diff --git a/.hgtags b/.hgtags index f2f9fa39a3c..b71e2cc2927 100644 --- a/.hgtags +++ b/.hgtags @@ -23,3 +23,9 @@ caf58ffa084568990cbb3441f9ae188e36b31770 jdk7-b42 04b2620edc72de93671646e4720c5992c74ac8b5 jdk7-b46 0c4657194eec95c08ba478aee9cfc3c295e41657 jdk7-b47 1bf51a4c2627c2f0e0cbcc2cf0421bdb37f1f2b2 jdk7-b48 +6b84b04a80afe23262377c60913eebfc898f14c4 jdk7-b49 +5da0e6b9f4f18ef483c977337214b12ee0e1fc8f jdk7-b50 +a25c5ec5e40e07733d1ff9898a0abe36159288ff jdk7-b51 +7a90e89e36d103038f8667f6a7daae34ecfa1ad8 jdk7-b52 +d52186ee770dac57950536cd00ccbfdef360b04c jdk7-b53 +15096652c4d48dfb9fc0b2cb135304db94c65ba0 jdk7-b54 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 7e83ea737e8..8525fbdcebc 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -23,3 +23,9 @@ a395e3aac4744cc9033fcd819fad1239a45add52 jdk7-b44 e8a2a4d187773a62f3309b0fa265c13425bc2258 jdk7-b46 d7744e86dedc21a8ecf6bdb73eb191b8eaf5b0da jdk7-b47 4ae9f4bfdb98f65bd957e3fe72471b320150b38e jdk7-b48 +aee93a8992d2389121eb610c00a86196f3e2b9b0 jdk7-b49 +5111e13e44e542fe945b47ab154546daec36737d jdk7-b50 +0f0189d55ce4a1f7840da7582ac7d970b3b7ab15 jdk7-b51 +4264c2fe66493e57c411045a1b61377796641e45 jdk7-b52 +c235f4a8559d196879c56af80159f67ee5d0e720 jdk7-b53 +2ef382b1bbd58a68e668391c6145a4b2066c5b96 jdk7-b54 diff --git a/Makefile b/Makefile index 54e5a256873..a0b2dc384f9 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/.hgtags b/corba/.hgtags index c1c59cf6a3c..628b5e09783 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -23,3 +23,9 @@ ccd6a16502e0650d91d85c4b86be05cbcd461a87 jdk7-b42 1691dbfc08f8ee3f4e23a1ff30cdff920718696c jdk7-b46 167ad0164301f318b069a947e1c9c07ed667748a jdk7-b47 0be222241fd405e48915647facfaa176621b39b9 jdk7-b48 +d70978bc64bc7a04be7797ab0dcd9b7b1b3a6bff jdk7-b49 +0edbd0074b02b42b2b83cc47cb391d4869b7a8ec jdk7-b50 +3eb8f1047a7402a9a79937d1c39560e931e91da2 jdk7-b51 +bec82237d694f9802b820fa11bbb4f7fa9bf8e77 jdk7-b52 +3c4d73194f6f89f040ae3b2d257335dfa8a1b2b5 jdk7-b53 +8130ac858d6789d5853d23044ba4a992afda574a jdk7-b54 diff --git a/corba/make/Makefile b/corba/make/Makefile index 0b5c31d7001..5eebabb2cd5 100644 --- a/corba/make/Makefile +++ b/corba/make/Makefile @@ -112,8 +112,6 @@ ifndef TARGET_JAVA TARGET_JAVA = java endif -NO_PROPRIETARY_API_WARNINGS = -XDignore.symbol.file=true - SELF = $(lastword $(MAKEFILE_LIST)) # for jdk, we generate the following: diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_dynamicany.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_dynamicany.jmk index a3a4ffb5fdd..2907634301b 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_dynamicany.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_dynamicany.jmk @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_encoding.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_encoding.jmk index 84f725c3353..3ecad394981 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_encoding.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_encoding.jmk @@ -1,5 +1,5 @@ # -# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_ior.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_ior.jmk index c4cddea8de3..6616877f547 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_ior.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_ior.jmk @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk index 871b48df55d..476fec4be41 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_protocol.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_protocol.jmk index 0a6b350ae85..ae588f38bab 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_protocol.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_protocol.jmk @@ -1,5 +1,5 @@ # -# Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_legacy_interceptor.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_legacy_interceptor.jmk index 156eb299ee2..f8cec1b92aa 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_legacy_interceptor.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_legacy_interceptor.jmk @@ -1,5 +1,5 @@ # -# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_monitoring.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_monitoring.jmk index 6a423c0bb9b..67610d6e5d4 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_monitoring.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_monitoring.jmk @@ -1,5 +1,5 @@ # -# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_presentation_rmi.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_presentation_rmi.jmk index d6e5e7f94dd..7f78d64ee24 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_presentation_rmi.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_presentation_rmi.jmk @@ -1,5 +1,5 @@ # -# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_transport.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_transport.jmk index 68f68bae04c..e3e75e7fd05 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_transport.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_spi_transport.jmk @@ -1,5 +1,5 @@ # -# Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/org_omg_CosNaming.jmk b/corba/make/com/sun/corba/minclude/org_omg_CosNaming.jmk index 0cff6b03d7d..960eeea740c 100644 --- a/corba/make/com/sun/corba/minclude/org_omg_CosNaming.jmk +++ b/corba/make/com/sun/corba/minclude/org_omg_CosNaming.jmk @@ -1,5 +1,5 @@ # -# Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/org_omg_DynamicAny.jmk b/corba/make/com/sun/corba/minclude/org_omg_DynamicAny.jmk index d9e7c1f8ea8..2ce167ee7ee 100644 --- a/corba/make/com/sun/corba/minclude/org_omg_DynamicAny.jmk +++ b/corba/make/com/sun/corba/minclude/org_omg_DynamicAny.jmk @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/minclude/org_omg_PortableInterceptor.jmk b/corba/make/com/sun/corba/minclude/org_omg_PortableInterceptor.jmk index 5f0a661971c..1c050e894f8 100644 --- a/corba/make/com/sun/corba/minclude/org_omg_PortableInterceptor.jmk +++ b/corba/make/com/sun/corba/minclude/org_omg_PortableInterceptor.jmk @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/com/sun/corba/se/sources/Makefile b/corba/make/com/sun/corba/se/sources/Makefile index 624661e5afa..9d945a29343 100644 --- a/corba/make/com/sun/corba/se/sources/Makefile +++ b/corba/make/com/sun/corba/se/sources/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -46,8 +46,6 @@ CORBA_JMK_DIRECTORY=$(TOPDIR)/make/com/sun/corba/minclude/ include $(CORBA_JMK_DIRECTORY)com_sun_corba_se_PortableActivationIDL.jmk include $(CORBA_JMK_DIRECTORY)com_sun_corba_se_impl_logging.jmk -FILES_java += com/sun/corba/se/org/omg/CORBA/ORB.java - # # Dirs # @@ -80,11 +78,11 @@ ORBUTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/ORBUtil.mc POA.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/POA.mc UTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/Util.mc -MC_GENERATE_CLASS = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-class -MC_GENERATE_LOG_RB = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-resource +MC_GENERATE_CLASS = make-class +MC_GENERATE_LOG_RB = make-resource -JSCHEME_GENERATE_CLASS = $(BOOT_JAVA_CMD) jscheme.REPL $(MC_GENERATE_CLASS) -JSCHEME_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) jscheme.REPL $(MC_GENERATE_LOG_RB) +JSCHEME_GENERATE_CLASS = $(BOOT_JAVA_CMD) com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_CLASS) +JSCHEME_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_LOG_RB) # diff --git a/corba/make/common/Defs-windows.gmk b/corba/make/common/Defs-windows.gmk index b387e8b51d2..f85c9c14229 100644 --- a/corba/make/common/Defs-windows.gmk +++ b/corba/make/common/Defs-windows.gmk @@ -1,5 +1,5 @@ # -# Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/common/Rules.gmk b/corba/make/common/Rules.gmk index c9605aafba5..aa674a9bd95 100644 --- a/corba/make/common/Rules.gmk +++ b/corba/make/common/Rules.gmk @@ -191,14 +191,18 @@ $(JAVA_SOURCE_LIST) : source_list_prime resources $(FILES_class) # Make sure all newer sources are compiled (in a batch) classes : $(CLASSES_INIT) .delete.classlist .compile.classlist +# Use this javac option to force it to favor the sourcepath file classes +# rather than any bootclasspath classes. +JAVAC_PREFER_SOURCE = -Xprefer:source + .compile.classlist : $(JAVA_SOURCE_LIST) @$(MKDIR) -p $(CLASSDESTDIR) @if [ `$(CAT) $(JAVA_SOURCE_LIST) | $(WC) -l` -ge 1 ] ; then \ $(ECHO) "# Java sources to be compiled: (listed in file $(JAVA_SOURCE_LIST))"; \ $(CAT) $(JAVA_SOURCE_LIST); \ $(ECHO) "# Running javac:"; \ - $(ECHO) $(JAVAC_CMD) -sourcepath "$(SOURCEPATH)" -d $(CLASSDESTDIR) @$(JAVA_SOURCE_LIST); \ - $(JAVAC_CMD) -sourcepath "$(SOURCEPATH)" -d $(CLASSDESTDIR) @$(JAVA_SOURCE_LIST); \ + $(ECHO) $(JAVAC_CMD) $(JAVAC_PREFER_SOURCE) -sourcepath "$(SOURCEPATH)" -d $(CLASSDESTDIR) @$(JAVA_SOURCE_LIST); \ + $(JAVAC_CMD) $(JAVAC_PREFER_SOURCE) -sourcepath "$(SOURCEPATH)" -d $(CLASSDESTDIR) @$(JAVA_SOURCE_LIST); \ fi @$(java-vm-cleanup) diff --git a/corba/make/common/shared/Compiler-msvc.gmk b/corba/make/common/shared/Compiler-msvc.gmk index e7ae0e35dcc..048ca78eb51 100644 --- a/corba/make/common/shared/Compiler-msvc.gmk +++ b/corba/make/common/shared/Compiler-msvc.gmk @@ -1,5 +1,5 @@ # -# Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -128,9 +128,19 @@ ifeq ($(PLATFORM), windows) endif endif endif - # This will cause problems if ALT_COMPILER_PATH is defined to "" - # which is a directive to use the PATH. - REBASE = $(COMPILER_PATH)../REBASE + ifeq ($(CC_MAJORVER), 15) + # This should be: CC_VER=15.00.21022.8 LINK_VER=9.00.21022.8 + REQUIRED_CC_VER = 15.00.21022.8 + REQUIRED_LINK_VER = 9.00.21022.8 + COMPILER_NAME=Windows SDK 6.1 Visual Studio 9 + COMPILER_VERSION=VS2008 + RC = $(MSSDK61)/bin/x64/rc + REBASE = $(MSSDK61/bin/x64/rebase + else + # This will cause problems if ALT_COMPILER_PATH is defined to "" + # which is a directive to use the PATH. + REBASE = $(COMPILER_PATH)../REBASE + endif ifndef COMPILER_PATH COMPILER_PATH := $(error COMPILER_PATH cannot be empty here) endif diff --git a/corba/make/common/shared/Compiler-sun.gmk b/corba/make/common/shared/Compiler-sun.gmk index 1dda0891d03..0baa24abec8 100644 --- a/corba/make/common/shared/Compiler-sun.gmk +++ b/corba/make/common/shared/Compiler-sun.gmk @@ -1,5 +1,5 @@ # -# Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/common/shared/Defs-java.gmk b/corba/make/common/shared/Defs-java.gmk index f811bee0859..f80f0ffa4e1 100644 --- a/corba/make/common/shared/Defs-java.gmk +++ b/corba/make/common/shared/Defs-java.gmk @@ -104,6 +104,9 @@ ifeq ($(COMPILER_WARNINGS_FATAL), true) JAVACFLAGS += -Werror endif +NO_PROPRIETARY_API_WARNINGS = -XDignore.symbol.file=true +JAVACFLAGS += $(NO_PROPRIETARY_API_WARNINGS) + # Add the source level (currently all source is 1.5, should this be 1.6?) LANGUAGE_VERSION = -source 1.5 JAVACFLAGS += $(LANGUAGE_VERSION) @@ -117,7 +120,7 @@ JAVACFLAGS += -classpath $(BOOTDIR)/lib/tools.jar JAVACFLAGS += $(OTHER_JAVACFLAGS) # Needed for javah -JAVAHFLAGS += -bootclasspath $(CLASSBINDIR) +JAVAHFLAGS += -classpath $(CLASSBINDIR) # Langtools ifdef LANGTOOLS_DIST diff --git a/corba/make/common/shared/Defs-utils.gmk b/corba/make/common/shared/Defs-utils.gmk index b008c5ed0f4..51bdb660372 100644 --- a/corba/make/common/shared/Defs-utils.gmk +++ b/corba/make/common/shared/Defs-utils.gmk @@ -1,5 +1,5 @@ # -# Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/common/shared/Defs-windows.gmk b/corba/make/common/shared/Defs-windows.gmk index ed8abc2eb9d..d78f7f7293e 100644 --- a/corba/make/common/shared/Defs-windows.gmk +++ b/corba/make/common/shared/Defs-windows.gmk @@ -282,13 +282,27 @@ endif # Compilers for 64bit are from SDK ifeq ($(ARCH_DATA_MODEL), 64) - ifneq ($(_ms_sdk),) + xMSSDK61 :="C:/Program Files/Microsoft SDKs/Windows/v6.1/" + MSSDK61 :=$(call FullPath,$(xMSSDK61)) + xVS2008 :="C:/Program Files (x86)/Microsoft Visual Studio 9.0/" + _vs2008 :=$(call FullPath,$(xVS2008)) + ifneq ($(_vs2008),) ifeq ($(ARCH), ia64) - _compiler_bin :=$(_ms_sdk)/Bin/Win64 + _compiler_bin :=$(_vs2008)/VC/Bin/x86_ia64 endif ifeq ($(ARCH), amd64) - _compiler_bin :=$(_ms_sdk)/Bin/Win64/x86/$(ARCH) - _redist_sdk :=$(_ms_sdk)/redist/win64/AMD64 + _compiler_bin :=$(_vs2008)/VC/Bin/$(ARCH) + _redist_sdk :=$(MSSDK61)/VC/redist + endif + else + ifneq ($(_ms_sdk),) + ifeq ($(ARCH), ia64) + _compiler_bin :=$(_ms_sdk)/Bin/Win64 + endif + ifeq ($(ARCH), amd64) + _compiler_bin :=$(_ms_sdk)/Bin/Win64/x86/$(ARCH) + _redist_sdk :=$(_ms_sdk)/redist/win64/AMD64 + endif endif endif endif diff --git a/corba/make/common/shared/Defs.gmk b/corba/make/common/shared/Defs.gmk index 5af64523ff7..e5afa8eb8e3 100644 --- a/corba/make/common/shared/Defs.gmk +++ b/corba/make/common/shared/Defs.gmk @@ -1,5 +1,5 @@ # -# Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/javax/xa/Makefile b/corba/make/javax/xa/Makefile index 6efdbe1e4f8..693bbdfdd3e 100644 --- a/corba/make/javax/xa/Makefile +++ b/corba/make/javax/xa/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/jprt.config b/corba/make/jprt.config index 2bff1a54c49..37d0086f525 100644 --- a/corba/make/jprt.config +++ b/corba/make/jprt.config @@ -1,7 +1,7 @@ #!echo "This is not a shell script" ############################################################################# # -# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/org/omg/CORBA/Makefile b/corba/make/org/omg/CORBA/Makefile index 110660256e4..c6295ccaf37 100644 --- a/corba/make/org/omg/CORBA/Makefile +++ b/corba/make/org/omg/CORBA/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/corba/make/sun/rmi/corbalogsources/Makefile b/corba/make/sun/rmi/corbalogsources/Makefile index a7b995c1c51..0859c5ab2a9 100644 --- a/corba/make/sun/rmi/corbalogsources/Makefile +++ b/corba/make/sun/rmi/corbalogsources/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -75,15 +75,14 @@ ORBUTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/ORBUtil.mc POA.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/POA.mc UTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/Util.mc -MC_GENERATE_CLASS = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-class -MC_GENERATE_LOG_RB = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-resource +MC_GENERATE_CLASS = make-class +MC_GENERATE_LOG_RB = make-resource -JSCHEME_LIB_DIRECTORY=$(SRC_DIR)/com/sun/tools/corba/se/logutil/lib -JSCHEME_CLASSPATH=$(JSCHEME_LIB_DIRECTORY)/jscheme.jar$(CLASSPATH_SEPARATOR)$(JSCHEME_LIB_DIRECTORY)/jschemelogutil.jar -JSCHEME_GENERATE_CLASS = $(BOOT_JAVA_CMD) \ - -cp "$(JSCHEME_CLASSPATH)" jscheme.REPL $(MC_GENERATE_CLASS) -JSCHEME_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) \ - -cp "$(JSCHEME_CLASSPATH)" jscheme.REPL $(MC_GENERATE_LOG_RB) +MC_CLASSPATH=$(BUILDTOOLJARDIR)/MC.jar +MCJ_GENERATE_CLASS = $(BOOT_JAVA_CMD) \ + -cp "$(MC_CLASSPATH)" com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_CLASS) +MCJ_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) \ + -cp "$(MC_CLASSPATH)" com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_LOG_RB) # @@ -104,28 +103,28 @@ $(LOG_GENDIRECTORY): $(MKDIR) -p $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/ActivationSystemException.java : $(ACTIVATION.MC) - $(JSCHEME_GENERATE_CLASS) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/IORSystemException.java : $(IOR.MC) - $(JSCHEME_GENERATE_CLASS) $(IOR.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(IOR.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/InterceptorsSystemException.java : $(INTERCEPTORS.MC) - $(JSCHEME_GENERATE_CLASS) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/NamingSystemException.java : $(NAMING.MC) - $(JSCHEME_GENERATE_CLASS) $(NAMING.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(NAMING.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/OMGSystemException.java : $(OMG.MC) - $(JSCHEME_GENERATE_CLASS) $(OMG.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(OMG.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/ORBUtilSystemException.java : $(ORBUTIL.MC) - $(JSCHEME_GENERATE_CLASS) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/POASystemException.java : $(POA.MC) - $(JSCHEME_GENERATE_CLASS) $(POA.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(POA.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/UtilSystemException.java : $(UTIL.MC) - $(JSCHEME_GENERATE_CLASS) $(UTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(UTIL.MC) $(LOG_GENDIRECTORY) logresource.generate: $(LOG_GENDIRECTORY)/LogStrings.properties @@ -142,28 +141,28 @@ $(LOG_GENDIRECTORY)/LogStrings.properties: \ $(CAT) $(LOG_GENDIRECTORY)/*.resource > $(LOG_GENDIRECTORY)/LogStrings.properties $(LOG_GENDIRECTORY)/ActivationSystemException.resource : $(ACTIVATION.MC) - $(JSCHEME_GENERATE_LOG_RB) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/IORSystemException.resource : $(IOR.MC) - $(JSCHEME_GENERATE_LOG_RB) $(IOR.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(IOR.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/InterceptorsSystemException.resource : $(INTERCEPTORS.MC) - $(JSCHEME_GENERATE_LOG_RB) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/NamingSystemException.resource : $(NAMING.MC) - $(JSCHEME_GENERATE_LOG_RB) $(NAMING.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(NAMING.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/OMGSystemException.resource : $(OMG.MC) - $(JSCHEME_GENERATE_LOG_RB) $(OMG.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(OMG.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/ORBUtilSystemException.resource : $(ORBUTIL.MC) - $(JSCHEME_GENERATE_LOG_RB) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/POASystemException.resource : $(POA.MC) - $(JSCHEME_GENERATE_LOG_RB) $(POA.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(POA.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/UtilSystemException.resource : $(UTIL.MC) - $(JSCHEME_GENERATE_LOG_RB) $(UTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(UTIL.MC) $(LOG_GENDIRECTORY) # diff --git a/corba/make/tools/Makefile b/corba/make/tools/Makefile index 489c7b2f269..f0d95363b84 100644 --- a/corba/make/tools/Makefile +++ b/corba/make/tools/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ include $(BUILDDIR)/common/Defs.gmk SUBDIRS = \ strip_properties \ idlj \ + logutil \ all build clean clobber:: $(SUBDIRS-loop) diff --git a/jdk/make/common/shared/Compiler.gmk b/corba/make/tools/logutil/Makefile similarity index 67% rename from jdk/make/common/shared/Compiler.gmk rename to corba/make/tools/logutil/Makefile index e5847a2e28c..2e19867f8d4 100644 --- a/jdk/make/common/shared/Compiler.gmk +++ b/corba/make/tools/logutil/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,24 +24,20 @@ # # -# Compiler settings for all platforms and the default compiler for each. +# Makefile for building the idlj tool # -# Windows uses Microsoft compilers by default -ifeq ($(PLATFORM), windows) - override CC_VERSION = msvc -endif +BUILDDIR = ../.. +PACKAGE = com.sun.tools.corba.se.logutil +PRODUCT = tools +PROGRAM = MC +include $(BUILDDIR)/common/Defs.gmk -# Solaris uses Sun Studio compilers by default -ifeq ($(PLATFORM), solaris) - override CC_VERSION = sun -endif +BUILDTOOL_SOURCE_ROOT = $(SHARE_SRC)/classes +BUILDTOOL_MAIN = $(PKGDIR)/MC.java -# Linux uses GNU compilers by default -ifeq ($(PLATFORM), linux) - override CC_VERSION = gcc -endif - -# Get the compiler specific settings -include $(JDK_MAKE_SHARED_DIR)/Compiler-$(CC_VERSION).gmk +# +# Build tool jar rules. +# +include $(BUILDDIR)/common/BuildToolJar.gmk diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java index d8b31fc0f77..e618a7401fa 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.io.Writer ; import java.io.OutputStream ; import java.io.BufferedWriter ; import java.io.OutputStreamWriter ; -import jsint.Pair ; import java.util.StringTokenizer ; public class IndentingPrintWriter extends PrintWriter { @@ -38,22 +37,20 @@ public class IndentingPrintWriter extends PrintWriter { private int indentWidth = 4 ; private String indentString = "" ; - public void printMsg( String msg, Pair data ) + public void printMsg( String msg, Object... data ) { // System.out.println( "printMsg called with msg=" + msg + " data=" + data ) ; StringTokenizer st = new StringTokenizer( msg, "@", true ) ; StringBuffer result = new StringBuffer() ; - Object head = data.first ; - Pair tail = (Pair)data.rest ; String token = null ; + int pos = 0; while (st.hasMoreTokens()) { token = st.nextToken() ; if (token.equals("@")) { - if (head != null) { - result.append( head ) ; - head = tail.first ; - tail = (Pair)tail.rest ; + if (pos < data.length) { + result.append( data[pos] ); + ++pos; } else { throw new Error( "List too short for message" ) ; } diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java new file mode 100644 index 00000000000..5431f0c7a17 --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java @@ -0,0 +1,211 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.corba.se.logutil; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStreamReader; +import java.io.IOException; + +import java.util.LinkedList; +import java.util.Queue; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Input { + + /** + * The name of the package this class will inhabit. + */ + private String packageName; + + /** + * The name of the generated class. + */ + private String className; + + /** + * The name of the group of exceptions handled by the class. + */ + private String groupName; + + /** + * The group of exceptions. + */ + private Queue exceptions; + + /** + * Represents the current state of parsing the input. + */ + private enum State + { + OUTER, + IN_CLASS, + IN_EXCEPTION_LIST + }; + + /** + * Regular expression to match each code line. + */ + private static final Pattern EXCEPTION_INFO_REGEX = + Pattern.compile("(\\w+)\\s*(\\d+)\\s*(\\w+)"); + + /** + * Parses the specified file to create a new {@link Input} + * object. + * + * @param filename the file to parse. + * @throws FileNotFoundException if the file can't be found. + * @throws IOException if an I/O error occurs. + */ + public Input(final String filename) + throws FileNotFoundException, IOException { + BufferedReader r = + new BufferedReader(new InputStreamReader(new FileInputStream(filename))); + State state = State.OUTER; + InputException current = null; + exceptions = new LinkedList(); + String line; + while ((line = r.readLine()) != null) { + // Skip ; comments + if (line.startsWith(";")) + continue; + + int index = line.indexOf("("); + if (index == -1) + continue; + + switch (state) { + case OUTER: + state = State.IN_CLASS; + String[] classInfo = line.substring(index).split(" "); + packageName = classInfo[0].substring(2, classInfo[0].length() - 1); + className = classInfo[1].substring(1, classInfo[1].length() - 1); + groupName = classInfo[2]; + break; + case IN_CLASS: + state = State.IN_EXCEPTION_LIST; + break; + case IN_EXCEPTION_LIST: + boolean inQuote = false; + boolean inCode = false; + boolean end = false; + int start = index + 1; + Queue lines = new LinkedList(); + for (int a = start; a < line.length(); ++a) { + if (line.charAt(a) == '(' && !inCode && !inQuote) { + if (current == null) + current = + new InputException(line.substring(start, a).trim()); + start = a + 1; + inCode = true; + } + if (line.charAt(a) == '"') + inQuote = !inQuote; + if (line.charAt(a) == ')' && !inQuote) { + if (inCode) { + lines.offer(line.substring(start, a)); + inCode = false; + } else + end = true; + } + if (!end && a == line.length() - 1) + line += r.readLine(); + } + for (String l : lines) { + int stringStart = l.indexOf("\"") + 1; + int stringEnd = l.indexOf("\"", stringStart); + Matcher matcher = EXCEPTION_INFO_REGEX.matcher(l.substring(0, stringStart)); + if (matcher.find()) + current.add(new InputCode(matcher.group(1), + Integer.parseInt(matcher.group(2)), + matcher.group(3), + l.substring(stringStart, stringEnd))); + } + exceptions.offer(current); + current = null; + break; + } + } + } + + /** + * Returns the name of this group of exceptions. + * + * @return the name of this group of exceptions. + */ + public String getGroupName() + { + return groupName; + } + + /** + * Returns the name of the package this class will go in. + * + * @return the name of the package. + */ + public String getPackageName() + { + return packageName; + } + + /** + * Returns the name of the generated class. + * + * @return the name of the class. + */ + public String getClassName() + { + return className; + } + + /** + * Returns the exceptions contained in this class. + * + * @return the exceptions. + */ + public Queue getExceptions() { + return exceptions; + } + + /** + * Returns a textual representation of this input. + * + * @return a textual representation. + */ + public String toString() { + return getClass().getName() + + "[packageName=" + packageName + + ",className=" + className + + ",groupName=" + groupName + + ",exceptions=" + exceptions + + "]"; + } + +} diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java new file mode 100644 index 00000000000..810a449f486 --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java @@ -0,0 +1,116 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.tools.corba.se.logutil; + +public class InputCode { + + /** + * The name of this code. + */ + private final String name; + + /** + * The code. + */ + private final int code; + + /** + * The log level for this code. + */ + private final String logLevel; + + /** + * The error message for this code. + */ + private final String message; + + /** + * Creates a new error code with the specified name, code, + * log level and error message. + * + * @param name the name of the new code. + * @param code the code itself. + * @param logLevel the level of severity of this error. + * @param message the error message for this code. + */ + public InputCode(final String name, final int code, + final String logLevel, final String message) { + this.name = name; + this.code = code; + this.logLevel = logLevel; + this.message = message; + } + + /** + * Returns the name of this code. + * + * @return the name of the code. + */ + public String getName() { + return name; + } + + /** + * Returns the code. + * + * @return the code. + */ + public int getCode() { + return code; + } + + /** + * Returns the severity of this code. + * + * @return the log level severity of the code. + */ + public String getLogLevel() { + return logLevel; + } + + /** + * Returns the error message for this code. + * + * @return the error message for this code. + */ + public String getMessage() { + return message; + } + + /** + * Returns a textual representation of this code. + * + * @return a textual representation. + */ + public String toString() { + return getClass().getName() + + "[name=" + name + + ",code=" + code + + ",logLevel=" + logLevel + + ",message=" + message + + "]"; + } + +} diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java new file mode 100644 index 00000000000..5c1f4984e57 --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java @@ -0,0 +1,94 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.tools.corba.se.logutil; + +import java.util.LinkedList; +import java.util.Queue; + +public class InputException { + + /** + * The name of this exception. + */ + private final String name; + + /** + * The codes associated with this exception. + */ + private final Queue codes; + + /** + * Constructs a new {@link InputException} with the + * specified name. + * + * @param name the name of the new exception; + */ + public InputException(final String name) { + this.name = name; + codes = new LinkedList(); + } + + /** + * Adds a new code to this exception. + * + * @param c the code to add. + */ + public void add(InputCode c) + { + codes.offer(c); + } + + /** + * Returns the name of this exception. + * + * @return the exception's name. + */ + public String getName() { + return name; + } + + /** + * Returns the codes associated with this exception. + * + * @return the exception's codes. + */ + public Queue getCodes() { + return codes; + } + + /** + * Returns a textual representation of this exception. + * + * @return a textual representation. + */ + public String toString() { + return getClass().getName() + + "[name=" + name + + ",codes=" + codes + + "]"; + } + +} + diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java new file mode 100644 index 00000000000..9246f70c3ab --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java @@ -0,0 +1,559 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.tools.corba.se.logutil; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import java.util.Arrays; +import java.util.Date; +import java.util.Formatter; +import java.util.List; +import java.util.Queue; + +public class MC { + + private static final String VERSION = "1.0"; + + private static final List SUN_EXCEPTION_GROUPS = Arrays.asList(new String[] + { "SUNBASE", "ORBUTIL", "ACTIVATION", "NAMING", "INTERCEPTORS", "POA", "IOR", "UTIL" }); + + private static final List EXCEPTIONS = Arrays.asList(new String[] + { "UNKNOWN", "BAD_PARAM", "NO_MEMORY", "IMP_LIMIT", "COMM_FAILURE", "INV_OBJREF", "NO_PERMISSION", + "INTERNAL", "MARSHAL", "INITIALIZE", "NO_IMPLEMENT", "BAD_TYPECODE", "BAD_OPERATION", "NO_RESOURCES", + "NO_RESPONSE", "PERSIST_STORE", "BAD_INV_ORDER", "TRANSIENT", "FREE_MEM", "INV_IDENT", "INV_FLAG", + "INTF_REPOS", "BAD_CONTEXT", "OBJ_ADAPTER", "DATA_CONVERSION", "OBJECT_NOT_EXIST", "TRANSACTION_REQUIRED", + "TRANSACTION_ROLLEDBACK", "INVALID_TRANSACTION", "INV_POLICY", "CODESET_INCOMPATIBLE", "REBIND", + "TIMEOUT", "TRANSACTION_UNAVAILABLE", "BAD_QOS", "INVALID_ACTIVITY", "ACTIVITY_COMPLETED", + "ACTIVITY_REQUIRED" }); + + /** + * Read the minor codes from the input file and + * write out a resource file. + * + * @param inFile the file to read the codes from. + * @param outDir the directory to write the resource file to. + * @throws FileNotFoundException if the input file can not be found. + * @throws IOException if an I/O error occurs. + */ + private void makeResource(String inFile, String outDir) + throws FileNotFoundException, IOException { + writeResource(outDir, new Input(inFile)); + } + + /** + * Create a new Java source file using the specified Scheme input file, + * and writing the result to the given output directory. + * + * @param inFile the file to read the data from. + * @param outDir the directory to write the Java class to. + * @throws FileNotFoundException if the input file can not be found. + * @throws IOException if an I/O error occurs. + */ + private void makeClass(String inFile, String outDir) + throws FileNotFoundException, IOException { + writeClass(inFile, outDir, new Input(inFile)); + } + + /** + * Writes out a Java source file using the data from the given + * {@link Input} object. The result is written to {@code outDir}. + * The name of the input file is just used in the header of the + * resulting source file. + * + * @param inFile the name of the file the data was read from. + * @param outDir the directory to write the Java class to. + * @param input the parsed input data. + * @throws FileNotFoundException if the output file can't be written. + */ + private void writeClass(String inFile, String outDir, Input input) + throws FileNotFoundException { + String packageName = input.getPackageName(); + String className = input.getClassName(); + String groupName = input.getGroupName(); + Queue exceptions = input.getExceptions(); + FileOutputStream file = new FileOutputStream(outDir + File.separator + className + ".java"); + IndentingPrintWriter pw = new IndentingPrintWriter(file); + + writeClassHeader(inFile, groupName, pw); + pw.printMsg("package @ ;", packageName); + pw.println(); + pw.println("import java.util.logging.Logger ;"); + pw.println("import java.util.logging.Level ;"); + pw.println(); + pw.println("import org.omg.CORBA.OMGVMCID ;"); + pw.println( "import com.sun.corba.se.impl.util.SUNVMCID ;"); + pw.println( "import org.omg.CORBA.CompletionStatus ;"); + pw.println( "import org.omg.CORBA.SystemException ;"); + pw.println(); + pw.println( "import com.sun.corba.se.spi.orb.ORB ;"); + pw.println(); + pw.println( "import com.sun.corba.se.spi.logging.LogWrapperFactory;"); + pw.println(); + pw.println( "import com.sun.corba.se.spi.logging.LogWrapperBase;"); + pw.println(); + writeImports(exceptions, pw); + pw.println(); + pw.indent(); + pw.printMsg("public class @ extends LogWrapperBase {", className); + pw.println(); + pw.printMsg("public @( Logger logger )", className); + pw.indent(); + pw.println( "{"); + pw.undent(); + pw.println( "super( logger ) ;"); + pw.println( "}"); + pw.println(); + pw.flush(); + writeFactoryMethod(className, groupName, pw); + writeExceptions(groupName, exceptions, className, pw); + pw.undent(); + pw.println( ); + pw.println( "}"); + pw.flush(); + pw.close(); + } + + /** + * Writes out the header of a Java source file. + * + * @param inFile the input file the file was generated from. + * @param groupName the group of exceptions the Java source file is for. + * @param pw the print writer used to write the output. + */ + private void writeClassHeader(String inFile, String groupName, + IndentingPrintWriter pw) { + if (groupName.equals("OMG")) + pw.println("// Log wrapper class for standard exceptions"); + else + pw.printMsg("// Log wrapper class for Sun private system exceptions in group @", + groupName); + pw.println("//"); + pw.printMsg("// Generated by MC.java version @, DO NOT EDIT BY HAND!", VERSION); + pw.printMsg("// Generated from input file @ on @", inFile, new Date()); + pw.println(); + } + + /** + * Write out the import list for the exceptions. + * + * @param groups the exceptions that were parsed. + * @param pw the {@link IndentingPrintWriter} for writing to the file. + */ + private void writeImports(Queue exceptions, + IndentingPrintWriter pw) { + if (exceptions == null) + return; + for (InputException e : exceptions) + pw.println("import org.omg.CORBA." + e.getName() + " ;"); + } + + /** + * Write out the factory method for this group of exceptions. + * + * @param className the name of the generated class. + * @param groupName the name of this group of exceptions. + * @param pw the {@link IndentingPrintWriter} for writing to the file. + */ + private void writeFactoryMethod(String className, String groupName, + IndentingPrintWriter pw) { + pw.indent(); + pw.println( "private static LogWrapperFactory factory = new LogWrapperFactory() {"); + pw.println( "public LogWrapperBase create( Logger logger )" ); + pw.indent(); + pw.println( "{"); + pw.undent(); + pw.printMsg("return new @( logger ) ;", className); + pw.undent(); + pw.println( "}" ); + pw.println( "} ;" ); + pw.println(); + pw.printMsg("public static @ get( ORB orb, String logDomain )", className); + pw.indent(); + pw.println( "{"); + pw.indent(); + pw.printMsg( "@ wrapper = ", className); + pw.indent(); + pw.printMsg( "(@) orb.getLogWrapper( logDomain, ", className); + pw.undent(); + pw.undent(); + pw.printMsg( "\"@\", factory ) ;", groupName); + pw.undent(); + pw.println( "return wrapper ;" ); + pw.println( "} " ); + pw.println(); + pw.printMsg( "public static @ get( String logDomain )", className); + pw.indent(); + pw.println( "{"); + pw.indent(); + pw.printMsg( "@ wrapper = ", className); + pw.indent(); + pw.printMsg( "(@) ORB.staticGetLogWrapper( logDomain, ", className); + pw.undent(); + pw.undent(); + pw.printMsg( "\"@\", factory ) ;", groupName); + pw.undent(); + pw.println( "return wrapper ;" ); + pw.println( "} " ); + pw.println(); + } + + /** + * Writes out the exceptions themselves. + * + * @param groupName the name of this group of exceptions. + * @param exceptions the exceptions to write out. + * @param className the name of the generated class. + * @param pw the {@link IndentingPrintWriter} for writing to the file. + */ + private void writeExceptions(String groupName, Queue exceptions, + String className, IndentingPrintWriter pw) { + for (InputException e : exceptions) { + pw.println("///////////////////////////////////////////////////////////"); + pw.printMsg("// @", e.getName()); + pw.println("///////////////////////////////////////////////////////////"); + pw.println(); + for (InputCode c : e.getCodes()) + writeMethods(groupName, e.getName(), c.getName(), c.getCode(), + c.getLogLevel(), className, StringUtil.countArgs(c.getMessage()), pw); + pw.flush(); + } + } + + /** + * Writes out the methods for a particular error. + * + * @param groupName the name of this group of exceptions. + * @param exceptionName the name of this particular exception. + * @param errorName the name of this particular error. + * @param code the minor code for this particular error. + * @param ident the name of the error in mixed-case identifier form. + * @param level the level at which to place log messages. + * @param className the name of the class for this group of exceptions. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethods(String groupName, String exceptionName, String errorName, + int code, String level, String className, int numParams, + IndentingPrintWriter pw) { + String ident = StringUtil.toMixedCase(errorName); + pw.printMsg("public static final int @ = @ ;", errorName, getBase(groupName, code)); + pw.println(); + pw.flush(); + writeMethodStatusCause(groupName, exceptionName, errorName, ident, level, + numParams, className, pw); + pw.println(); + pw.flush(); + writeMethodStatus(exceptionName, ident, numParams, pw); + pw.println(); + pw.flush(); + writeMethodCause(exceptionName, ident, numParams, pw); + pw.println(); + pw.flush(); + writeMethodNoArgs(exceptionName, ident, numParams, pw); + pw.println(); + pw.flush(); + } + + /** + * Writes out a method for an error that takes a + * {@link org.omg.CORBA.CompletionStatus} and a cause. + * + * @param groupName the name of this group of exceptions. + * @param exceptionName the name of this particular exception. + * @param errorName the name of this particular error. + * @param ident the name of the error in mixed-case identifier form. + * @param logLevel the level at which to place log messages. + * @param numParams the number of parameters the detail message takes. + * @param className the name of the class for this group of exceptions. + * @param pw the print writer for writing to the file. + */ + private void writeMethodStatusCause(String groupName, String exceptionName, + String errorName, String ident, + String logLevel, int numParams, + String className, IndentingPrintWriter pw) { + pw.indent(); + pw.printMsg( "public @ @( CompletionStatus cs, Throwable t@) {", exceptionName, + ident, makeDeclArgs(true, numParams)); + pw.printMsg( "@ exc = new @( @, cs ) ;", exceptionName, exceptionName, errorName); + pw.indent(); + pw.println( "if (t != null)" ); + pw.undent(); + pw.println( "exc.initCause( t ) ;" ); + pw.println(); + pw.indent(); + pw.printMsg( "if (logger.isLoggable( Level.@ )) {", logLevel); + if (numParams > 0) { + pw.printMsg( "Object[] parameters = new Object[@] ;", numParams); + for (int a = 0; a < numParams; ++a) + pw.printMsg("parameters[@] = arg@ ;", a, a); + } else + pw.println( "Object[] parameters = null ;"); + pw.indent(); + pw.printMsg( "doLog( Level.@, \"@.@\",", logLevel, groupName, ident); + pw.undent(); + pw.undent(); + pw.printMsg( "parameters, @.class, exc ) ;", className); + pw.println( "}"); + pw.println(); + + pw.undent(); + pw.println( "return exc ;"); + pw.println( "}"); + } + + /** + * Writes out a method for an error that takes a + * {@link org.omg.CORBA.CompletionStatus}. + * + * @param exceptionName the name of this particular exception. + * @param ident the name of the error in mixed-case identifier form. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethodStatus(String exceptionName, String ident, + int numParams, IndentingPrintWriter pw) { + pw.indent(); + pw.printMsg("public @ @( CompletionStatus cs@) {", exceptionName, + ident, makeDeclArgs(true, numParams)); + pw.undent(); + pw.printMsg("return @( cs, null@ ) ;", ident, makeCallArgs(true, numParams)); + pw.println("}"); + } + + /** + * Writes out a method for an error that takes a cause. + * + * @param exceptionName the name of this particular exception. + * @param ident the name of the error in mixed-case identifier form. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethodCause(String exceptionName, String ident, + int numParams, IndentingPrintWriter pw) { + pw.indent(); + pw.printMsg("public @ @( Throwable t@) {", exceptionName, ident, + makeDeclArgs(true, numParams)); + pw.undent(); + pw.printMsg("return @( CompletionStatus.COMPLETED_NO, t@ ) ;", ident, + makeCallArgs(true, numParams)); + pw.println("}"); + } + + /** + * Writes out a method for an error that takes no arguments. + * + * @param exceptionName the name of this particular exception. + * @param ident the name of the error in mixed-case identifier form. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethodNoArgs(String exceptionName, String ident, + int numParams, IndentingPrintWriter pw) { + + pw.indent(); + pw.printMsg("public @ @( @) {", exceptionName, ident, + makeDeclArgs(false, numParams)); + pw.undent(); + pw.printMsg("return @( CompletionStatus.COMPLETED_NO, null@ ) ;", + ident, makeCallArgs(true, numParams)); + pw.println("}"); + } + + /** + * Returns a list of comma-separated arguments with type declarations. + * + * @param leadingComma true if the list should start with a comma. + * @param numArgs the number of arguments to generate. + * @return the generated string. + */ + private String makeDeclArgs(boolean leadingComma, int numArgs) { + return makeArgString("Object arg", leadingComma, numArgs); + } + + /** + * Returns a list of comma-separated arguments without type declarations. + * + * @param leadingComma true if the list should start with a comma. + * @param numArgs the number of arguments to generate. + * @return the generated string. + */ + private String makeCallArgs(boolean leadingComma, int numArgs) { + return makeArgString("arg", leadingComma, numArgs); + } + + /** + * Returns a list of comma-separated arguments. + * + * @param prefixString the string with which to prefix each argument. + * @param leadingComma true if the list should start with a comma. + * @param numArgs the number of arguments to generate. + * @return the generated string. + */ + private String makeArgString(String prefixString, boolean leadingComma, + int numArgs) { + if (numArgs == 0) + return " "; + if (numArgs == 1) { + if (leadingComma) + return ", " + prefixString + (numArgs - 1); + else + return " " + prefixString + (numArgs - 1); + } + return makeArgString(prefixString, leadingComma, numArgs - 1) + + ", " + prefixString + (numArgs - 1); + } + + /** + * Returns the {@link String} containing the calculation of the + * error code. + * + * @param groupName the group of exception to which the code belongs. + * @param code the minor code number representing the exception within the group. + * @return the unique error code. + */ + private String getBase(String groupName, int code) { + if (groupName.equals("OMG")) + return "OMGVMCID.value + " + code; + else + return "SUNVMCID.value + " + (code + getSunBaseNumber(groupName)); + } + + /** + * Returns the base number for Sun-specific exceptions. + * + * @return the base number. + */ + private int getSunBaseNumber(String groupName) { + return 200 * SUN_EXCEPTION_GROUPS.indexOf(groupName); + } + + /** + * Writes out a resource file using the data from the given + * {@link Input} object. The result is written to {@code outDir}. + * + * @param outDir the directory to write the Java class to. + * @param input the parsed input data. + * @throws FileNotFoundException if the output file can't be written. + */ + private void writeResource(String outDir, Input input) + throws FileNotFoundException { + FileOutputStream file = new FileOutputStream(outDir + File.separator + + input.getClassName() + ".resource"); + IndentingPrintWriter pw = new IndentingPrintWriter(file); + String groupName = input.getGroupName(); + for (InputException e : input.getExceptions()) { + String exName = e.getName(); + for (InputCode c : e.getCodes()) { + String ident = StringUtil.toMixedCase(c.getName()); + pw.printMsg("@.@=\"@: (@) @\"", groupName, ident, + getMessageID(groupName, exName, c.getCode()), exName, c.getMessage()); + } + pw.flush(); + } + pw.close(); + } + + /** + * Returns the message ID corresponding to the given group name, + * exception name and error code. + * + * @param groupName the name of the group of exceptions. + * @param exception the name of the particular exception. + * @param code an error code from the given exception. + * @return the message ID. + */ + private String getMessageID(String groupName, String exceptionName, int code) { + if (groupName.equals("OMG")) + return getStandardMessageID(exceptionName, code); + else + return getSunMessageID(groupName, exceptionName, code); + } + + /** + * Returns the standard (OMG) message ID corresponding to the given + * exception name and error code. + * + * @param exceptionName the name of the particular exception. + * @param code an error code from the given exception. + * @return the message ID. + */ + private String getStandardMessageID(String exceptionName, int code) { + return new Formatter().format("IOP%s0%04d", getExceptionID(exceptionName), + code).toString(); + } + + /** + * Returns the Sun message ID corresponding to the given group name, + * exception name and error code. + * + * @param groupName the name of the group of exceptions. + * @param exceptionName the name of the particular exception. + * @param code an error code from the given exception. + * @return the message ID. + */ + private String getSunMessageID(String groupName, String exceptionName, int code) { + return new Formatter().format("IOP%s1%04d", getExceptionID(exceptionName), + getSunBaseNumber(groupName) + code).toString(); + } + + /** + * Returns the exception ID corresponding to the given exception name. + * + * @param exceptionName the name of the particular exception. + * @return the message ID. + */ + private String getExceptionID(String exceptionName) { + return new Formatter().format("%03d", EXCEPTIONS.indexOf(exceptionName)).toString(); + } + + /** + * Entry point for running the generator from the command + * line. Users can specify either "make-class" or "make-resource" + * as the first argument to generate the specified type of file. + * + * @param args the command-line arguments. + * @throws FileNotFoundException if the input file can not be found. + * @throws IOException if an I/O error occurs. + */ + public static void main(String[] args) + throws FileNotFoundException, IOException + { + if (args.length < 3) + { + System.err.println("(make-class|make-resource) "); + System.exit(-1); + } + if (args[0].equals("make-class")) + new MC().makeClass(args[1], args[2]); + else if (args[0].equals("make-resource")) + new MC().makeResource(args[1], args[2]); + else + System.err.println("Invalid command: " + args[0]); + } + +} diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jscheme.jar b/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jscheme.jar deleted file mode 100644 index 5a2a0f1f44d..00000000000 Binary files a/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jscheme.jar and /dev/null differ diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jschemelogutil.jar b/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jschemelogutil.jar deleted file mode 100644 index 4510aedd1d7..00000000000 Binary files a/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jschemelogutil.jar and /dev/null differ diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc b/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc deleted file mode 100644 index 16df63d031f..00000000000 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -java -cp lib/jscheme.jar:lib/util.jar jscheme.REPL mc.scm -main main $@ diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm b/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm deleted file mode 100644 index 3e9b51409ec..00000000000 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm +++ /dev/null @@ -1,662 +0,0 @@ -; Scheme program to produce CORBA standard exceptions class -; requires Jscheme Java extensions -; Makes use of some custom Java classes also - -(import "com.sun.tools.corba.se.logutil.IndentingPrintWriter" ) -(import "com.sun.tools.corba.se.logutil.StringUtil" ) -(import "java.io.FileOutputStream") - -(define version-string "1.3") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Utility functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; reload this file (convenience definition) -(define (reload) (load "mc.scm")) - -; Simple little function to report an error -(define (error msg) - (throw (Error. msg))) - -; some debug support -(define debug #f) - -(define (dprint msg) - (if debug - (.println System.out$ msg))) - -; Replace dprint with noprint to avoid seeing messages when debug is #t -(define (noprint msg) ()) - -; Helper function present so that a scheme method taking strings as args -; can be easily run from a command line. -; arg: vector containing argument strings. Element 0 is the function name -; to execute -(define (main arg) - (let* - ( - (arg-list (vector->list arg)) - (function-symbol (string->symbol (car arg-list))) - (args (cdr arg-list))) - (apply (eval function-symbol) args))) - -; Returns the position of key in lst, numbering from 0. key is matched using eqv? -(define (get-list-position key lst) - (letrec - ( - (helper (lambda (k l accum) - (cond - ((null? l) (error (string-append "Could not find " k))) - ((eqv? k (car l)) accum) - (else (helper k (cdr l) (+ accum 1))) )))) - (begin - (noprint (string-append "get-list-position called with key " key " lst " lst )) - (helper key lst 0)))) - -; Return a string representing number in decimal padded to length with leading 0s. -(define (pad-number-string number length) - (let* - ( - (number-string (number->string number)) - (pad-length (- length (string-length number-string))) - ) - (string-append (make-string pad-length #\0) number-string))) - -; Read an S-expression from a file that contains all of the data. -; -; The S-expression used for minor codes must have the structure -; (package-name class-name exception-group-name -; (exception -; (name value level explanation) -; ... -; ) -; ... -; ) -(define (read-file fname) - (read (open-input-file fname))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Functions for handling major system exceptions and exception groups -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Function to find the base ID given an exception group name. Result is a function that -; maps the minor code into the Java expression for that minor code's actual value. -(define (get-base group-name) - (if (eqv? group-name 'OMG) - (lambda (minor-code) - (string-append "OMGVMCID.value + " (number->string minor-code))) - (let ; bind base-number outside the lambda so it is only evaluated once - ( - (base-number (get-sun-base-number group-name))) - (lambda (minor-code) - (string-append "SUNVMCID.value + " (number->string (+ base-number minor-code))))))) - -; Function to get a base value for the group-name -(define (get-sun-base-number group-name) - (let* - ( - (lst (list 'SUNBASE 'ORBUTIL 'ACTIVATION 'NAMING 'INTERCEPTORS 'POA 'IOR 'UTIL)) - (subsystem-size 200)) - (* subsystem-size (get-list-position group-name lst)))) - -; Function to get a 3 digit number for a system exception -(define (get-exception-id exception-name) - (let - ( - (lst (list 'UNKNOWN 'BAD_PARAM 'NO_MEMORY 'IMP_LIMIT 'COMM_FAILURE 'INV_OBJREF 'NO_PERMISSION - 'INTERNAL 'MARSHAL 'INITIALIZE 'NO_IMPLEMENT 'BAD_TYPECODE 'BAD_OPERATION 'NO_RESOURCES - 'NO_RESPONSE 'PERSIST_STORE 'BAD_INV_ORDER 'TRANSIENT 'FREE_MEM 'INV_IDENT 'INV_FLAG - 'INTF_REPOS 'BAD_CONTEXT 'OBJ_ADAPTER 'DATA_CONVERSION 'OBJECT_NOT_EXIST 'TRANSACTION_REQUIRED - 'TRANSACTION_ROLLEDBACK 'INVALID_TRANSACTION 'INV_POLICY 'CODESET_INCOMPATIBLE 'REBIND - 'TIMEOUT 'TRANSACTION_UNAVAILABLE 'BAD_QOS 'INVALID_ACTIVITY 'ACTIVITY_COMPLETED - 'ACTIVITY_REQUIRED ))) - (pad-number-string (get-list-position exception-name lst) 3))) - -; Return the message id string for any system exception -; -(define (get-message-id exception-type group-name minor) - (if (eqv? group-name 'OMG) - (get-standard-message-id exception-type minor) - (get-sun-message-id exception-type group-name minor))) - -; Return the message id string for a particular standard exception -; -(define (get-standard-message-id exception-type minor) - (string-append - "IOP" - (get-exception-id exception-type) - "0" - (pad-number-string (number->string minor) 4))) - -; Return the sun message id for this exception-type, group-name, and minor code. -(define (get-sun-message-id exception-type group-name minor) - (string-append - "IOP" - (get-exception-id exception-type) - "1" - (pad-number-string (+ (get-sun-base-number group-name) minor) 4))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; visitor framework for the input file format -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define (visit-top obj func1) - (let* - ( - (package (car obj)) - (class (cadr obj)) - (group (caddr obj)) - (func2 (func1 package class group)) - (exceptions (cadddr obj))) - (visit-exceptions exceptions func2))) - -; visit the elements of an arbitrary list -; lst: the list to visit -; func: the function to apply to each element of lst -; next-level the function on lst element and func that visits the next level -(define (visit-list lst func next-level) - (if (null? (cdr lst)) - (next-level #t (car lst) func) - (begin - (next-level #f (car lst) func) - (visit-list (cdr lst) func next-level)))) - -(define (visit-exceptions exceptions func2) - (visit-list exceptions func2 (lambda (last-flag element func) (visit-exception last-flag element func)))) - -(define (visit-exception last-flag exception func2) - (let* - ( - (major (car exception)) - (minor-codes (cdr exception)) - (func3 (func2 last-flag major))) - (visit-minor-codes minor-codes func3))) - -(define (visit-minor-codes minor-codes func3) - (visit-list minor-codes func3 (lambda (last-flag element func) (visit-minor-code last-flag element func)))) - -(define (visit-minor-code last-flag minor-code func3) - (let* - ( - (name (car minor-code)) - (minor (cadr minor-code)) - (level (caddr minor-code)) - (msg (cadddr minor-code))) - (func3 last-flag name minor level msg))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; The visitors -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; A simple visitor that just echoes the input for test purposes -(define (simple-visitor package class group) - (let* - ( - (pw (IndentingPrintWriter. System.out$))) - (begin - (.indent pw) - (.printMsg pw "package=@ class=@ group=@" (list package class group)) - (.flush pw) - (lambda (last-flag major) - (begin - (.indent pw) - (.printMsg pw "major=@" (list major)) - (.flush pw) - (lambda (last-flag name minor level message) - (begin - (if last-flag (.undent pw)) - (.printMsg pw "name=@ minor=@ level=@ message=@" (list name minor level message)) - (.flush pw)))))))) - -; Function that returns a visitor that writes out the resource file in the form: -; id="MSGID: explanation" -; outdir: Output directory -(define (resource-visitor outdir) - (lambda (package class group) - (let* - ( - (file-name (string-append outdir java.io.File.separator$ class ".resource")) - (pw (IndentingPrintWriter. (FileOutputStream. file-name)))) - (begin - (dprint (string-append "package= " package " class=" class " group=" group " file-name=" file-name)) - (lambda (last-flag1 major) - (begin - ; (dprint (string-append "last-flag1=" last-flag1 " major=" major)) - (lambda (last-flag2 name minor level message) - (begin - ; (dprint (string-append "last-flag2=" last-flag2 " name=" name - ; " minor=" minor " level=" level " message=" message)) - (let* - ( - (msgid (get-message-id major group minor)) - (ident (StringUtil.toMixedCase (symbol->string name)))) - (begin - ; (dprint (string-append "msgid=" msgid " ident=" ident)) - (.printMsg pw "@.@=\"@: (@) @\"" (list group ident msgid major message)) - (.flush pw) - (if (and last-flag1 last-flag2) - (begin - ; (dprint "closing file") - (.close pw))))))))))))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Top-level functions for creating the products. All have names of the form make-xxx -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Read the minor codes from the infile and write out a resource file. -(define (make-resource infile outdir) - (tryCatch - (visit-top (read-file infile) (resource-visitor outdir)) - (lambda (exc) - (begin - (.println System.out$ (string-append "make-resource failed with exception " (.toString exc))) - (System.exit 1))))) - -; Read the minor codes from the infile and write a Java implementation to -; handle them to outfile under outdir -(define (make-class infile outdir) - (tryCatch - (write-class infile outdir (read-file infile)) - (lambda (exc) - (begin - (.println System.out$ (string-append "make-class failed with exception " (.toString exc))) - (System.exit 1))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; The original make-class implementation (this should be replaced by two visitors) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Write out the Java source code for the StandardExceptions class -; outdir: Output directory to write the generated files -; obj: the data from the input file -(define (write-class infile outdir obj) - (let* - ( - (package-name (car obj)) - (class-name (cadr obj)) - (exception-group-name (caddr obj)) - (exceptions (cadddr obj)) - (file (FileOutputStream. (string-append outdir java.io.File.separator$ class-name ".java"))) - (pw (IndentingPrintWriter. file)) - ) - (begin - (write-class-header infile package-name class-name exception-group-name pw) - (.printMsg pw "package @ ;" - (list package-name)) - (.println pw) - (.println pw "import java.util.logging.Logger ;") - (.println pw "import java.util.logging.Level ;") - (.println pw) - (.println pw "import org.omg.CORBA.OMGVMCID ;") - (.println pw "import com.sun.corba.se.impl.util.SUNVMCID ;") - (.println pw "import org.omg.CORBA.CompletionStatus ;") - (.println pw "import org.omg.CORBA.SystemException ;") - (.println pw) - (.println pw "import com.sun.corba.se.spi.orb.ORB ;") - (.println pw) - (.println pw "import com.sun.corba.se.spi.logging.LogWrapperFactory;") - (.println pw) - (.println pw "import com.sun.corba.se.spi.logging.LogWrapperBase;") - (.println pw) - (write-imports exceptions pw) - (.println pw) - (.indent pw) - (.printMsg pw "public class @ extends LogWrapperBase {" - (list class-name)) - (.println pw) - (.printMsg pw "public @( Logger logger )" - (list class-name)) - (.indent pw) - (.println pw "{") - (.undent pw) - (.println pw "super( logger ) ;") - (.println pw "}") - (.println pw) - (.flush pw) - (write-factory-method class-name exception-group-name pw) - (write-exceptions exception-group-name exceptions (get-base exception-group-name) class-name pw) - (.undent pw) - (.println pw ) - (.println pw "}") - (.flush pw) - (.close pw) - ))) - -; Write out the header for the resource file -(define (write-class-header infile package class group pw) - (begin - (if (eqv? group 'OMG) - (.println pw "// Log wrapper class for standard exceptions") - (.printMsg pw "// Log wrapper class for Sun private system exceptions in group @" (list group))) - (.println pw "//") - (.printMsg pw "// Generated by mc.scm version @, DO NOT EDIT BY HAND!" (list version-string)) - (.printMsg pw "// Generated from input file @ on @" (list infile (java.util.Date.))) - (.println pw))) - -(define (write-factory-method class-name exception-group-name pw) - (begin - (.indent pw) - (.println pw "private static LogWrapperFactory factory = new LogWrapperFactory() {") - (.println pw "public LogWrapperBase create( Logger logger )" ) - (.indent pw) - (.println pw "{") - (.undent pw) - (.printMsg pw "return new @( logger ) ;" (list class-name)) - (.undent pw) - (.println pw "}" ) - (.println pw "} ;" ) - (.println pw) - (.printMsg pw "public static @ get( ORB orb, String logDomain )" (list class-name)) - (.indent pw) - (.println pw "{") - (.indent pw) - (.printMsg pw "@ wrapper = " - (list class-name)) - (.indent pw) - (.printMsg pw "(@) orb.getLogWrapper( logDomain, " - (list class-name)) - (.undent pw) - (.undent pw) - (.printMsg pw "\"@\", factory ) ;" - (list exception-group-name)) - (.undent pw) - (.println pw "return wrapper ;" ) - (.println pw "} " ) - (.println pw) - (.printMsg pw "public static @ get( String logDomain )" (list class-name)) - (.indent pw) - (.println pw "{") - (.indent pw) - (.printMsg pw "@ wrapper = " - (list class-name)) - (.indent pw) - (.printMsg pw "(@) ORB.staticGetLogWrapper( logDomain, " - (list class-name)) - (.undent pw) - (.undent pw) - (.printMsg pw "\"@\", factory ) ;" - (list exception-group-name)) - (.undent pw) - (.println pw "return wrapper ;" ) - (.println pw "} " ) - (.println pw))) - -; Write out the import list for the exceptions listed in obj -; obj: the data from the input file -; pw: an IndentingPrintWriter for the output file -(define (write-imports obj pw) - (if (null? obj) - () - (let - ( - (exception (caar obj)) - ) - (begin - (.print pw "import org.omg.CORBA.") - (.print pw exception) - (.println pw " ;") - (write-imports (cdr obj) pw) - )))) - -; Write out the list of exceptions starting with the first one -; obj: the data from the input file -; base: the lambda that returns the string defining the minor code value -; pw: an IndentingPrintWriter for the output file -(define (write-exceptions group-name obj base class-name pw) - (if (null? obj) - () - (let* - ( - (record (car obj)) - (exception (car record)) - (minor-codes (cdr record)) - ) - (begin - (write-exception group-name exception minor-codes base class-name pw) - (write-exceptions group-name (cdr obj) base class-name pw) - )))) - -; Write out a single exception -; exception: the CORBA SystemException type -; base: the base for the minor code value -; minor-codes: a list of minor code data for each minor exception type -; pw: an IndentingPrintWriter for the output file -(define (write-exception group-name exception minor-codes base class-name pw) - (begin - (.println pw "///////////////////////////////////////////////////////////") - (.printMsg pw "// @" (list exception)) - (.println pw "///////////////////////////////////////////////////////////") - (.println pw) - (write-methods group-name exception minor-codes base class-name pw) - (.flush pw))) - -; Write all of the methods for a single exception -; exception: the CORBA SystemException type -; base: the base for the minor code value -; minor-codes: a list of minor code data for each minor exception type -; pw: an IndentingPrintWriter for the output file -(define (write-methods group-name exception minor-codes base class-name pw) - (if (null? minor-codes) - () - (begin - (write-method group-name exception (car minor-codes) base class-name pw) - (write-methods group-name exception (cdr minor-codes) base class-name pw) - ))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Code that writes out the Java methods for exception handling -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Write the methods for a single minor code within an exception -; exception: the CORBA SystemException type -; minor-code: minor code data for one minor exception type -; (name value level explanation) -; base: the base for the minor code value -; pw: an IndentingPrintWriter for the output file -(define (write-method group-name exception minor-code base class-name pw) - (let* - ( - (x (symbol->string (car minor-code))) - (ident (cons x (StringUtil.toMixedCase x))) - (value (cadr minor-code)) - (level (symbol->string (caddr minor-code))) - (explanation (cadddr minor-code)) - (num-params (StringUtil.countArgs explanation))) - (begin - (.printMsg pw "public static final int @ = @ ;" - (list x (base value))) - (.println pw ) - (.flush pw ) - (write-method-status-cause group-name exception ident level num-params class-name pw) - (.println pw) - (.flush pw) - (write-method-status exception ident level num-params pw) - (.println pw) - (.flush pw) - (write-method-cause exception ident level num-params pw) - (.println pw) - (.flush pw) - (write-method-no-args exception ident level num-params pw) - (.println pw) - (.flush pw)))) - -; Construct a string of the form arg1, ..., argn where n is num-params -(define (make-arg-string fixed leading-comma-flag num-args) - (let - ( - (helper (lambda (lcf n) - (let* - ( - (numstr (number->string (- n 1)))) - (if (or lcf (> n 1)) - (string-append ", " fixed numstr) - (string-append " " fixed numstr)))))) - (cond - ((eqv? num-args 0) " ") - ((eqv? num-args 1) (helper leading-comma-flag 1)) - (else (string-append - (make-arg-string fixed leading-comma-flag (- num-args 1)) - (helper leading-comma-flag num-args )))))) - -(define (make-decl-args leading-comma-flag num-args) - (make-arg-string "Object arg" leading-comma-flag num-args)) - -(define (make-call-args leading-comma-flag num-args) - (make-arg-string "arg" leading-comma-flag num-args)) - -; make-xxx-args patterns: -; leading-comma-flag #t -; -; 0 " " -; 1 ", arg0" -; 2 ", arg0, arg1" -; 3 ", arg0, arg1, arg2" -; -; 0 " " -; 1 ", Object arg0" -; 2 ", Object arg0, Object arg1" -; 3 ", Object arg0, Object arg1, Object arg2" -; -; leading-comma-flag #f -; -; 0 " " -; 1 " arg0" -; 2 " arg0, arg1" -; 3 " arg0, arg1, arg2" -; -; 0 " " -; 1 " Object arg0" -; 2 " Object arg0, Object arg1" -; 3 " Object arg0, Object arg1, Object arg2" - -(define (emit-assignments num pw) - (let - ( - (helper - (lambda (n) - (.printMsg pw "parameters[@] = arg@ ;" (list n n))))) - (if (= num 1) - (helper (- num 1)) - (begin - (emit-assignments (- num 1) pw) - (helper (- num 1)))))) - -; Write a method for an exception that takes a CompletionStatus and a cause -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-status-cause group-name exception id level num-params class-name pw) - (let* - ( - (ident (car id)) - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( CompletionStatus cs, Throwable t@) {" - (list exception ident-mc (make-decl-args #t num-params))) - (.printMsg pw "@ exc = new @( @, cs ) ;" - (list exception exception ident )) - - (.indent pw) - (.println pw "if (t != null)" ) - (.undent pw) - (.println pw "exc.initCause( t ) ;" ) - (.println pw) - - (.indent pw) - (.printMsg pw "if (logger.isLoggable( Level.@ )) {" - (list level)) - - (if (> num-params 0) - (begin - (.printMsg pw "Object[] parameters = new Object[@] ;" - (list (number->string num-params))) - (emit-assignments num-params pw) - ) - (begin - (.println pw "Object[] parameters = null ;" - ))) - - (.indent pw) - (.printMsg pw "doLog( Level.@, \"@.@\"," (list level group-name ident-mc)) - (.undent pw) - (.undent pw) - (.printMsg pw "parameters, @.class, exc ) ;" (list class-name)) - (.println pw "}") - (.println pw) - - (.undent pw) - (.println pw "return exc ;") - - (.println pw "}")))) - -; Write a method for an exception that takes a CompletionStatus. The cause is null. -; -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-status exception id level num-params pw) - (let* - ( - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( CompletionStatus cs@) {" - (list exception ident-mc (make-decl-args #t num-params))) - (.undent pw) - (.printMsg pw "return @( cs, null@ ) ;" - (list ident-mc (make-call-args #t num-params))) - (.println pw "}")))) - -; Write a method for an exception that takes a cause. The status is COMPLETED_NO. -; -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-cause exception id level num-params pw) - (let* - ( - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( Throwable t@) {" - (list exception ident-mc (make-decl-args #t num-params))) - (.undent pw) - (.printMsg pw "return @( CompletionStatus.COMPLETED_NO, t@ ) ;" - (list ident-mc (make-call-args #t num-params))) - (.println pw "}")))) - -; Write a method for an exception that takes no arguments. This is COMPLETED_NO and -; a null cause. -; -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-no-args exception id level num-params pw) - (let* - ( - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( @) {" - (list exception ident-mc (make-decl-args #f num-params))) - (.undent pw) - (.printMsg pw "return @( CompletionStatus.COMPLETED_NO, null@ ) ;" - (list ident-mc (make-call-args #t num-params))) - (.println pw "}")))) - -;;; end of file diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run b/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run deleted file mode 100644 index 81efed3479a..00000000000 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -java -cp ${CLASSPATH}:lib/jscheme.jar:lib/util.jar jscheme.REPL mc.scm diff --git a/corba/src/share/classes/org/omg/CORBA/ir.idl b/corba/src/share/classes/org/omg/CORBA/ir.idl index d7312f993a1..60a985fa516 100644 --- a/corba/src/share/classes/org/omg/CORBA/ir.idl +++ b/corba/src/share/classes/org/omg/CORBA/ir.idl @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/corba/src/share/classes/org/omg/DynamicAny/DynamicAny.idl b/corba/src/share/classes/org/omg/DynamicAny/DynamicAny.idl index 2d21393963e..204880e1484 100644 --- a/corba/src/share/classes/org/omg/DynamicAny/DynamicAny.idl +++ b/corba/src/share/classes/org/omg/DynamicAny/DynamicAny.idl @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/corba/src/windows/resource/version.rc b/corba/src/windows/resource/version.rc index 61311efabcf..41479562435 100644 --- a/corba/src/windows/resource/version.rc +++ b/corba/src/windows/resource/version.rc @@ -23,7 +23,7 @@ // have any questions. // -#include "afxres.h" +#include "windows.h" // Need 2 defines so macro argument to XSTR will get expanded before quoting. #define XSTR(x) STR(x) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 95ce2df1f90..eab9a6d2f3c 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -23,3 +23,9 @@ fc6a5ae3fef5ebacfa896dbb3ae37715e388e282 jdk7-b43 16bb38eeda35b46268eefa4c1f829eb086e0ca46 jdk7-b46 fcb923bad68e2b10380a030ea83a723f4dc3d4d6 jdk7-b47 bcb33806d186561c781992e5f4d8a90bb033f9f0 jdk7-b48 +8b22ccb5aba2c6c11bddf6488a7bb7ef5b4bf2be jdk7-b49 +dae503d9f04c1a11e182dbf7f770509c28dc0609 jdk7-b50 +2581d90c6c9b2012da930eb4742add94a03069a0 jdk7-b51 +1b1e8f1a4fe8cebc01c022484f78148e17b62a0d jdk7-b52 +032c6af894dae8d939b3dd31d82042549e7793e0 jdk7-b53 +fafab5d5349c7c066d677538db67a1ee0fb33bd2 jdk7-b54 diff --git a/hotspot/agent/src/os/linux/ps_core.c b/hotspot/agent/src/os/linux/ps_core.c index a6156f0a8d4..95e14574894 100644 --- a/hotspot/agent/src/os/linux/ps_core.c +++ b/hotspot/agent/src/os/linux/ps_core.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/agent/src/os/solaris/proc/saproc.cpp b/hotspot/agent/src/os/solaris/proc/saproc.cpp index 415e28af658..dc1018e2602 100644 --- a/hotspot/agent/src/os/solaris/proc/saproc.cpp +++ b/hotspot/agent/src/os/solaris/proc/saproc.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java index acbb90d4b66..41e71c2228e 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java @@ -118,9 +118,9 @@ public interface Debugger extends SymbolLookup, ThreadAccess { public long getJIntSize(); public long getJLongSize(); public long getJShortSize(); - public long getHeapBase(); public long getHeapOopSize(); - public long getLogMinObjAlignmentInBytes(); + public long getNarrowOopBase(); + public int getNarrowOopShift(); public ReadResult readBytesFromProcess(long address, long numBytes) throws DebuggerException; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java index 7b4ca75f431..8f5c732499b 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java @@ -56,8 +56,8 @@ public abstract class DebuggerBase implements Debugger { // heap data. protected long oopSize; protected long heapOopSize; - protected long heapBase; // heap base for compressed oops. - protected long logMinObjAlignmentInBytes; // Used to decode compressed oops. + protected long narrowOopBase; // heap base for compressed oops. + protected int narrowOopShift; // shift to decode compressed oops. // Should be initialized if desired by calling initCache() private PageCache cache; @@ -159,10 +159,10 @@ public abstract class DebuggerBase implements Debugger { javaPrimitiveTypesConfigured = true; } - public void putHeapConst(long heapBase, long heapOopSize, long logMinObjAlignmentInBytes) { - this.heapBase = heapBase; + public void putHeapConst(long heapOopSize, long narrowOopBase, int narrowOopShift) { this.heapOopSize = heapOopSize; - this.logMinObjAlignmentInBytes = logMinObjAlignmentInBytes; + this.narrowOopBase = narrowOopBase; + this.narrowOopShift = narrowOopShift; } /** May be called by subclasses if desired to initialize the page @@ -459,7 +459,7 @@ public abstract class DebuggerBase implements Debugger { long value = readCInteger(address, getHeapOopSize(), true); if (value != 0) { // See oop.inline.hpp decode_heap_oop - value = (long)(heapBase + (long)(value << logMinObjAlignmentInBytes)); + value = (long)(narrowOopBase + (long)(value << narrowOopShift)); } return value; } @@ -545,10 +545,10 @@ public abstract class DebuggerBase implements Debugger { return heapOopSize; } - public long getHeapBase() { - return heapBase; + public long getNarrowOopBase() { + return narrowOopBase; } - public long getLogMinObjAlignmentInBytes() { - return logMinObjAlignmentInBytes; + public int getNarrowOopShift() { + return narrowOopShift; } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java index 679036cdac0..80b71637393 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java @@ -42,5 +42,5 @@ public interface JVMDebugger extends Debugger { long jintSize, long jlongSize, long jshortSize); - public void putHeapConst(long heapBase, long heapOopSize, long logMinObjAlignment); + public void putHeapConst(long heapOopSize, long narrowOopBase, int narrowOopShift); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java index 179fc1e9d64..df03ce3e01c 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java @@ -65,9 +65,10 @@ public interface RemoteDebugger extends Remote { public long getJIntSize() throws RemoteException; public long getJLongSize() throws RemoteException; public long getJShortSize() throws RemoteException; - public long getHeapBase() throws RemoteException; public long getHeapOopSize() throws RemoteException; - public long getLogMinObjAlignmentInBytes() throws RemoteException; + public long getNarrowOopBase() throws RemoteException; + public int getNarrowOopShift() throws RemoteException; + public boolean areThreadsEqual(long addrOrId1, boolean isAddress1, long addrOrId2, boolean isAddress2) throws RemoteException; public int getThreadHashCode(long addrOrId, boolean isAddress) throws RemoteException; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java index c1464f3d98c..8a1bacb2fee 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java @@ -85,9 +85,9 @@ public class RemoteDebuggerClient extends DebuggerBase implements JVMDebugger { jlongSize = remoteDebugger.getJLongSize(); jshortSize = remoteDebugger.getJShortSize(); javaPrimitiveTypesConfigured = true; - heapBase = remoteDebugger.getHeapBase(); + narrowOopBase = remoteDebugger.getNarrowOopBase(); + narrowOopShift = remoteDebugger.getNarrowOopShift(); heapOopSize = remoteDebugger.getHeapOopSize(); - logMinObjAlignmentInBytes = remoteDebugger.getLogMinObjAlignmentInBytes(); } catch (RemoteException e) { throw new DebuggerException(e); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java index cdc5c713619..edb52a65012 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java @@ -114,17 +114,18 @@ public class RemoteDebuggerServer extends UnicastRemoteObject return debugger.getJShortSize(); } - public long getHeapBase() throws RemoteException { - return debugger.getHeapBase(); - } - public long getHeapOopSize() throws RemoteException { return debugger.getHeapOopSize(); } - public long getLogMinObjAlignmentInBytes() throws RemoteException { - return debugger.getLogMinObjAlignmentInBytes(); + public long getNarrowOopBase() throws RemoteException { + return debugger.getNarrowOopBase(); } + + public int getNarrowOopShift() throws RemoteException { + return debugger.getNarrowOopShift(); + } + public boolean areThreadsEqual(long addrOrId1, boolean isAddress1, long addrOrId2, boolean isAddress2) throws RemoteException { ThreadProxy t1 = getThreadProxy(addrOrId1, isAddress1); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java index d20dfae7445..b9cdc92ff03 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java @@ -53,7 +53,8 @@ public class Universe { // system obj array klass object private static sun.jvm.hotspot.types.OopField systemObjArrayKlassObjField; - private static AddressField heapBaseField; + private static AddressField narrowOopBaseField; + private static CIntegerField narrowOopShiftField; static { VM.registerVMInitializedObserver(new Observer() { @@ -86,7 +87,8 @@ public class Universe { systemObjArrayKlassObjField = type.getOopField("_systemObjArrayKlassObj"); - heapBaseField = type.getAddressField("_heap_base"); + narrowOopBaseField = type.getAddressField("_narrow_oop._base"); + narrowOopShiftField = type.getCIntegerField("_narrow_oop._shift"); } public Universe() { @@ -100,14 +102,18 @@ public class Universe { } } - public static long getHeapBase() { - if (heapBaseField.getValue() == null) { + public static long getNarrowOopBase() { + if (narrowOopBaseField.getValue() == null) { return 0; } else { - return heapBaseField.getValue().minus(null); + return narrowOopBaseField.getValue().minus(null); } } + public static int getNarrowOopShift() { + return (int)narrowOopShiftField.getValue(); + } + /** Returns "TRUE" iff "p" points into the allocated area of the heap. */ public boolean isIn(Address p) { return heap().isIn(p); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java index be55ca524c7..fad351b495d 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java @@ -46,12 +46,18 @@ public class StubRoutines { Type type = db.lookupType("StubRoutines"); callStubReturnAddressField = type.getAddressField("_call_stub_return_address"); - // Only some platforms have specif return from compiled to call_stub + // Only some platforms have specific return from compiled to call_stub try { - callStubCompiledReturnAddressField = type.getAddressField("_call_stub_compiled_return"); + type = db.lookupType("StubRoutines::x86"); + if (type != null) { + callStubCompiledReturnAddressField = type.getAddressField("_call_stub_compiled_return"); + } } catch (RuntimeException re) { callStubCompiledReturnAddressField = null; } + if (callStubCompiledReturnAddressField == null && VM.getVM().getCPU().equals("x86")) { + throw new InternalError("Missing definition for _call_stub_compiled_return"); + } } public StubRoutines() { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java index 0272c069352..44fb1a817ea 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -342,11 +342,14 @@ public class VM { throw new RuntimeException("Attempt to initialize VM twice"); } soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian()); - debugger.putHeapConst(Universe.getHeapBase(), soleInstance.getHeapOopSize(), - soleInstance.logMinObjAlignmentInBytes); + + debugger.putHeapConst(soleInstance.getHeapOopSize(), Universe.getNarrowOopBase(), + Universe.getNarrowOopShift()); + for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) { ((Observer) iter.next()).update(null, null); } + } /** This is used by the debugging system */ diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index eea8597c7cf..64a2efe6dd1 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -1,5 +1,5 @@ # -# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,11 @@ # # Don't put quotes (fail windows build). -HOTSPOT_VM_COPYRIGHT=Copyright 2008 +HOTSPOT_VM_COPYRIGHT=Copyright 2009 HS_MAJOR_VER=15 HS_MINOR_VER=0 -HS_BUILD_NUMBER=02 +HS_BUILD_NUMBER=05 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff --git a/hotspot/make/jprt.properties b/hotspot/make/jprt.properties index 012015262ae..63320086cd8 100644 --- a/hotspot/make/jprt.properties +++ b/hotspot/make/jprt.properties @@ -19,12 +19,12 @@ # Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. -# +# # # Properties for jprt -# All build result bundles are full jdks, so the 64bit testing does not +# All build result bundles are full jdks, so the 64bit testing does not # need the 32bit sibling bundle installed. # Note: If the hotspot/make/Makefile changed to only bundle the 64bit files # when bundling 64bit, and stripped out the 64bit files from any 32bit @@ -89,60 +89,52 @@ jprt.my.solaris.sparc.test.targets= \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jvm98, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese, \ - ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese_Xcomp, \ - ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese_Xcomp_2, \ - ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese_Xcomp_3, \ ${jprt.my.solaris.sparc}-fastdebug-c1-runThese_Xshare, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_default, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_default_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_CMS_2, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_G1, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParOldGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_default, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_SerialGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParallelGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParNewGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_CMS, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_G1, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_default, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_SerialGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParallelGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_CMS, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark_3 + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_G1, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParOldGC jprt.my.solaris.sparcv9.test.targets= \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark, \ ${jprt.my.solaris.sparcv9}-product-c2-runThese, \ - ${jprt.my.solaris.sparcv9}-product-c2-runThese_Xcomp, \ - ${jprt.my.solaris.sparcv9}-product-c2-runThese_Xcomp_2, \ - ${jprt.my.solaris.sparcv9}-product-c2-runThese_Xcomp_3, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_default, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_SerialGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_default_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_SerialGC_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParallelGC_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParNewGC_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_CMS_2, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_G1, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_default, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_SerialGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParallelGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParNewGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_SerialGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParallelGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_CMS, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark_3 + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_G1, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParOldGC jprt.my.solaris.x64.test.targets= \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98, \ @@ -154,73 +146,80 @@ jprt.my.solaris.x64.test.targets= \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_default_2, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_SerialGC_2, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC_2, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC_2, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_CMS_2, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_G1, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_default, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_SerialGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_CMS + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC jprt.my.solaris.i586.test.targets= \ ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.solaris.i586}-product-{c1|c2}-runThese_Xcomp, \ - ${jprt.my.solaris.i586}-product-c2-runThese_Xcomp_2, \ - ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xcomp_2, \ + ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xcomp, \ ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xshare, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_default, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_SerialGC, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_ParallelGC, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_ParNewGC, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_CMS, \ + ${jprt.my.solaris.i586}-product-c1-GCBasher_G1, \ + ${jprt.my.solaris.i586}-product-c1-GCBasher_ParOldGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_default, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_SerialGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParallelGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParNewGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_CMS, \ + ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_G1, \ + ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParOldGC, \ ${jprt.my.solaris.i586}-product-c1-GCOld_default, \ ${jprt.my.solaris.i586}-product-c1-GCOld_SerialGC, \ ${jprt.my.solaris.i586}-product-c1-GCOld_ParallelGC, \ ${jprt.my.solaris.i586}-product-c1-GCOld_ParNewGC, \ ${jprt.my.solaris.i586}-product-c1-GCOld_CMS, \ + ${jprt.my.solaris.i586}-product-c1-GCOld_G1, \ + ${jprt.my.solaris.i586}-product-c1-GCOld_ParOldGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_default, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParallelGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_CMS, \ - ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark_2, \ - ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark_3 + ${jprt.my.solaris.i586}-fastdebug-c2-jbb_G1, \ + ${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParOldGC jprt.my.linux.i586.test.targets = \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.linux.i586}-product-c1-runThese_Xcomp, \ - ${jprt.my.linux.i586}-product-c1-runThese_Xcomp_2, \ - ${jprt.my.linux.i586}-product-c1-runThese_Xcomp_3, \ ${jprt.my.linux.i586}-fastdebug-c1-runThese_Xshare, \ ${jprt.my.linux.i586}-fastdebug-c2-runThese_Xcomp, \ - ${jprt.my.linux.i586}-fastdebug-c2-runThese_Xcomp_2, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_default, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_G1, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParOldGC, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_default, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_SerialGC, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParallelGC, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParNewGC, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_CMS, \ + ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_G1, \ + ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_default, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParallelGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_CMS, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-scimark_2, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-scimark_3 + ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_G1, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParOldGC jprt.my.linux.x64.test.targets = \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98, \ @@ -230,15 +229,19 @@ jprt.my.linux.x64.test.targets = \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_G1, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_default, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark_2, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark_3 + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_G1, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParOldGC jprt.my.windows.i586.test.targets = \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ @@ -251,16 +254,20 @@ jprt.my.windows.i586.test.targets = \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_G1, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParOldGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_default, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_SerialGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParallelGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParNewGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_CMS, \ + ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_G1, \ + ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jbb_default, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParallelGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_CMS, \ - ${jprt.my.windows.i586}-product-{c1|c2}-scimark_2, \ - ${jprt.my.windows.i586}-product-{c1|c2}-scimark_3 + ${jprt.my.windows.i586}-product-{c1|c2}-jbb_G1, \ + ${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParOldGC jprt.my.windows.x64.test.targets = \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98, \ @@ -272,16 +279,20 @@ jprt.my.windows.x64.test.targets = \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_G1, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_default, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default, \ ${jprt.my.windows.x64}-product-c2-jbb_CMS, \ ${jprt.my.windows.x64}-product-c2-jbb_ParallelGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark_2, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark_3 + ${jprt.my.windows.x64}-product-c2-jbb_G1, \ + ${jprt.my.windows.x64}-product-c2-jbb_ParOldGC # The complete list of test targets for jprt diff --git a/hotspot/make/linux/makefiles/adlc.make b/hotspot/make/linux/makefiles/adlc.make index 5e48fed1567..927462967f7 100644 --- a/hotspot/make/linux/makefiles/adlc.make +++ b/hotspot/make/linux/makefiles/adlc.make @@ -1,5 +1,5 @@ # -# Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -61,8 +61,8 @@ CPPFLAGS = $(SYSDEFS) $(INCLUDES) CPPFLAGS += -DASSERT # CFLAGS_WARN holds compiler options to suppress/enable warnings. -# Suppress warnings (for now) -CFLAGS_WARN = -w +# Compiler warnings are treated as errors +CFLAGS_WARN = -Werror CFLAGS += $(CFLAGS_WARN) OBJECTNAMES = \ diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index 4a01c29c50e..002e960d36e 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -1,5 +1,5 @@ # -# Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -131,6 +131,14 @@ endif # Enable linker optimization LFLAGS += -Xlinker -O1 +# If this is a --hash-style=gnu system, use --hash-style=both +# The gnu .hash section won't work on some Linux systems like SuSE 10. +_HAS_HASH_STYLE_GNU:=$(shell $(CC) -dumpspecs | grep -- '--hash-style=gnu') +ifneq ($(_HAS_HASH_STYLE_GNU),) + LDFLAGS_HASH_STYLE = -Wl,--hash-style=both +endif +LFLAGS += $(LDFLAGS_HASH_STYLE) + # Use $(MAPFLAG:FILENAME=real_file_name) to specify a map file. MAPFLAG = -Xlinker --version-script=FILENAME diff --git a/hotspot/make/solaris/makefiles/adlc.make b/hotspot/make/solaris/makefiles/adlc.make index 2d1a87a20b4..b13e1fa528f 100644 --- a/hotspot/make/solaris/makefiles/adlc.make +++ b/hotspot/make/solaris/makefiles/adlc.make @@ -1,5 +1,5 @@ # -# Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -67,6 +67,8 @@ ifndef USE_GCC endif # CFLAGS_WARN holds compiler options to suppress/enable warnings. +# Compiler warnings are treated as errors +CFLAGS_WARN = +w -errwarn CFLAGS += $(CFLAGS_WARN) ifeq ("${Platform_compiler}", "sparcWorks") diff --git a/hotspot/make/windows/build_vm_def.sh b/hotspot/make/windows/build_vm_def.sh index 6cc931963b2..99e30bb1b9e 100644 --- a/hotspot/make/windows/build_vm_def.sh +++ b/hotspot/make/windows/build_vm_def.sh @@ -52,6 +52,19 @@ CAT="$MKS_HOME/cat.exe" RM="$MKS_HOME/rm.exe" DUMPBIN="link.exe /dump" +# When called from IDE the first param should contain the link version, otherwise may be nill +if [ "x$1" != "x" ]; then +LINK_VER="$1" +fi + +if [ "x$LINK_VER" != "x800" -a "x$LINK_VER" != "x900" ]; then $DUMPBIN /symbols *.obj | "$GREP" "??_7.*@@6B@" | "$AWK" '{print $7}' | "$SORT" | "$UNIQ" > vm2.def +else +# Can't use pipes when calling cl.exe or link.exe from IDE. Using transit file vm3.def +$DUMPBIN /OUT:vm3.def /symbols *.obj +"$CAT" vm3.def | "$GREP" "??_7.*@@6B@" | "$AWK" '{print $7}' | "$SORT" | "$UNIQ" > vm2.def +"$RM" -f vm3.def +fi + "$CAT" vm1.def vm2.def > vm.def "$RM" -f vm1.def vm2.def diff --git a/hotspot/make/windows/create.bat b/hotspot/make/windows/create.bat index 21f97033669..bdb1916107d 100644 --- a/hotspot/make/windows/create.bat +++ b/hotspot/make/windows/create.bat @@ -72,12 +72,20 @@ REM figure out MSC version for /F %%i in ('sh %HotSpotWorkSpace%/make/windows/get_msc_ver.sh') do set %%i echo ************************************************************** +set ProjectFile=vm.vcproj if "%MSC_VER%" == "1200" ( set ProjectFile=vm.dsp echo Will generate VC6 project {unsupported} ) else ( -set ProjectFile=vm.vcproj -echo Will generate VC7 project +if "%MSC_VER%" == "1400" ( +echo Will generate VC8 {Visual Studio 2005} +) else ( +if "%MSC_VER%" == "1500" ( +echo Will generate VC9 {Visual Studio 2008} +) else ( +echo Will generate VC7 project {Visual Studio 2003 .NET} +) +) ) echo %ProjectFile% echo ************************************************************** diff --git a/hotspot/make/windows/get_msc_ver.sh b/hotspot/make/windows/get_msc_ver.sh index 6bbbbef7859..67df0d0dd95 100644 --- a/hotspot/make/windows/get_msc_ver.sh +++ b/hotspot/make/windows/get_msc_ver.sh @@ -29,6 +29,7 @@ # cl version 13.10.3077 returns "MSC_VER=1310" # cl version 14.00.30701 returns "MSC_VER=1399" (OLD_MSSDK version) # cl version 14.00.40310.41 returns "MSC_VER=1400" +# cl version 15.00.21022.8 returns "MSC_VER=1500" # Note that we currently do not have a way to set HotSpotMksHome in # the batch build, but so far this has not seemed to be a problem. The diff --git a/hotspot/make/windows/makefiles/adlc.make b/hotspot/make/windows/makefiles/adlc.make index b6feb0e78b9..e9af2f964bb 100644 --- a/hotspot/make/windows/makefiles/adlc.make +++ b/hotspot/make/windows/makefiles/adlc.make @@ -46,6 +46,7 @@ ADLCFLAGS=-q -T -D_LP64 ADLCFLAGS=-q -T -U_LP64 !endif +CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_WARNINGS /D _CRT_SECURE_NO_DEPRECATE CPP_INCLUDE_DIRS=\ /I "..\generated" \ diff --git a/hotspot/make/windows/makefiles/compile.make b/hotspot/make/windows/makefiles/compile.make index ddc9ea11a9f..4906ab5a989 100644 --- a/hotspot/make/windows/makefiles/compile.make +++ b/hotspot/make/windows/makefiles/compile.make @@ -170,10 +170,6 @@ LINK_FLAGS = /manifest $(LINK_FLAGS) $(BUFFEROVERFLOWLIB) # Manifest Tool - used in VS2005 and later to adjust manifests stored # as resources inside build artifacts. MT=mt.exe -!if "$(BUILDARCH)" == "i486" -# VS2005 on x86 restricts the use of certain libc functions without this -CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE -!endif !endif !if "$(COMPILER_NAME)" == "VS2008" @@ -185,10 +181,6 @@ LINK_FLAGS = /manifest $(LINK_FLAGS) # Manifest Tool - used in VS2005 and later to adjust manifests stored # as resources inside build artifacts. MT=mt.exe -!if "$(BUILDARCH)" == "i486" -# VS2005 on x86 restricts the use of certain libc functions without this -CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE -!endif !endif # Compile for space above time. diff --git a/hotspot/make/windows/makefiles/makedeps.make b/hotspot/make/windows/makefiles/makedeps.make index 8bfe00737ab..43f25a4666d 100644 --- a/hotspot/make/windows/makefiles/makedeps.make +++ b/hotspot/make/windows/makefiles/makedeps.make @@ -48,6 +48,8 @@ MakeDepsSources=\ $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatform.java \ $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC6.java \ $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC7.java \ + $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC8.java \ + $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC9.java \ $(WorkSpace)\src\share\tools\MakeDeps\Util.java \ $(WorkSpace)\src\share\tools\MakeDeps\BuildConfig.java \ $(WorkSpace)\src\share\tools\MakeDeps\ArgsParser.java @@ -121,7 +123,7 @@ MakeDepsIDEOptions=\ -additionalFile includeDB_gc_shared \ -additionalFile includeDB_gc_serial \ -additionalGeneratedFile $(HOTSPOTBUILDSPACE)\%f\%b vm.def \ - -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh" \ + -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LINK_VER)" \ $(MakeDepsIncludesPRIVATE) # Add in build-specific options diff --git a/hotspot/make/windows/makefiles/rules.make b/hotspot/make/windows/makefiles/rules.make index f07f84aee1d..064fb3f231d 100644 --- a/hotspot/make/windows/makefiles/rules.make +++ b/hotspot/make/windows/makefiles/rules.make @@ -42,10 +42,23 @@ COMPILE_RMIC=rmic BOOT_JAVA_HOME= !endif +ProjectFile=vm.vcproj + !if "$(MSC_VER)" == "1200" + VcVersion=VC6 ProjectFile=vm.dsp + +!elseif "$(MSC_VER)" == "1400" + +VcVersion=VC8 + +!elseif "$(MSC_VER)" == "1500" + +VcVersion=VC9 + !else + VcVersion=VC7 -ProjectFile=vm.vcproj + !endif diff --git a/hotspot/make/windows/makefiles/sa.make b/hotspot/make/windows/makefiles/sa.make index c1956057188..1970f116b45 100644 --- a/hotspot/make/windows/makefiles/sa.make +++ b/hotspot/make/windows/makefiles/sa.make @@ -89,9 +89,11 @@ checkAndBuildSA:: $(SAWINDBG) SA_CFLAGS = /nologo $(MS_RUNTIME_OPTION) /W3 $(GX_OPTION) /Od /D "WIN32" /D "WIN64" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c !elseif "$(BUILDARCH)" == "amd64" SA_CFLAGS = /nologo $(MS_RUNTIME_OPTION) /W3 $(GX_OPTION) /Od /D "WIN32" /D "WIN64" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +!if "$(COMPILER_NAME)" == "VS2005" # On amd64, VS2005 compiler requires bufferoverflowU.lib on the link command line, # otherwise we get missing __security_check_cookie externals at link time. SA_LINK_FLAGS = bufferoverflowU.lib +!endif !else SA_CFLAGS = /nologo $(MS_RUNTIME_OPTION) /W3 /Gm $(GX_OPTION) /ZI /Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c !endif diff --git a/hotspot/make/windows/makefiles/sanity.make b/hotspot/make/windows/makefiles/sanity.make index 5b4293d27f8..dd5c7499f1d 100644 --- a/hotspot/make/windows/makefiles/sanity.make +++ b/hotspot/make/windows/makefiles/sanity.make @@ -27,9 +27,9 @@ all: checkCL checkLink checkCL: - @ if "$(MSC_VER)" NEQ "1310" if "$(MSC_VER)" NEQ "1399" if "$(MSC_VER)" NEQ "1400" \ + @ if "$(MSC_VER)" NEQ "1310" if "$(MSC_VER)" NEQ "1399" if "$(MSC_VER)" NEQ "1400" if "$(MSC_VER)" NEQ "1500" \ echo *** WARNING *** unrecognized cl.exe version $(MSC_VER) ($(RAW_MSC_VER)). Use FORCE_MSC_VER to override automatic detection. checkLink: - @ if "$(LINK_VER)" NEQ "710" if "$(LINK_VER)" NEQ "800" \ + @ if "$(LINK_VER)" NEQ "710" if "$(LINK_VER)" NEQ "800" if "$(LINK_VER)" NEQ "900" \ echo *** WARNING *** unrecognized link.exe version $(LINK_VER) ($(RAW_LINK_VER)). Use FORCE_LINK_VER to override automatic detection. diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp index 07879e32a8b..597a91ae340 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2615,6 +2615,420 @@ void MacroAssembler::cas_under_lock(Register top_ptr_reg, Register top_reg, Regi } } +RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, + Register tmp, + int offset) { + intptr_t value = *delayed_value_addr; + if (value != 0) + return RegisterOrConstant(value + offset); + + // load indirectly to solve generation ordering problem + Address a(tmp, (address) delayed_value_addr); + load_ptr_contents(a, tmp); + +#ifdef ASSERT + tst(tmp); + breakpoint_trap(zero, xcc); +#endif + + if (offset != 0) + add(tmp, offset, tmp); + + return RegisterOrConstant(tmp); +} + + +void MacroAssembler::regcon_inc_ptr( RegisterOrConstant& dest, RegisterOrConstant src, Register temp ) { + assert(dest.register_or_noreg() != G0, "lost side effect"); + if ((src.is_constant() && src.as_constant() == 0) || + (src.is_register() && src.as_register() == G0)) { + // do nothing + } else if (dest.is_register()) { + add(dest.as_register(), ensure_rs2(src, temp), dest.as_register()); + } else if (src.is_constant()) { + intptr_t res = dest.as_constant() + src.as_constant(); + dest = RegisterOrConstant(res); // side effect seen by caller + } else { + assert(temp != noreg, "cannot handle constant += register"); + add(src.as_register(), ensure_rs2(dest, temp), temp); + dest = RegisterOrConstant(temp); // side effect seen by caller + } +} + +void MacroAssembler::regcon_sll_ptr( RegisterOrConstant& dest, RegisterOrConstant src, Register temp ) { + assert(dest.register_or_noreg() != G0, "lost side effect"); + if (!is_simm13(src.constant_or_zero())) + src = (src.as_constant() & 0xFF); + if ((src.is_constant() && src.as_constant() == 0) || + (src.is_register() && src.as_register() == G0)) { + // do nothing + } else if (dest.is_register()) { + sll_ptr(dest.as_register(), src, dest.as_register()); + } else if (src.is_constant()) { + intptr_t res = dest.as_constant() << src.as_constant(); + dest = RegisterOrConstant(res); // side effect seen by caller + } else { + assert(temp != noreg, "cannot handle constant <<= register"); + set(dest.as_constant(), temp); + sll_ptr(temp, src, temp); + dest = RegisterOrConstant(temp); // side effect seen by caller + } +} + + +// Look up the method for a megamorphic invokeinterface call. +// The target method is determined by . +// The receiver klass is in recv_klass. +// On success, the result will be in method_result, and execution falls through. +// On failure, execution transfers to the given label. +void MacroAssembler::lookup_interface_method(Register recv_klass, + Register intf_klass, + RegisterOrConstant itable_index, + Register method_result, + Register scan_temp, + Register sethi_temp, + Label& L_no_such_interface) { + assert_different_registers(recv_klass, intf_klass, method_result, scan_temp); + assert(itable_index.is_constant() || itable_index.as_register() == method_result, + "caller must use same register for non-constant itable index as for method"); + + // Compute start of first itableOffsetEntry (which is at the end of the vtable) + int vtable_base = instanceKlass::vtable_start_offset() * wordSize; + int scan_step = itableOffsetEntry::size() * wordSize; + int vte_size = vtableEntry::size() * wordSize; + + lduw(recv_klass, instanceKlass::vtable_length_offset() * wordSize, scan_temp); + // %%% We should store the aligned, prescaled offset in the klassoop. + // Then the next several instructions would fold away. + + int round_to_unit = ((HeapWordsPerLong > 1) ? BytesPerLong : 0); + int itb_offset = vtable_base; + if (round_to_unit != 0) { + // hoist first instruction of round_to(scan_temp, BytesPerLong): + itb_offset += round_to_unit - wordSize; + } + int itb_scale = exact_log2(vtableEntry::size() * wordSize); + sll(scan_temp, itb_scale, scan_temp); + add(scan_temp, itb_offset, scan_temp); + if (round_to_unit != 0) { + // Round up to align_object_offset boundary + // see code for instanceKlass::start_of_itable! + // Was: round_to(scan_temp, BytesPerLong); + // Hoisted: add(scan_temp, BytesPerLong-1, scan_temp); + and3(scan_temp, -round_to_unit, scan_temp); + } + add(recv_klass, scan_temp, scan_temp); + + // Adjust recv_klass by scaled itable_index, so we can free itable_index. + RegisterOrConstant itable_offset = itable_index; + regcon_sll_ptr(itable_offset, exact_log2(itableMethodEntry::size() * wordSize)); + regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes()); + add(recv_klass, ensure_rs2(itable_offset, sethi_temp), recv_klass); + + // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) { + // if (scan->interface() == intf) { + // result = (klass + scan->offset() + itable_index); + // } + // } + Label search, found_method; + + for (int peel = 1; peel >= 0; peel--) { + // %%%% Could load both offset and interface in one ldx, if they were + // in the opposite order. This would save a load. + ld_ptr(scan_temp, itableOffsetEntry::interface_offset_in_bytes(), method_result); + + // Check that this entry is non-null. A null entry means that + // the receiver class doesn't implement the interface, and wasn't the + // same as when the caller was compiled. + bpr(Assembler::rc_z, false, Assembler::pn, method_result, L_no_such_interface); + delayed()->cmp(method_result, intf_klass); + + if (peel) { + brx(Assembler::equal, false, Assembler::pt, found_method); + } else { + brx(Assembler::notEqual, false, Assembler::pn, search); + // (invert the test to fall through to found_method...) + } + delayed()->add(scan_temp, scan_step, scan_temp); + + if (!peel) break; + + bind(search); + } + + bind(found_method); + + // Got a hit. + int ito_offset = itableOffsetEntry::offset_offset_in_bytes(); + // scan_temp[-scan_step] points to the vtable offset we need + ito_offset -= scan_step; + lduw(scan_temp, ito_offset, scan_temp); + ld_ptr(recv_klass, scan_temp, method_result); +} + + +void MacroAssembler::check_klass_subtype(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label& L_success) { + Label L_failure, L_pop_to_failure; + check_klass_subtype_fast_path(sub_klass, super_klass, + temp_reg, temp2_reg, + &L_success, &L_failure, NULL); + Register sub_2 = sub_klass; + Register sup_2 = super_klass; + if (!sub_2->is_global()) sub_2 = L0; + if (!sup_2->is_global()) sup_2 = L1; + + save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2); + check_klass_subtype_slow_path(sub_2, sup_2, + L2, L3, L4, L5, + NULL, &L_pop_to_failure); + + // on success: + restore(); + ba(false, L_success); + delayed()->nop(); + + // on failure: + bind(L_pop_to_failure); + restore(); + bind(L_failure); +} + + +void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterOrConstant super_check_offset, + Register instanceof_hack) { + int sc_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_super_cache_offset_in_bytes()); + int sco_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::super_check_offset_offset_in_bytes()); + + bool must_load_sco = (super_check_offset.constant_or_zero() == -1); + bool need_slow_path = (must_load_sco || + super_check_offset.constant_or_zero() == sco_offset); + + assert_different_registers(sub_klass, super_klass, temp_reg); + if (super_check_offset.is_register()) { + assert_different_registers(sub_klass, super_klass, + super_check_offset.as_register()); + } else if (must_load_sco) { + assert(temp2_reg != noreg, "supply either a temp or a register offset"); + } + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1 || instanceof_hack != noreg || + (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path), + "at most one NULL in the batch, usually"); + + // Support for the instanceof hack, which uses delay slots to + // set a destination register to zero or one. + bool do_bool_sets = (instanceof_hack != noreg); +#define BOOL_SET(bool_value) \ + if (do_bool_sets && bool_value >= 0) \ + set(bool_value, instanceof_hack) +#define DELAYED_BOOL_SET(bool_value) \ + if (do_bool_sets && bool_value >= 0) \ + delayed()->set(bool_value, instanceof_hack); \ + else delayed()->nop() + // Hacked ba(), which may only be used just before L_fallthrough. +#define FINAL_JUMP(label, bool_value) \ + if (&(label) == &L_fallthrough) { \ + BOOL_SET(bool_value); \ + } else { \ + ba((do_bool_sets && bool_value >= 0), label); \ + DELAYED_BOOL_SET(bool_value); \ + } + + // If the pointers are equal, we are done (e.g., String[] elements). + // This self-check enables sharing of secondary supertype arrays among + // non-primary types such as array-of-interface. Otherwise, each such + // type would need its own customized SSA. + // We move this check to the front of the fast path because many + // type checks are in fact trivially successful in this manner, + // so we get a nicely predicted branch right at the start of the check. + cmp(super_klass, sub_klass); + brx(Assembler::equal, do_bool_sets, Assembler::pn, *L_success); + DELAYED_BOOL_SET(1); + + // Check the supertype display: + if (must_load_sco) { + // The super check offset is always positive... + lduw(super_klass, sco_offset, temp2_reg); + super_check_offset = RegisterOrConstant(temp2_reg); + } + ld_ptr(sub_klass, super_check_offset, temp_reg); + cmp(super_klass, temp_reg); + + // This check has worked decisively for primary supers. + // Secondary supers are sought in the super_cache ('super_cache_addr'). + // (Secondary supers are interfaces and very deeply nested subtypes.) + // This works in the same check above because of a tricky aliasing + // between the super_cache and the primary super display elements. + // (The 'super_check_addr' can address either, as the case requires.) + // Note that the cache is updated below if it does not help us find + // what we need immediately. + // So if it was a primary super, we can just fail immediately. + // Otherwise, it's the slow path for us (no success at this point). + + if (super_check_offset.is_register()) { + brx(Assembler::equal, do_bool_sets, Assembler::pn, *L_success); + delayed(); if (do_bool_sets) BOOL_SET(1); + // if !do_bool_sets, sneak the next cmp into the delay slot: + cmp(super_check_offset.as_register(), sc_offset); + + if (L_failure == &L_fallthrough) { + brx(Assembler::equal, do_bool_sets, Assembler::pt, *L_slow_path); + delayed()->nop(); + BOOL_SET(0); // fallthrough on failure + } else { + brx(Assembler::notEqual, do_bool_sets, Assembler::pn, *L_failure); + DELAYED_BOOL_SET(0); + FINAL_JUMP(*L_slow_path, -1); // -1 => vanilla delay slot + } + } else if (super_check_offset.as_constant() == sc_offset) { + // Need a slow path; fast failure is impossible. + if (L_slow_path == &L_fallthrough) { + brx(Assembler::equal, do_bool_sets, Assembler::pt, *L_success); + DELAYED_BOOL_SET(1); + } else { + brx(Assembler::notEqual, false, Assembler::pn, *L_slow_path); + delayed()->nop(); + FINAL_JUMP(*L_success, 1); + } + } else { + // No slow path; it's a fast decision. + if (L_failure == &L_fallthrough) { + brx(Assembler::equal, do_bool_sets, Assembler::pt, *L_success); + DELAYED_BOOL_SET(1); + BOOL_SET(0); + } else { + brx(Assembler::notEqual, do_bool_sets, Assembler::pn, *L_failure); + DELAYED_BOOL_SET(0); + FINAL_JUMP(*L_success, 1); + } + } + + bind(L_fallthrough); + +#undef final_jump +#undef bool_set +#undef DELAYED_BOOL_SET +#undef final_jump +} + + +void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register count_temp, + Register scan_temp, + Register scratch_reg, + Register coop_reg, + Label* L_success, + Label* L_failure) { + assert_different_registers(sub_klass, super_klass, + count_temp, scan_temp, scratch_reg, coop_reg); + + Label L_fallthrough, L_loop; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1, "at most one NULL in the batch"); + + // a couple of useful fields in sub_klass: + int ss_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_supers_offset_in_bytes()); + int sc_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_super_cache_offset_in_bytes()); + + // Do a linear scan of the secondary super-klass chain. + // This code is rarely used, so simplicity is a virtue here. + +#ifndef PRODUCT + int* pst_counter = &SharedRuntime::_partial_subtype_ctr; + inc_counter((address) pst_counter, count_temp, scan_temp); +#endif + + // We will consult the secondary-super array. + ld_ptr(sub_klass, ss_offset, scan_temp); + + // Compress superclass if necessary. + Register search_key = super_klass; + bool decode_super_klass = false; + if (UseCompressedOops) { + if (coop_reg != noreg) { + encode_heap_oop_not_null(super_klass, coop_reg); + search_key = coop_reg; + } else { + encode_heap_oop_not_null(super_klass); + decode_super_klass = true; // scarce temps! + } + // The superclass is never null; it would be a basic system error if a null + // pointer were to sneak in here. Note that we have already loaded the + // Klass::super_check_offset from the super_klass in the fast path, + // so if there is a null in that register, we are already in the afterlife. + } + + // Load the array length. (Positive movl does right thing on LP64.) + lduw(scan_temp, arrayOopDesc::length_offset_in_bytes(), count_temp); + + // Check for empty secondary super list + tst(count_temp); + + // Top of search loop + bind(L_loop); + br(Assembler::equal, false, Assembler::pn, *L_failure); + delayed()->add(scan_temp, heapOopSize, scan_temp); + assert(heapOopSize != 0, "heapOopSize should be initialized"); + + // Skip the array header in all array accesses. + int elem_offset = arrayOopDesc::base_offset_in_bytes(T_OBJECT); + elem_offset -= heapOopSize; // the scan pointer was pre-incremented also + + // Load next super to check + if (UseCompressedOops) { + // Don't use load_heap_oop; we don't want to decode the element. + lduw( scan_temp, elem_offset, scratch_reg ); + } else { + ld_ptr( scan_temp, elem_offset, scratch_reg ); + } + + // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list + cmp(scratch_reg, search_key); + + // A miss means we are NOT a subtype and need to keep looping + brx(Assembler::notEqual, false, Assembler::pn, L_loop); + delayed()->deccc(count_temp); // decrement trip counter in delay slot + + // Falling out the bottom means we found a hit; we ARE a subtype + if (decode_super_klass) decode_heap_oop(super_klass); + + // Success. Cache the super we found and proceed in triumph. + st_ptr(super_klass, sub_klass, sc_offset); + + if (L_success != &L_fallthrough) { + ba(false, *L_success); + delayed()->nop(); + } + + bind(L_fallthrough); +} + + + + void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg, Register temp_reg, Label& done, Label* slow_case, @@ -3820,7 +4234,6 @@ void MacroAssembler::g1_write_barrier_pre(Register obj, Register index, int offs static jint num_ct_writes = 0; static jint num_ct_writes_filtered_in_hr = 0; static jint num_ct_writes_filtered_null = 0; -static jint num_ct_writes_filtered_pop = 0; static G1CollectedHeap* g1 = NULL; static Thread* count_ct_writes(void* filter_val, void* new_val) { @@ -3833,25 +4246,19 @@ static Thread* count_ct_writes(void* filter_val, void* new_val) { if (g1 == NULL) { g1 = G1CollectedHeap::heap(); } - if ((HeapWord*)new_val < g1->popular_object_boundary()) { - Atomic::inc(&num_ct_writes_filtered_pop); - } } if ((num_ct_writes % 1000000) == 0) { jint num_ct_writes_filtered = num_ct_writes_filtered_in_hr + - num_ct_writes_filtered_null + - num_ct_writes_filtered_pop; + num_ct_writes_filtered_null; tty->print_cr("%d potential CT writes: %5.2f%% filtered\n" - " (%5.2f%% intra-HR, %5.2f%% null, %5.2f%% popular).", + " (%5.2f%% intra-HR, %5.2f%% null).", num_ct_writes, 100.0*(float)num_ct_writes_filtered/(float)num_ct_writes, 100.0*(float)num_ct_writes_filtered_in_hr/ (float)num_ct_writes, 100.0*(float)num_ct_writes_filtered_null/ - (float)num_ct_writes, - 100.0*(float)num_ct_writes_filtered_pop/ (float)num_ct_writes); } return Thread::current(); @@ -4057,6 +4464,24 @@ void MacroAssembler::card_write_barrier_post(Register store_addr, Register new_v card_table_write(bs->byte_map_base, tmp, store_addr); } +// Loading values by size and signed-ness +void MacroAssembler::load_sized_value(Register s1, RegisterOrConstant s2, Register d, + int size_in_bytes, bool is_signed) { + switch (size_in_bytes ^ (is_signed ? -1 : 0)) { + case ~8: // fall through: + case 8: ld_long( s1, s2, d ); break; + case ~4: ldsw( s1, s2, d ); break; + case 4: lduw( s1, s2, d ); break; + case ~2: ldsh( s1, s2, d ); break; + case 2: lduh( s1, s2, d ); break; + case ~1: ldsb( s1, s2, d ); break; + case 1: ldub( s1, s2, d ); break; + default: ShouldNotReachHere(); + } +} + + + void MacroAssembler::load_klass(Register src_oop, Register klass) { // The number of bytes in this code is used by // MachCallDynamicJavaNode::ret_addr_offset() @@ -4146,7 +4571,13 @@ void MacroAssembler::store_heap_oop(Register d, const Address& a, int offset) { void MacroAssembler::encode_heap_oop(Register src, Register dst) { assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); verify_oop(src); + if (Universe::narrow_oop_base() == NULL) { + srlx(src, LogMinObjAlignmentInBytes, dst); + return; + } Label done; if (src == dst) { // optimize for frequent case src == dst @@ -4168,26 +4599,39 @@ void MacroAssembler::encode_heap_oop(Register src, Register dst) { void MacroAssembler::encode_heap_oop_not_null(Register r) { assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); verify_oop(r); - sub(r, G6_heapbase, r); + if (Universe::narrow_oop_base() != NULL) + sub(r, G6_heapbase, r); srlx(r, LogMinObjAlignmentInBytes, r); } void MacroAssembler::encode_heap_oop_not_null(Register src, Register dst) { assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); verify_oop(src); - sub(src, G6_heapbase, dst); - srlx(dst, LogMinObjAlignmentInBytes, dst); + if (Universe::narrow_oop_base() == NULL) { + srlx(src, LogMinObjAlignmentInBytes, dst); + } else { + sub(src, G6_heapbase, dst); + srlx(dst, LogMinObjAlignmentInBytes, dst); + } } // Same algorithm as oops.inline.hpp decode_heap_oop. void MacroAssembler::decode_heap_oop(Register src, Register dst) { assert (UseCompressedOops, "must be compressed"); - Label done; + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); sllx(src, LogMinObjAlignmentInBytes, dst); - bpr(rc_nz, true, Assembler::pt, dst, done); - delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken - bind(done); + if (Universe::narrow_oop_base() != NULL) { + Label done; + bpr(rc_nz, true, Assembler::pt, dst, done); + delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken + bind(done); + } verify_oop(dst); } @@ -4196,8 +4640,11 @@ void MacroAssembler::decode_heap_oop_not_null(Register r) { // pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); sllx(r, LogMinObjAlignmentInBytes, r); - add(r, G6_heapbase, r); + if (Universe::narrow_oop_base() != NULL) + add(r, G6_heapbase, r); } void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) { @@ -4205,14 +4652,17 @@ void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) { // pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); sllx(src, LogMinObjAlignmentInBytes, dst); - add(dst, G6_heapbase, dst); + if (Universe::narrow_oop_base() != NULL) + add(dst, G6_heapbase, dst); } void MacroAssembler::reinit_heapbase() { if (UseCompressedOops) { // call indirectly to solve generation ordering problem - Address base(G6_heapbase, (address)Universe::heap_base_addr()); + Address base(G6_heapbase, (address)Universe::narrow_oop_base_addr()); load_ptr_contents(base, G6_heapbase); } } diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp index 1d735ade174..5c756c4b6b1 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -384,6 +384,12 @@ class Address VALUE_OBJ_CLASS_SPEC { inline bool is_simm13(int offset = 0); // check disp+offset for overflow + Address plus_disp(int disp) const { // bump disp by a small amount + Address a = (*this); + a._disp += disp; + return a; + } + Address split_disp() const { // deal with disp overflow Address a = (*this); int hi_disp = _disp & ~0x3ff; @@ -1082,7 +1088,8 @@ public: inline void add( Register s1, Register s2, Register d ); inline void add( Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none); inline void add( Register s1, int simm13a, Register d, RelocationHolder const& rspec); - inline void add( const Address& a, Register d, int offset = 0); + inline void add( Register s1, RegisterOrConstant s2, Register d, int offset = 0); + inline void add( const Address& a, Register d, int offset = 0); void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } void addcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } @@ -1298,6 +1305,16 @@ public: inline void ld( const Address& a, Register d, int offset = 0 ); inline void ldd( const Address& a, Register d, int offset = 0 ); + inline void ldub( Register s1, RegisterOrConstant s2, Register d ); + inline void ldsb( Register s1, RegisterOrConstant s2, Register d ); + inline void lduh( Register s1, RegisterOrConstant s2, Register d ); + inline void ldsh( Register s1, RegisterOrConstant s2, Register d ); + inline void lduw( Register s1, RegisterOrConstant s2, Register d ); + inline void ldsw( Register s1, RegisterOrConstant s2, Register d ); + inline void ldx( Register s1, RegisterOrConstant s2, Register d ); + inline void ld( Register s1, RegisterOrConstant s2, Register d ); + inline void ldd( Register s1, RegisterOrConstant s2, Register d ); + // pp 177 void ldsba( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } @@ -1518,6 +1535,13 @@ public: inline void st( Register d, const Address& a, int offset = 0 ); inline void std( Register d, const Address& a, int offset = 0 ); + inline void stb( Register d, Register s1, RegisterOrConstant s2 ); + inline void sth( Register d, Register s1, RegisterOrConstant s2 ); + inline void stw( Register d, Register s1, RegisterOrConstant s2 ); + inline void stx( Register d, Register s1, RegisterOrConstant s2 ); + inline void std( Register d, Register s1, RegisterOrConstant s2 ); + inline void st( Register d, Register s1, RegisterOrConstant s2 ); + // pp 177 void stba( Register d, Register s1, Register s2, int ia ) { emit_long( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } @@ -1835,6 +1859,7 @@ class MacroAssembler: public Assembler { // Functions for isolating 64 bit shifts for LP64 inline void sll_ptr( Register s1, Register s2, Register d ); inline void sll_ptr( Register s1, int imm6a, Register d ); + inline void sll_ptr( Register s1, RegisterOrConstant s2, Register d ); inline void srl_ptr( Register s1, Register s2, Register d ); inline void srl_ptr( Register s1, int imm6a, Register d ); @@ -1940,20 +1965,47 @@ class MacroAssembler: public Assembler { // st_ptr will perform st for 32 bit VM's and stx for 64 bit VM's inline void ld_ptr( Register s1, Register s2, Register d ); inline void ld_ptr( Register s1, int simm13a, Register d); + inline void ld_ptr( Register s1, RegisterOrConstant s2, Register d ); inline void ld_ptr( const Address& a, Register d, int offset = 0 ); inline void st_ptr( Register d, Register s1, Register s2 ); inline void st_ptr( Register d, Register s1, int simm13a); + inline void st_ptr( Register d, Register s1, RegisterOrConstant s2 ); inline void st_ptr( Register d, const Address& a, int offset = 0 ); // ld_long will perform ld for 32 bit VM's and ldx for 64 bit VM's // st_long will perform st for 32 bit VM's and stx for 64 bit VM's inline void ld_long( Register s1, Register s2, Register d ); inline void ld_long( Register s1, int simm13a, Register d ); + inline void ld_long( Register s1, RegisterOrConstant s2, Register d ); inline void ld_long( const Address& a, Register d, int offset = 0 ); inline void st_long( Register d, Register s1, Register s2 ); inline void st_long( Register d, Register s1, int simm13a ); + inline void st_long( Register d, Register s1, RegisterOrConstant s2 ); inline void st_long( Register d, const Address& a, int offset = 0 ); + // Loading values by size and signed-ness + void load_sized_value(Register s1, RegisterOrConstant s2, Register d, + int size_in_bytes, bool is_signed); + + // Helpers for address formation. + // They update the dest in place, whether it is a register or constant. + // They emit no code at all if src is a constant zero. + // If dest is a constant and src is a register, the temp argument + // is required, and becomes the result. + // If dest is a register and src is a non-simm13 constant, + // the temp argument is required, and is used to materialize the constant. + void regcon_inc_ptr( RegisterOrConstant& dest, RegisterOrConstant src, + Register temp = noreg ); + void regcon_sll_ptr( RegisterOrConstant& dest, RegisterOrConstant src, + Register temp = noreg ); + RegisterOrConstant ensure_rs2(RegisterOrConstant rs2, Register sethi_temp) { + guarantee(sethi_temp != noreg, "constant offset overflow"); + if (is_simm13(rs2.constant_or_zero())) + return rs2; // register or short constant + set(rs2.as_constant(), sethi_temp); + return sethi_temp; + } + // -------------------------------------------------- public: @@ -2267,6 +2319,54 @@ class MacroAssembler: public Assembler { ); void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); + // interface method calling + void lookup_interface_method(Register recv_klass, + Register intf_klass, + RegisterOrConstant itable_index, + Register method_result, + Register temp_reg, Register temp2_reg, + Label& no_such_interface); + + // Test sub_klass against super_klass, with fast and slow paths. + + // The fast path produces a tri-state answer: yes / no / maybe-slow. + // One of the three labels can be NULL, meaning take the fall-through. + // If super_check_offset is -1, the value is loaded up from super_klass. + // No registers are killed, except temp_reg and temp2_reg. + // If super_check_offset is not -1, temp2_reg is not used and can be noreg. + void check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterOrConstant super_check_offset = RegisterOrConstant(-1), + Register instanceof_hack = noreg); + + // The rest of the type check; must be wired to a corresponding fast path. + // It does not repeat the fast path logic, so don't use it standalone. + // The temp_reg can be noreg, if no temps are available. + // It can also be sub_klass or super_klass, meaning it's OK to kill that one. + // Updates the sub's secondary super cache as necessary. + void check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Register temp3_reg, + Register temp4_reg, + Label* L_success, + Label* L_failure); + + // Simplified, combined version, good for typical uses. + // Falls through on failure. + void check_klass_subtype(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label& L_success); + + // Stack overflow checking // Note: this clobbers G3_scratch @@ -2281,6 +2381,8 @@ class MacroAssembler: public Assembler { // stack overflow + shadow pages. Clobbers tsp and scratch registers. void bang_stack_size(Register Rsize, Register Rtsp, Register Rscratch); + virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset); + void verify_tlab(); Condition negate_condition(Condition cond); diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp index 0efaa846b1d..d9053f7f6b7 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,6 +143,49 @@ inline void Assembler::ld( Register s1, Register s2, Register d) { lduw( s1, s2 inline void Assembler::ld( Register s1, int simm13a, Register d) { lduw( s1, simm13a, d); } #endif +inline void Assembler::ldub( Register s1, RegisterOrConstant s2, Register d) { + if (s2.is_register()) ldsb(s1, s2.as_register(), d); + else ldsb(s1, s2.as_constant(), d); +} +inline void Assembler::ldsb( Register s1, RegisterOrConstant s2, Register d) { + if (s2.is_register()) ldsb(s1, s2.as_register(), d); + else ldsb(s1, s2.as_constant(), d); +} +inline void Assembler::lduh( Register s1, RegisterOrConstant s2, Register d) { + if (s2.is_register()) ldsh(s1, s2.as_register(), d); + else ldsh(s1, s2.as_constant(), d); +} +inline void Assembler::ldsh( Register s1, RegisterOrConstant s2, Register d) { + if (s2.is_register()) ldsh(s1, s2.as_register(), d); + else ldsh(s1, s2.as_constant(), d); +} +inline void Assembler::lduw( Register s1, RegisterOrConstant s2, Register d) { + if (s2.is_register()) ldsw(s1, s2.as_register(), d); + else ldsw(s1, s2.as_constant(), d); +} +inline void Assembler::ldsw( Register s1, RegisterOrConstant s2, Register d) { + if (s2.is_register()) ldsw(s1, s2.as_register(), d); + else ldsw(s1, s2.as_constant(), d); +} +inline void Assembler::ldx( Register s1, RegisterOrConstant s2, Register d) { + if (s2.is_register()) ldx(s1, s2.as_register(), d); + else ldx(s1, s2.as_constant(), d); +} +inline void Assembler::ld( Register s1, RegisterOrConstant s2, Register d) { + if (s2.is_register()) ld(s1, s2.as_register(), d); + else ld(s1, s2.as_constant(), d); +} +inline void Assembler::ldd( Register s1, RegisterOrConstant s2, Register d) { + if (s2.is_register()) ldd(s1, s2.as_register(), d); + else ldd(s1, s2.as_constant(), d); +} + +// form effective addresses this way: +inline void Assembler::add( Register s1, RegisterOrConstant s2, Register d, int offset) { + if (s2.is_register()) add(s1, s2.as_register(), d); + else { add(s1, s2.as_constant() + offset, d); offset = 0; } + if (offset != 0) add(d, offset, d); +} inline void Assembler::ld( const Address& a, Register d, int offset ) { relocate(a.rspec(offset)); ld( a.base(), a.disp() + offset, d ); } inline void Assembler::ldsb( const Address& a, Register d, int offset ) { relocate(a.rspec(offset)); ldsb( a.base(), a.disp() + offset, d ); } @@ -200,6 +243,27 @@ inline void Assembler::std( Register d, Register s1, int simm13a) { v9_dep(); a inline void Assembler::st( Register d, Register s1, Register s2) { stw(d, s1, s2); } inline void Assembler::st( Register d, Register s1, int simm13a) { stw(d, s1, simm13a); } +inline void Assembler::stb( Register d, Register s1, RegisterOrConstant s2) { + if (s2.is_register()) stb(d, s1, s2.as_register()); + else stb(d, s1, s2.as_constant()); +} +inline void Assembler::sth( Register d, Register s1, RegisterOrConstant s2) { + if (s2.is_register()) sth(d, s1, s2.as_register()); + else sth(d, s1, s2.as_constant()); +} +inline void Assembler::stx( Register d, Register s1, RegisterOrConstant s2) { + if (s2.is_register()) stx(d, s1, s2.as_register()); + else stx(d, s1, s2.as_constant()); +} +inline void Assembler::std( Register d, Register s1, RegisterOrConstant s2) { + if (s2.is_register()) std(d, s1, s2.as_register()); + else std(d, s1, s2.as_constant()); +} +inline void Assembler::st( Register d, Register s1, RegisterOrConstant s2) { + if (s2.is_register()) st(d, s1, s2.as_register()); + else st(d, s1, s2.as_constant()); +} + inline void Assembler::stb( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); stb( d, a.base(), a.disp() + offset); } inline void Assembler::sth( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); sth( d, a.base(), a.disp() + offset); } inline void Assembler::stw( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); stw( d, a.base(), a.disp() + offset); } @@ -244,6 +308,14 @@ inline void MacroAssembler::ld_ptr( Register s1, int simm13a, Register d ) { #endif } +inline void MacroAssembler::ld_ptr( Register s1, RegisterOrConstant s2, Register d ) { +#ifdef _LP64 + Assembler::ldx( s1, s2, d); +#else + Assembler::ld( s1, s2, d); +#endif +} + inline void MacroAssembler::ld_ptr( const Address& a, Register d, int offset ) { #ifdef _LP64 Assembler::ldx( a, d, offset ); @@ -268,6 +340,14 @@ inline void MacroAssembler::st_ptr( Register d, Register s1, int simm13a ) { #endif } +inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterOrConstant s2 ) { +#ifdef _LP64 + Assembler::stx( d, s1, s2); +#else + Assembler::st( d, s1, s2); +#endif +} + inline void MacroAssembler::st_ptr( Register d, const Address& a, int offset) { #ifdef _LP64 Assembler::stx( d, a, offset); @@ -293,6 +373,14 @@ inline void MacroAssembler::ld_long( Register s1, int simm13a, Register d ) { #endif } +inline void MacroAssembler::ld_long( Register s1, RegisterOrConstant s2, Register d ) { +#ifdef _LP64 + Assembler::ldx(s1, s2, d); +#else + Assembler::ldd(s1, s2, d); +#endif +} + inline void MacroAssembler::ld_long( const Address& a, Register d, int offset ) { #ifdef _LP64 Assembler::ldx(a, d, offset ); @@ -317,6 +405,14 @@ inline void MacroAssembler::st_long( Register d, Register s1, int simm13a ) { #endif } +inline void MacroAssembler::st_long( Register d, Register s1, RegisterOrConstant s2 ) { +#ifdef _LP64 + Assembler::stx(d, s1, s2); +#else + Assembler::std(d, s1, s2); +#endif +} + inline void MacroAssembler::st_long( Register d, const Address& a, int offset ) { #ifdef _LP64 Assembler::stx(d, a, offset); @@ -359,6 +455,11 @@ inline void MacroAssembler::srl_ptr( Register s1, int imm6a, Register d ) { #endif } +inline void MacroAssembler::sll_ptr( Register s1, RegisterOrConstant s2, Register d ) { + if (s2.is_register()) sll_ptr(s1, s2.as_register(), d); + else sll_ptr(s1, s2.as_constant(), d); +} + // Use the right branch for the platform inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) { diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index dabea15a087..1e8c190c0bf 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2393,23 +2393,11 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { // get instance klass load(k_RInfo, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc), k_RInfo, T_OBJECT, NULL); - // get super_check_offset - load(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), Rtmp1, T_INT, NULL); - // See if we get an immediate positive hit - __ ld_ptr(klass_RInfo, Rtmp1, FrameMap::O7_oop_opr->as_register()); - __ cmp(k_RInfo, O7); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); - // check for immediate negative hit - __ cmp(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ br(Assembler::notEqual, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - // check for self - __ cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, &done, stub->entry(), NULL); - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); + // call out-of-line instance of __ check_klass_subtype_slow_path(...): + assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); __ delayed()->nop(); __ cmp(G3, 0); @@ -2493,58 +2481,30 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ delayed()->nop(); __ bind(done); } else { + bool need_slow_path = true; if (k->is_loaded()) { - load(klass_RInfo, k->super_check_offset(), Rtmp1, T_OBJECT, NULL); - - if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) { - // See if we get an immediate positive hit - __ cmp(Rtmp1, k_RInfo ); - __ br(Assembler::notEqual, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } else { - // See if we get an immediate positive hit - assert_different_registers(Rtmp1, k_RInfo, klass_RInfo); - __ cmp(Rtmp1, k_RInfo ); - __ br(Assembler::equal, false, Assembler::pn, done); - // check for self - __ delayed()->cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); - - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ cmp(G3, 0); - __ br(Assembler::equal, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } - __ bind(done); + if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()) + need_slow_path = false; + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, noreg, + (need_slow_path ? &done : NULL), + stub->entry(), NULL, + RegisterOrConstant(k->super_check_offset())); } else { - assert_different_registers(Rtmp1, klass_RInfo, k_RInfo); - - load(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), Rtmp1, T_INT, NULL); - // See if we get an immediate positive hit - load(klass_RInfo, Rtmp1, FrameMap::O7_oop_opr, T_OBJECT); - __ cmp(k_RInfo, O7); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); - // check for immediate negative hit - __ cmp(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ br(Assembler::notEqual, false, Assembler::pn, *stub->entry()); - // check for self - __ delayed()->cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); - - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, + &done, stub->entry(), NULL); + } + if (need_slow_path) { + // call out-of-line instance of __ check_klass_subtype_slow_path(...): + assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); __ delayed()->nop(); __ cmp(G3, 0); __ br(Assembler::equal, false, Assembler::pn, *stub->entry()); __ delayed()->nop(); - __ bind(done); } - + __ bind(done); } __ mov(obj, dst); } else if (code == lir_instanceof) { @@ -2582,58 +2542,32 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ set(0, dst); __ bind(done); } else { + bool need_slow_path = true; if (k->is_loaded()) { - assert_different_registers(Rtmp1, klass_RInfo, k_RInfo); - load(klass_RInfo, k->super_check_offset(), Rtmp1, T_OBJECT, NULL); - - if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) { - // See if we get an immediate positive hit - __ cmp(Rtmp1, k_RInfo ); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - __ set(0, dst); - __ bind(done); - } else { - // See if we get an immediate positive hit - assert_different_registers(Rtmp1, k_RInfo, klass_RInfo); - __ cmp(Rtmp1, k_RInfo ); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - // check for self - __ cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ mov(G3, dst); - __ bind(done); - } + if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()) + need_slow_path = false; + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, noreg, + (need_slow_path ? &done : NULL), + (need_slow_path ? &done : NULL), NULL, + RegisterOrConstant(k->super_check_offset()), + dst); } else { assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers"); - - load(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), dst, T_INT, NULL); - // See if we get an immediate positive hit - load(klass_RInfo, dst, FrameMap::O7_oop_opr, T_OBJECT); - __ cmp(k_RInfo, O7); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - // check for immediate negative hit - __ cmp(dst, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ br(Assembler::notEqual, true, Assembler::pt, done); - __ delayed()->set(0, dst); - // check for self - __ cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, dst, + &done, &done, NULL, + RegisterOrConstant(-1), + dst); + } + if (need_slow_path) { + // call out-of-line instance of __ check_klass_subtype_slow_path(...): + assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); __ delayed()->nop(); __ mov(G3, dst); - __ bind(done); } + __ bind(done); } } else { ShouldNotReachHere(); diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 489e84dd58c..6dfb8efbc7c 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -714,38 +714,19 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // sub : G3, argument, destroyed // super: G1, argument, not changed // raddr: O7, blown by call - Label loop, miss; + Label miss; __ save_frame(0); // Blow no registers! - __ ld_ptr( G3, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes(), L3 ); - __ lduw(L3,arrayOopDesc::length_offset_in_bytes(),L0); // length in l0 - __ add(L3,arrayOopDesc::base_offset_in_bytes(T_OBJECT),L1); // ptr into array - __ clr(L4); // Index - // Load a little early; will load 1 off the end of the array. - // Ok for now; revisit if we have other uses of this routine. - __ ld_ptr(L1,0,L2); // Will load a little early - - // The scan loop - __ bind(loop); - __ add(L1,wordSize,L1); // Bump by OOP size - __ cmp(L4,L0); - __ br(Assembler::equal,false,Assembler::pn,miss); - __ delayed()->inc(L4); // Bump index - __ subcc(L2,G1,L3); // Check for match; zero in L3 for a hit - __ brx( Assembler::notEqual, false, Assembler::pt, loop ); - __ delayed()->ld_ptr(L1,0,L2); // Will load a little early - - // Got a hit; report success; set cache - __ st_ptr( G1, G3, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); + __ check_klass_subtype_slow_path(G3, G1, L0, L1, L2, L4, NULL, &miss); __ mov(1, G3); - __ ret(); // Result in G5 is ok; flags set + __ ret(); // Result in G5 is 'true' __ delayed()->restore(); // free copy or add can go here __ bind(miss); __ mov(0, G3); - __ ret(); // Result in G5 is ok; flags set + __ ret(); // Result in G5 is 'false' __ delayed()->restore(); // free copy or add can go here } diff --git a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp index 9d1bd7ac26f..98b3230ec7b 100644 --- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp @@ -46,6 +46,7 @@ define_pd_global(uintx, TLABSize, 0); define_pd_global(uintx, NewSize, ScaleForWordSize((2048 * K) + (2 * (64 * K)))); define_pd_global(intx, SurvivorRatio, 8); define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC +define_pd_global(intx, InlineSmallCode, 1500); #ifdef _LP64 // Stack slots are 2X larger in LP64 than in the 32 bit VM. define_pd_global(intx, ThreadStackSize, 1024); diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index f134852e4d6..e843d3fad8b 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -866,65 +866,18 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Register Rtmp2, Register Rtmp3, Label &ok_is_subtype ) { - Label not_subtype, loop; + Label not_subtype; // Profile the not-null value's klass. profile_typecheck(Rsub_klass, Rtmp1); - // Load the super-klass's check offset into Rtmp1 - ld( Rsuper_klass, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), Rtmp1 ); - // Load from the sub-klass's super-class display list, or a 1-word cache of - // the secondary superclass list, or a failing value with a sentinel offset - // if the super-klass is an interface or exceptionally deep in the Java - // hierarchy and we have to scan the secondary superclass list the hard way. - ld_ptr( Rsub_klass, Rtmp1, Rtmp2 ); - // See if we get an immediate positive hit - cmp( Rtmp2, Rsuper_klass ); - brx( Assembler::equal, false, Assembler::pt, ok_is_subtype ); - // In the delay slot, check for immediate negative hit - delayed()->cmp( Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); - br( Assembler::notEqual, false, Assembler::pt, not_subtype ); - // In the delay slot, check for self - delayed()->cmp( Rsub_klass, Rsuper_klass ); - brx( Assembler::equal, false, Assembler::pt, ok_is_subtype ); + check_klass_subtype_fast_path(Rsub_klass, Rsuper_klass, + Rtmp1, Rtmp2, + &ok_is_subtype, ¬_subtype, NULL); - // Now do a linear scan of the secondary super-klass chain. - delayed()->ld_ptr( Rsub_klass, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes(), Rtmp2 ); - - // compress superclass - if (UseCompressedOops) encode_heap_oop(Rsuper_klass); - - // Rtmp2 holds the objArrayOop of secondary supers. - ld( Rtmp2, arrayOopDesc::length_offset_in_bytes(), Rtmp1 );// Load the array length - // Check for empty secondary super list - tst(Rtmp1); - - // Top of search loop - bind( loop ); - br( Assembler::equal, false, Assembler::pn, not_subtype ); - delayed()->nop(); - - // load next super to check - if (UseCompressedOops) { - lduw( Rtmp2, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rtmp3); - // Bump array pointer forward one oop - add( Rtmp2, 4, Rtmp2 ); - } else { - ld_ptr( Rtmp2, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rtmp3); - // Bump array pointer forward one oop - add( Rtmp2, wordSize, Rtmp2); - } - // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list - cmp( Rtmp3, Rsuper_klass ); - // A miss means we are NOT a subtype and need to keep looping - brx( Assembler::notEqual, false, Assembler::pt, loop ); - delayed()->deccc( Rtmp1 ); // dec trip counter in delay slot - // Falling out the bottom means we found a hit; we ARE a subtype - if (UseCompressedOops) decode_heap_oop(Rsuper_klass); - br( Assembler::always, false, Assembler::pt, ok_is_subtype ); - // Update the cache - delayed()->st_ptr( Rsuper_klass, Rsub_klass, - sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); + check_klass_subtype_slow_path(Rsub_klass, Rsuper_klass, + Rtmp1, Rtmp2, Rtmp3, /*hack:*/ noreg, + &ok_is_subtype, NULL); bind(not_subtype); profile_typecheck_failed(Rtmp1); @@ -2465,7 +2418,10 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { // InterpreterRuntime::post_method_entry(); // } // if (DTraceMethodProbes) { -// SharedRuntime::dtrace_method_entry(method, reciever); +// SharedRuntime::dtrace_method_entry(method, receiver); +// } +// if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { +// SharedRuntime::rc_trace_method_entry(method, receiver); // } void InterpreterMacroAssembler::notify_method_entry() { @@ -2497,6 +2453,13 @@ void InterpreterMacroAssembler::notify_method_entry() { CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), G2_thread, Lmethod); } + + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + call_VM_leaf(noreg, + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + G2_thread, Lmethod); + } } diff --git a/hotspot/src/cpu/sparc/vm/jni_sparc.h b/hotspot/src/cpu/sparc/vm/jni_sparc.h index 33a494b6066..8eaab8d9481 100644 --- a/hotspot/src/cpu/sparc/vm/jni_sparc.h +++ b/hotspot/src/cpu/sparc/vm/jni_sparc.h @@ -1,5 +1,5 @@ /* - * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp index 2527e35b3e9..81bdca4cd28 100644 --- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp @@ -243,7 +243,7 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { // Regenerate the instruction sequence that performs the 64 bit // sethi. This only does the sethi. The disp field (bottom 10 bits) - // must be handled seperately. + // must be handled separately. static void set_data64_sethi(address instaddr, intptr_t x); // combine the fields of a sethi/simm13 pair (simm13 = or, add, jmpl, ld/st) diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index 6fed65b3ddc..5804fbbfe12 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -2161,6 +2161,18 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ restore(); } + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + // create inner frame + __ save_frame(0); + __ mov(G2_thread, L7_thread_cache); + __ set_oop_constant(JNIHandles::make_local(method()), O1); + __ call_VM_leaf(L7_thread_cache, + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + G2_thread, O1); + __ restore(); + } + // We are in the jni frame unless saved_frame is true in which case // we are in one frame deeper (the "inner" frame). If we are in the // "inner" frames the args are in the Iregs and if the jni frame then diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index b4a94ac240a..c65cc5495e6 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -1,5 +1,5 @@ // -// Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -189,7 +189,7 @@ reg_def R_F31( SOC, SOC, Op_RegF, 31, F31->as_VMReg()); // double fp register numbers. FloatRegisterImpl in register_sparc.hpp // wants 0-63, so we have to convert every time we want to use fp regs // with the macroassembler, using reg_to_DoubleFloatRegister_object(). -// 255 is a flag meaning 'dont go here'. +// 255 is a flag meaning "don't go here". // I believe we can't handle callee-save doubles D32 and up until // the place in the sparc stack crawler that asserts on the 255 is // fixed up. @@ -462,7 +462,7 @@ extern bool can_branch_register( Node *bol, Node *cmp ); // Macros to extract hi & lo halves from a long pair. // G0 is not part of any long pair, so assert on that. -// Prevents accidently using G1 instead of G0. +// Prevents accidentally using G1 instead of G0. #define LONG_HI_REG(x) (x) #define LONG_LO_REG(x) (x) @@ -547,7 +547,11 @@ int MachCallDynamicJavaNode::ret_addr_offset() { int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes(); int klass_load_size; if (UseCompressedOops) { - klass_load_size = 3*BytesPerInstWord; // see MacroAssembler::load_klass() + assert(Universe::heap() != NULL, "java heap should be initialized"); + if (Universe::narrow_oop_base() == NULL) + klass_load_size = 2*BytesPerInstWord; // see MacroAssembler::load_klass() + else + klass_load_size = 3*BytesPerInstWord; } else { klass_load_size = 1*BytesPerInstWord; } @@ -1431,7 +1435,7 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, #ifndef _LP64 // In the LP64 build, all registers can be moved as aligned/adjacent - // pairs, so there's never any need to move the high bits seperately. + // pairs, so there's never any need to move the high bits separately. // The 32-bit builds have to deal with the 32-bit ABI which can force // all sorts of silly alignment problems. @@ -1601,9 +1605,11 @@ void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { st->print_cr("\nUEP:"); #ifdef _LP64 if (UseCompressedOops) { + assert(Universe::heap() != NULL, "java heap should be initialized"); st->print_cr("\tLDUW [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check - compressed klass"); st->print_cr("\tSLL R_G5,3,R_G5"); - st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5"); + if (Universe::narrow_oop_base() != NULL) + st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5"); } else { st->print_cr("\tLDX [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check"); } @@ -1624,7 +1630,7 @@ void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { Register temp_reg = G3; assert( G5_ic_reg != temp_reg, "conflicting registers" ); - // Load klass from reciever + // Load klass from receiver __ load_klass(O0, temp_reg); // Compare against expected klass __ cmp(temp_reg, G5_ic_reg); @@ -2502,7 +2508,11 @@ encode %{ __ load_klass(O0, G3_scratch); int klass_load_size; if (UseCompressedOops) { - klass_load_size = 3*BytesPerInstWord; + assert(Universe::heap() != NULL, "java heap should be initialized"); + if (Universe::narrow_oop_base() == NULL) + klass_load_size = 2*BytesPerInstWord; + else + klass_load_size = 3*BytesPerInstWord; } else { klass_load_size = 1*BytesPerInstWord; } @@ -2993,6 +3003,202 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{ __ bind(Ldone); %} +enc_class enc_String_Equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{ + Label Lword, Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone; + MacroAssembler _masm(&cbuf); + + Register str1_reg = reg_to_register_object($str1$$reg); + Register str2_reg = reg_to_register_object($str2$$reg); + Register tmp1_reg = reg_to_register_object($tmp1$$reg); + Register tmp2_reg = reg_to_register_object($tmp2$$reg); + Register result_reg = reg_to_register_object($result$$reg); + + // Get the first character position in both strings + // [8] char array, [12] offset, [16] count + int value_offset = java_lang_String:: value_offset_in_bytes(); + int offset_offset = java_lang_String::offset_offset_in_bytes(); + int count_offset = java_lang_String:: count_offset_in_bytes(); + + // load str1 (jchar*) base address into tmp1_reg + __ load_heap_oop(Address(str1_reg, 0, value_offset), tmp1_reg); + __ ld(Address(str1_reg, 0, offset_offset), result_reg); + __ add(tmp1_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp1_reg); + __ ld(Address(str1_reg, 0, count_offset), str1_reg); // hoisted + __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg); + __ load_heap_oop(Address(str2_reg, 0, value_offset), tmp2_reg); // hoisted + __ add(result_reg, tmp1_reg, tmp1_reg); + + // load str2 (jchar*) base address into tmp2_reg + // __ ld_ptr(Address(str2_reg, 0, value_offset), tmp2_reg); // hoisted + __ ld(Address(str2_reg, 0, offset_offset), result_reg); + __ add(tmp2_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp2_reg); + __ ld(Address(str2_reg, 0, count_offset), str2_reg); // hoisted + __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg); + __ cmp(str1_reg, str2_reg); // hoisted + __ add(result_reg, tmp2_reg, tmp2_reg); + + __ sll(str1_reg, exact_log2(sizeof(jchar)), str1_reg); + __ br(Assembler::notEqual, true, Assembler::pt, Ldone); + __ delayed()->mov(G0, result_reg); // not equal + + __ br_zero(Assembler::equal, true, Assembler::pn, str1_reg, Ldone); + __ delayed()->add(G0, 1, result_reg); //equals + + __ cmp(tmp1_reg, tmp2_reg); //same string ? + __ brx(Assembler::equal, true, Assembler::pn, Ldone); + __ delayed()->add(G0, 1, result_reg); + + //rename registers + Register limit_reg = str1_reg; + Register chr2_reg = str2_reg; + Register chr1_reg = result_reg; + // tmp{12} are the base pointers + + //check for alignment and position the pointers to the ends + __ or3(tmp1_reg, tmp2_reg, chr1_reg); + __ andcc(chr1_reg, 0x3, chr1_reg); // notZero means at least one not 4-byte aligned + __ br(Assembler::notZero, false, Assembler::pn, Lchar); + __ delayed()->nop(); + + __ bind(Lword); + __ and3(limit_reg, 0x2, O7); //remember the remainder (either 0 or 2) + __ andn(limit_reg, 0x3, limit_reg); + __ br_zero(Assembler::zero, false, Assembler::pn, limit_reg, Lpost_word); + __ delayed()->nop(); + + __ add(tmp1_reg, limit_reg, tmp1_reg); + __ add(tmp2_reg, limit_reg, tmp2_reg); + __ neg(limit_reg); + + __ lduw(tmp1_reg, limit_reg, chr1_reg); + __ bind(Lword_loop); + __ lduw(tmp2_reg, limit_reg, chr2_reg); + __ cmp(chr1_reg, chr2_reg); + __ br(Assembler::notEqual, true, Assembler::pt, Ldone); + __ delayed()->mov(G0, result_reg); + __ inccc(limit_reg, 2*sizeof(jchar)); + // annul LDUW if branch i s not taken to prevent access past end of string + __ br(Assembler::notZero, true, Assembler::pt, Lword_loop); //annul on taken + __ delayed()->lduw(tmp1_reg, limit_reg, chr1_reg); // hoisted + + __ bind(Lpost_word); + __ br_zero(Assembler::zero, true, Assembler::pt, O7, Ldone); + __ delayed()->add(G0, 1, result_reg); + + __ lduh(tmp1_reg, 0, chr1_reg); + __ lduh(tmp2_reg, 0, chr2_reg); + __ cmp (chr1_reg, chr2_reg); + __ br(Assembler::notEqual, true, Assembler::pt, Ldone); + __ delayed()->mov(G0, result_reg); + __ ba(false,Ldone); + __ delayed()->add(G0, 1, result_reg); + + __ bind(Lchar); + __ add(tmp1_reg, limit_reg, tmp1_reg); + __ add(tmp2_reg, limit_reg, tmp2_reg); + __ neg(limit_reg); //negate count + + __ lduh(tmp1_reg, limit_reg, chr1_reg); + __ bind(Lchar_loop); + __ lduh(tmp2_reg, limit_reg, chr2_reg); + __ cmp(chr1_reg, chr2_reg); + __ br(Assembler::notEqual, true, Assembler::pt, Ldone); + __ delayed()->mov(G0, result_reg); //not equal + __ inccc(limit_reg, sizeof(jchar)); + // annul LDUH if branch is not taken to prevent access past end of string + __ br(Assembler::notZero, true, Assembler::pt, Lchar_loop); //annul on taken + __ delayed()->lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted + + __ add(G0, 1, result_reg); //equal + + __ bind(Ldone); + %} + +enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{ + Label Lvector, Ldone, Lloop; + MacroAssembler _masm(&cbuf); + + Register ary1_reg = reg_to_register_object($ary1$$reg); + Register ary2_reg = reg_to_register_object($ary2$$reg); + Register tmp1_reg = reg_to_register_object($tmp1$$reg); + Register tmp2_reg = reg_to_register_object($tmp2$$reg); + Register result_reg = reg_to_register_object($result$$reg); + + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + + // return true if the same array + __ cmp(ary1_reg, ary2_reg); + __ br(Assembler::equal, true, Assembler::pn, Ldone); + __ delayed()->add(G0, 1, result_reg); // equal + + __ br_null(ary1_reg, true, Assembler::pn, Ldone); + __ delayed()->mov(G0, result_reg); // not equal + + __ br_null(ary2_reg, true, Assembler::pn, Ldone); + __ delayed()->mov(G0, result_reg); // not equal + + //load the lengths of arrays + __ ld(Address(ary1_reg, 0, length_offset), tmp1_reg); + __ ld(Address(ary2_reg, 0, length_offset), tmp2_reg); + + // return false if the two arrays are not equal length + __ cmp(tmp1_reg, tmp2_reg); + __ br(Assembler::notEqual, true, Assembler::pn, Ldone); + __ delayed()->mov(G0, result_reg); // not equal + + __ br_zero(Assembler::zero, true, Assembler::pn, tmp1_reg, Ldone); + __ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal + + // load array addresses + __ add(ary1_reg, base_offset, ary1_reg); + __ add(ary2_reg, base_offset, ary2_reg); + + // renaming registers + Register chr1_reg = tmp2_reg; // for characters in ary1 + Register chr2_reg = result_reg; // for characters in ary2 + Register limit_reg = tmp1_reg; // length + + // set byte count + __ sll(limit_reg, exact_log2(sizeof(jchar)), limit_reg); + __ andcc(limit_reg, 0x2, chr1_reg); //trailing character ? + __ br(Assembler::zero, false, Assembler::pt, Lvector); + __ delayed()->nop(); + + //compare the trailing char + __ sub(limit_reg, sizeof(jchar), limit_reg); + __ lduh(ary1_reg, limit_reg, chr1_reg); + __ lduh(ary2_reg, limit_reg, chr2_reg); + __ cmp(chr1_reg, chr2_reg); + __ br(Assembler::notEqual, true, Assembler::pt, Ldone); + __ delayed()->mov(G0, result_reg); // not equal + + // only one char ? + __ br_zero(Assembler::zero, true, Assembler::pn, limit_reg, Ldone); + __ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal + + __ bind(Lvector); + // Shift ary1_reg and ary2_reg to the end of the arrays, negate limit + __ add(ary1_reg, limit_reg, ary1_reg); + __ add(ary2_reg, limit_reg, ary2_reg); + __ neg(limit_reg, limit_reg); + + __ lduw(ary1_reg, limit_reg, chr1_reg); + __ bind(Lloop); + __ lduw(ary2_reg, limit_reg, chr2_reg); + __ cmp(chr1_reg, chr2_reg); + __ br(Assembler::notEqual, false, Assembler::pt, Ldone); + __ delayed()->mov(G0, result_reg); // not equal + __ inccc(limit_reg, 2*sizeof(jchar)); + // annul LDUW if branch is not taken to prevent access past end of string + __ br(Assembler::notZero, true, Assembler::pt, Lloop); //annul on taken + __ delayed()->lduw(ary1_reg, limit_reg, chr1_reg); // hoisted + + __ add(G0, 1, result_reg); // equals + + __ bind(Ldone); + %} + enc_class enc_rethrow() %{ cbuf.set_inst_mark(); Register temp_reg = G3; @@ -4149,7 +4355,7 @@ operand cmpOp_commute() %{ //----------OPERAND CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used to simplify -// instruction definitions by not requiring the AD writer to specify seperate +// instruction definitions by not requiring the AD writer to specify separate // instructions for every form of operand when the instruction accepts // multiple operand types with the same basic encoding and format. The classic // case of this is memory operands. @@ -5286,55 +5492,91 @@ instruct loadB(iRegI dst, memory mem) %{ ins_cost(MEMORY_REF_COST); size(4); - format %{ "LDSB $mem,$dst" %} + format %{ "LDSB $mem,$dst\t! byte" %} opcode(Assembler::ldsb_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} -// Load Byte (8bit UNsigned) into an int reg -instruct loadUB(iRegI dst, memory mem, immI_255 bytemask) %{ - match(Set dst (AndI (LoadB mem) bytemask)); +// Load Byte (8bit signed) into a Long Register +instruct loadB2L(iRegL dst, memory mem) %{ + match(Set dst (ConvI2L (LoadB mem))); ins_cost(MEMORY_REF_COST); size(4); - format %{ "LDUB $mem,$dst" %} + format %{ "LDSB $mem,$dst\t! byte -> long" %} + opcode(Assembler::ldsb_op3); + ins_encode(simple_form3_mem_reg( mem, dst ) ); + ins_pipe(iload_mask_mem); +%} + +// Load Unsigned Byte (8bit UNsigned) into an int reg +instruct loadUB(iRegI dst, memory mem) %{ + match(Set dst (LoadUB mem)); + ins_cost(MEMORY_REF_COST); + + size(4); + format %{ "LDUB $mem,$dst\t! ubyte" %} opcode(Assembler::ldub_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} -// Load Byte (8bit UNsigned) into a Long Register -instruct loadUBL(iRegL dst, memory mem, immL_FF bytemask) %{ - match(Set dst (AndL (ConvI2L (LoadB mem)) bytemask)); +// Load Unsigned Byte (8bit UNsigned) into a Long Register +instruct loadUB2L(iRegL dst, memory mem) %{ + match(Set dst (ConvI2L (LoadUB mem))); ins_cost(MEMORY_REF_COST); size(4); - format %{ "LDUB $mem,$dst" %} + format %{ "LDUB $mem,$dst\t! ubyte -> long" %} opcode(Assembler::ldub_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} -// Load Unsigned Short/Char (16bit UNsigned) into a Long Register -instruct loadUS2L(iRegL dst, memory mem, immL_FFFF bytemask) %{ - match(Set dst (AndL (ConvI2L (LoadUS mem)) bytemask)); +// Load Short (16bit signed) +instruct loadS(iRegI dst, memory mem) %{ + match(Set dst (LoadS mem)); ins_cost(MEMORY_REF_COST); size(4); - format %{ "LDUH $mem,$dst" %} - opcode(Assembler::lduh_op3); + format %{ "LDSH $mem,$dst\t! short" %} + opcode(Assembler::ldsh_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} -// Load Unsigned Short/Char (16bit unsigned) +// Load Short (16bit signed) into a Long Register +instruct loadS2L(iRegL dst, memory mem) %{ + match(Set dst (ConvI2L (LoadS mem))); + ins_cost(MEMORY_REF_COST); + + size(4); + format %{ "LDSH $mem,$dst\t! short -> long" %} + opcode(Assembler::ldsh_op3); + ins_encode(simple_form3_mem_reg( mem, dst ) ); + ins_pipe(iload_mask_mem); +%} + +// Load Unsigned Short/Char (16bit UNsigned) instruct loadUS(iRegI dst, memory mem) %{ match(Set dst (LoadUS mem)); ins_cost(MEMORY_REF_COST); size(4); - format %{ "LDUH $mem,$dst" %} + format %{ "LDUH $mem,$dst\t! ushort/char" %} + opcode(Assembler::lduh_op3); + ins_encode(simple_form3_mem_reg( mem, dst ) ); + ins_pipe(iload_mask_mem); +%} + +// Load Unsigned Short/Char (16bit UNsigned) into a Long Register +instruct loadUS2L(iRegL dst, memory mem) %{ + match(Set dst (ConvI2L (LoadUS mem))); + ins_cost(MEMORY_REF_COST); + + size(4); + format %{ "LDUH $mem,$dst\t! ushort/char -> long" %} opcode(Assembler::lduh_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); @@ -5344,9 +5586,33 @@ instruct loadUS(iRegI dst, memory mem) %{ instruct loadI(iRegI dst, memory mem) %{ match(Set dst (LoadI mem)); ins_cost(MEMORY_REF_COST); - size(4); - format %{ "LDUW $mem,$dst" %} + size(4); + format %{ "LDUW $mem,$dst\t! int" %} + opcode(Assembler::lduw_op3); + ins_encode(simple_form3_mem_reg( mem, dst ) ); + ins_pipe(iload_mem); +%} + +// Load Integer into a Long Register +instruct loadI2L(iRegL dst, memory mem) %{ + match(Set dst (ConvI2L (LoadI mem))); + ins_cost(MEMORY_REF_COST); + + size(4); + format %{ "LDSW $mem,$dst\t! int -> long" %} + opcode(Assembler::ldsw_op3); + ins_encode(simple_form3_mem_reg( mem, dst ) ); + ins_pipe(iload_mem); +%} + +// Load Unsigned Integer into a Long Register +instruct loadUI2L(iRegL dst, memory mem) %{ + match(Set dst (LoadUI2L mem)); + ins_cost(MEMORY_REF_COST); + + size(4); + format %{ "LDUW $mem,$dst\t! uint -> long" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mem); @@ -5356,6 +5622,7 @@ instruct loadI(iRegI dst, memory mem) %{ instruct loadL(iRegL dst, memory mem ) %{ match(Set dst (LoadL mem)); ins_cost(MEMORY_REF_COST); + size(4); format %{ "LDX $mem,$dst\t! long" %} opcode(Assembler::ldx_op3); @@ -5471,13 +5738,11 @@ instruct loadN(iRegN dst, memory mem) %{ format %{ "LDUW $mem,$dst\t! compressed ptr" %} ins_encode %{ - Register base = as_Register($mem$$base); - Register index = as_Register($mem$$index); - Register dst = $dst$$Register; + Register index = $mem$$index$$Register; if (index != G0) { - __ lduw(base, index, dst); + __ lduw($mem$$base$$Register, index, $dst$$Register); } else { - __ lduw(base, $mem$$disp, dst); + __ lduw($mem$$base$$Register, $mem$$disp, $dst$$Register); } %} ins_pipe(iload_mem); @@ -5521,18 +5786,6 @@ instruct loadNKlass(iRegN dst, memory mem) %{ ins_pipe(iload_mem); %} -// Load Short (16bit signed) -instruct loadS(iRegI dst, memory mem) %{ - match(Set dst (LoadS mem)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDSH $mem,$dst" %} - opcode(Assembler::ldsh_op3); - ins_encode(simple_form3_mem_reg( mem, dst ) ); - ins_pipe(iload_mask_mem); -%} - // Load Double instruct loadD(regD dst, memory mem) %{ match(Set dst (LoadD mem)); @@ -6847,7 +7100,7 @@ instruct mul_hi(iRegIsafe dst, iRegIsafe src1, iRegIsafe src2 ) %{ ins_pipe(sdiv_reg_reg); %} -// Magic constant, reciprical of 10 +// Magic constant, reciprocal of 10 instruct loadConI_x66666667(iRegIsafe dst) %{ effect( DEF dst ); @@ -6857,7 +7110,7 @@ instruct loadConI_x66666667(iRegIsafe dst) %{ ins_pipe(ialu_hi_lo_reg); %} -// Register Shift Right Arithmatic Long by 32-63 +// Register Shift Right Arithmetic Long by 32-63 instruct sra_31( iRegI dst, iRegI src ) %{ effect( DEF dst, USE src ); format %{ "SRA $src,31,$dst\t! Used in div-by-10" %} @@ -8958,6 +9211,52 @@ instruct string_compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, note ins_pipe(long_memory_op); %} +instruct string_equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result, + o7RegI tmp3, flagsReg ccr) %{ + match(Set result (StrEquals str1 str2)); + effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL ccr, KILL tmp3); + ins_cost(300); + format %{ "String Equals $str1,$str2 -> $result" %} + ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, result) ); + ins_pipe(long_memory_op); +%} + +instruct array_equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result, + flagsReg ccr) %{ + match(Set result (AryEq ary1 ary2)); + effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL ccr); + ins_cost(300); + format %{ "Array Equals $ary1,$ary2 -> $result" %} + ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result)); + ins_pipe(long_memory_op); +%} + +//---------- Population Count Instructions ------------------------------------- + +instruct popCountI(iRegI dst, iRegI src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI src)); + + format %{ "POPC $src, $dst" %} + ins_encode %{ + __ popc($src$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL(iRegI dst, iRegL src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL src)); + + format %{ "POPC $src, $dst" %} + ins_encode %{ + __ popc($src$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + + // ============================================================================ //------------Bytes reverse-------------------------------------------------- @@ -9048,7 +9347,7 @@ instruct storeL_reversed(memory dst, iRegL src) %{ // These must follow all instruction definitions as they use the names // defined in the instructions definitions. // -// peepmatch ( root_instr_name [preceeding_instruction]* ); +// peepmatch ( root_instr_name [preceding_instruction]* ); // // peepconstraint %{ // (instruction_number.operand_name relational_op instruction_number.operand_name diff --git a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp index 9b4981dff7a..62c201605e5 100644 --- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp @@ -817,21 +817,6 @@ class StubGenerator: public StubCodeGenerator { Label _atomic_add_stub; // called from other stubs - // Support for void OrderAccess::fence(). - // - address generate_fence() { - StubCodeMark mark(this, "StubRoutines", "fence"); - address start = __ pc(); - - __ membar(Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore | - Assembler::StoreLoad | Assembler::StoreStore)); - __ retl(false); - __ delayed()->nop(); - - return start; - } - - //------------------------------------------------------------------------------------------------------------------------ // The following routine generates a subroutine to throw an asynchronous // UnknownError when an unsafe access gets a fault that could not be @@ -900,19 +885,7 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", "partial_subtype_check"); address start = __ pc(); - Label loop, miss; - - // Compare super with sub directly, since super is not in its own SSA. - // The compiler used to emit this test, but we fold it in here, - // to increase overall code density, with no real loss of speed. - { Label L; - __ cmp(O1, O2); - __ brx(Assembler::notEqual, false, Assembler::pt, L); - __ delayed()->nop(); - __ retl(); - __ delayed()->addcc(G0,0,O0); // set Z flags, zero result - __ bind(L); - } + Label miss; #if defined(COMPILER2) && !defined(_LP64) // Do not use a 'save' because it blows the 64-bit O registers. @@ -936,56 +909,12 @@ class StubGenerator: public StubCodeGenerator { Register L2_super = L2; Register L3_index = L3; -#ifdef _LP64 - Register L4_ooptmp = L4; + __ check_klass_subtype_slow_path(Rsub, Rsuper, + L0, L1, L2, L3, + NULL, &miss); - if (UseCompressedOops) { - // this must be under UseCompressedOops check, as we rely upon fact - // that L4 not clobbered in C2 on 32-bit platforms, where we do explicit save - // on stack, see several lines above - __ encode_heap_oop(Rsuper, L4_ooptmp); - } -#endif - - inc_counter_np(SharedRuntime::_partial_subtype_ctr, L0, L1); - - __ ld_ptr( Rsub, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes(), L3 ); - __ lduw(L3,arrayOopDesc::length_offset_in_bytes(),L0_ary_len); - __ add(L3,arrayOopDesc::base_offset_in_bytes(T_OBJECT),L1_ary_ptr); - __ clr(L3_index); // zero index - // Load a little early; will load 1 off the end of the array. - // Ok for now; revisit if we have other uses of this routine. - if (UseCompressedOops) { - __ lduw(L1_ary_ptr,0,L2_super);// Will load a little early - } else { - __ ld_ptr(L1_ary_ptr,0,L2_super);// Will load a little early - } - - assert(heapOopSize != 0, "heapOopSize should be initialized"); - // The scan loop - __ BIND(loop); - __ add(L1_ary_ptr, heapOopSize, L1_ary_ptr); // Bump by OOP size - __ cmp(L3_index,L0_ary_len); - __ br(Assembler::equal,false,Assembler::pn,miss); - __ delayed()->inc(L3_index); // Bump index - - if (UseCompressedOops) { -#ifdef _LP64 - __ subcc(L2_super,L4_ooptmp,Rret); // Check for match; zero in Rret for a hit - __ br( Assembler::notEqual, false, Assembler::pt, loop ); - __ delayed()->lduw(L1_ary_ptr,0,L2_super);// Will load a little early -#else - ShouldNotReachHere(); -#endif - } else { - __ subcc(L2_super,Rsuper,Rret); // Check for match; zero in Rret for a hit - __ brx( Assembler::notEqual, false, Assembler::pt, loop ); - __ delayed()->ld_ptr(L1_ary_ptr,0,L2_super);// Will load a little early - } - - // Got a hit; report success; set cache. Cache load doesn't - // happen here; for speed it is directly emitted by the compiler. - __ st_ptr( Rsuper, Rsub, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); + // Match falls through here. + __ addcc(G0,0,Rret); // set Z flags, Z result #if defined(COMPILER2) && !defined(_LP64) __ ld_ptr(SP,(frame::register_save_words+0)*wordSize,L0); @@ -999,7 +928,6 @@ class StubGenerator: public StubCodeGenerator { __ delayed()->restore(); #endif - // Hit or miss falls through here __ BIND(miss); __ addcc(G0,1,Rret); // set NZ flags, NZ result @@ -2330,51 +2258,31 @@ class StubGenerator: public StubCodeGenerator { Register super_check_offset, Register super_klass, Register temp, - Label& L_success, - Register deccc_hack = noreg) { + Label& L_success) { assert_different_registers(sub_klass, super_check_offset, super_klass, temp); BLOCK_COMMENT("type_check:"); - Label L_miss; + Label L_miss, L_pop_to_miss; assert_clean_int(super_check_offset, temp); - // maybe decrement caller's trip count: -#define DELAY_SLOT delayed(); \ - { if (deccc_hack == noreg) __ nop(); else __ deccc(deccc_hack); } - - // if the pointers are equal, we are done (e.g., String[] elements) - __ cmp(sub_klass, super_klass); - __ brx(Assembler::equal, true, Assembler::pt, L_success); - __ DELAY_SLOT; - - // check the supertype display: - __ ld_ptr(sub_klass, super_check_offset, temp); // query the super type - __ cmp(super_klass, temp); // test the super type - __ brx(Assembler::equal, true, Assembler::pt, L_success); - __ DELAY_SLOT; - - int sc_offset = (klassOopDesc::header_size() * HeapWordSize + - Klass::secondary_super_cache_offset_in_bytes()); - __ cmp(super_klass, sc_offset); - __ brx(Assembler::notEqual, true, Assembler::pt, L_miss); - __ delayed()->nop(); + __ check_klass_subtype_fast_path(sub_klass, super_klass, temp, noreg, + &L_success, &L_miss, NULL, + super_check_offset); + BLOCK_COMMENT("type_check_slow_path:"); __ save_frame(0); - __ mov(sub_klass->after_save(), O1); - // mov(super_klass->after_save(), O2); //fill delay slot - assert(StubRoutines::Sparc::_partial_subtype_check != NULL, "order of generation"); - __ call(StubRoutines::Sparc::_partial_subtype_check); - __ delayed()->mov(super_klass->after_save(), O2); + __ check_klass_subtype_slow_path(sub_klass->after_save(), + super_klass->after_save(), + L0, L1, L2, L4, + NULL, &L_pop_to_miss); + __ ba(false, L_success); + __ delayed()->restore(); + + __ bind(L_pop_to_miss); __ restore(); - // Upon return, the condition codes are already set. - __ brx(Assembler::equal, true, Assembler::pt, L_success); - __ DELAY_SLOT; - -#undef DELAY_SLOT - // Fall through on failure! __ BIND(L_miss); } @@ -2411,7 +2319,7 @@ class StubGenerator: public StubCodeGenerator { gen_write_ref_array_pre_barrier(O1, O2); #ifdef ASSERT - // We sometimes save a frame (see partial_subtype_check below). + // We sometimes save a frame (see generate_type_check below). // If this will cause trouble, let's fail now instead of later. __ save_frame(0); __ restore(); @@ -2455,41 +2363,39 @@ class StubGenerator: public StubCodeGenerator { // G3, G4, G5 --- current oop, oop.klass, oop.klass.super __ align(16); - __ bind(store_element); - // deccc(G1_remain); // decrement the count (hoisted) + __ BIND(store_element); + __ deccc(G1_remain); // decrement the count __ store_heap_oop(G3_oop, O1_to, O5_offset); // store the oop __ inc(O5_offset, heapOopSize); // step to next offset __ brx(Assembler::zero, true, Assembler::pt, do_card_marks); __ delayed()->set(0, O0); // return -1 on success // ======== loop entry is here ======== - __ bind(load_element); + __ BIND(load_element); __ load_heap_oop(O0_from, O5_offset, G3_oop); // load the oop __ br_null(G3_oop, true, Assembler::pt, store_element); - __ delayed()->deccc(G1_remain); // decrement the count + __ delayed()->nop(); __ load_klass(G3_oop, G4_klass); // query the object klass generate_type_check(G4_klass, O3_ckoff, O4_ckval, G5_super, // branch to this on success: - store_element, - // decrement this on success: - G1_remain); + store_element); // ======== end loop ======== // It was a real error; we must depend on the caller to finish the job. // Register G1 has number of *remaining* oops, O2 number of *total* oops. // Emit GC store barriers for the oops we have copied (O2 minus G1), // and report their number to the caller. - __ bind(fail); + __ BIND(fail); __ subcc(O2_count, G1_remain, O2_count); __ brx(Assembler::zero, false, Assembler::pt, done); __ delayed()->not1(O2_count, O0); // report (-1^K) to caller - __ bind(do_card_marks); + __ BIND(do_card_marks); gen_write_ref_array_post_barrier(O1_to, O2_count, O3); // store check on O1[0..O2] - __ bind(done); + __ BIND(done); inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, O3, O4); __ retl(); __ delayed()->nop(); // return value in 00 @@ -2940,16 +2846,16 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_atomic_cmpxchg_ptr_entry = StubRoutines::_atomic_cmpxchg_entry; StubRoutines::_atomic_cmpxchg_long_entry = generate_atomic_cmpxchg_long(); StubRoutines::_atomic_add_ptr_entry = StubRoutines::_atomic_add_entry; - StubRoutines::_fence_entry = generate_fence(); #endif // COMPILER2 !=> _LP64 - - StubRoutines::Sparc::_partial_subtype_check = generate_partial_subtype_check(); } void generate_all() { // Generates all stubs and initializes the entry points + // Generate partial_subtype_check first here since its code depends on + // UseZeroBaseCompressedOops which is defined after heap initialization. + StubRoutines::Sparc::_partial_subtype_check = generate_partial_subtype_check(); // These entry points require SharedInfo::stack0 to be set up in non-core builds StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index 6ba85859c2b..a4c1fa89258 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -1545,7 +1545,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Handle all the JSR stuff here, then exit. // It's much shorter and cleaner than intermingling with the - // non-JSR normal-branch stuff occuring below. + // non-JSR normal-branch stuff occurring below. if( is_jsr ) { // compute return address as bci in Otos_i __ ld_ptr(Address(Lmethod, 0, in_bytes(methodOopDesc::const_offset())), G3_scratch); @@ -3079,7 +3079,7 @@ void TemplateTable::invokeinterface(int byte_no) { Label ok; // Check that entry is non-null. Null entries are probably a bytecode - // problem. If the interface isn't implemented by the reciever class, + // problem. If the interface isn't implemented by the receiver class, // the VM should throw IncompatibleClassChangeError. linkResolver checks // this too but that's only if the entry isn't already resolved, so we // need to check again. diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index a870c7dc15b..17666c0a7fc 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ void VM_Version::initialize() { if (is_niagara1()) { // Indirect branch is the same cost as direct if (FLAG_IS_DEFAULT(UseInlineCaches)) { - UseInlineCaches = false; + FLAG_SET_DEFAULT(UseInlineCaches, false); } #ifdef _LP64 // Single issue niagara1 is slower for CompressedOops @@ -72,33 +72,50 @@ void VM_Version::initialize() { FLAG_SET_ERGO(bool, UseCompressedOops, false); } } + // 32-bit oops don't make sense for the 64-bit VM on sparc + // since the 32-bit VM has the same registers and smaller objects. + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); #endif // _LP64 #ifdef COMPILER2 // Indirect branch is the same cost as direct if (FLAG_IS_DEFAULT(UseJumpTables)) { - UseJumpTables = true; + FLAG_SET_DEFAULT(UseJumpTables, true); } // Single-issue, so entry and loop tops are // aligned on a single instruction boundary if (FLAG_IS_DEFAULT(InteriorEntryAlignment)) { - InteriorEntryAlignment = 4; + FLAG_SET_DEFAULT(InteriorEntryAlignment, 4); } if (FLAG_IS_DEFAULT(OptoLoopAlignment)) { - OptoLoopAlignment = 4; + FLAG_SET_DEFAULT(OptoLoopAlignment, 4); + } + if (is_niagara1_plus() && FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { + // Use smaller prefetch distance on N2 + FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256); } #endif } + // Use hardware population count instruction if available. + if (has_hardware_popc()) { + if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { + FLAG_SET_DEFAULT(UsePopCountInstruction, true); + } + } + char buf[512]; - jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s", (has_v8() ? ", has_v8" : ""), (has_v9() ? ", has_v9" : ""), + (has_hardware_popc() ? ", popc" : ""), (has_vis1() ? ", has_vis1" : ""), (has_vis2() ? ", has_vis2" : ""), (is_ultra3() ? ", is_ultra3" : ""), (is_sun4v() ? ", is_sun4v" : ""), (is_niagara1() ? ", is_niagara1" : ""), - (!has_hardware_int_muldiv() ? ", no-muldiv" : ""), + (is_niagara1_plus() ? ", is_niagara1_plus" : ""), + (!has_hardware_mul32() ? ", no-mul32" : ""), + (!has_hardware_div32() ? ", no-div32" : ""), (!has_hardware_fsmuld() ? ", no-fsmuld" : "")); // buf is started with ", " or is empty diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp index 050e7e68fcc..e057c608ce8 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,34 +25,38 @@ class VM_Version: public Abstract_VM_Version { protected: enum Feature_Flag { - v8_instructions = 0, - hardware_int_muldiv = 1, - hardware_fsmuld = 2, - v9_instructions = 3, - vis1_instructions = 4, - vis2_instructions = 5, - sun4v_instructions = 6 + v8_instructions = 0, + hardware_mul32 = 1, + hardware_div32 = 2, + hardware_fsmuld = 3, + hardware_popc = 4, + v9_instructions = 5, + vis1_instructions = 6, + vis2_instructions = 7, + sun4v_instructions = 8 }; enum Feature_Flag_Set { - unknown_m = 0, - all_features_m = -1, + unknown_m = 0, + all_features_m = -1, - v8_instructions_m = 1 << v8_instructions, - hardware_int_muldiv_m = 1 << hardware_int_muldiv, - hardware_fsmuld_m = 1 << hardware_fsmuld, - v9_instructions_m = 1 << v9_instructions, - vis1_instructions_m = 1 << vis1_instructions, - vis2_instructions_m = 1 << vis2_instructions, - sun4v_m = 1 << sun4v_instructions, + v8_instructions_m = 1 << v8_instructions, + hardware_mul32_m = 1 << hardware_mul32, + hardware_div32_m = 1 << hardware_div32, + hardware_fsmuld_m = 1 << hardware_fsmuld, + hardware_popc_m = 1 << hardware_popc, + v9_instructions_m = 1 << v9_instructions, + vis1_instructions_m = 1 << vis1_instructions, + vis2_instructions_m = 1 << vis2_instructions, + sun4v_m = 1 << sun4v_instructions, - generic_v8_m = v8_instructions_m | hardware_int_muldiv_m | hardware_fsmuld_m, - generic_v9_m = generic_v8_m | v9_instructions_m | vis1_instructions_m, - ultra3_m = generic_v9_m | vis2_instructions_m, + generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m, + generic_v9_m = generic_v8_m | v9_instructions_m, + ultra3_m = generic_v9_m | vis1_instructions_m | vis2_instructions_m, // Temporary until we have something more accurate - niagara1_unique_m = sun4v_m, - niagara1_m = generic_v9_m | niagara1_unique_m + niagara1_unique_m = sun4v_m, + niagara1_m = generic_v9_m | niagara1_unique_m }; static int _features; @@ -62,7 +66,7 @@ protected: static int determine_features(); static int platform_features(int features); - static bool is_niagara1(int features) { return (features & niagara1_m) == niagara1_m; } + static bool is_niagara1(int features) { return (features & sun4v_m) != 0; } static int maximum_niagara1_processor_count() { return 32; } // Returns true if the platform is in the niagara line and @@ -76,8 +80,10 @@ public: // Instruction support static bool has_v8() { return (_features & v8_instructions_m) != 0; } static bool has_v9() { return (_features & v9_instructions_m) != 0; } - static bool has_hardware_int_muldiv() { return (_features & hardware_int_muldiv_m) != 0; } + static bool has_hardware_mul32() { return (_features & hardware_mul32_m) != 0; } + static bool has_hardware_div32() { return (_features & hardware_div32_m) != 0; } static bool has_hardware_fsmuld() { return (_features & hardware_fsmuld_m) != 0; } + static bool has_hardware_popc() { return (_features & hardware_popc_m) != 0; } static bool has_vis1() { return (_features & vis1_instructions_m) != 0; } static bool has_vis2() { return (_features & vis2_instructions_m) != 0; } diff --git a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp index af2536b7c48..ce2c8532d08 100644 --- a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp @@ -106,6 +106,15 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { __ delayed()->nop(); masm->flush(); + + if (PrintMiscellaneous && (WizardMode || Verbose)) { + tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d", + vtable_index, s->entry_point(), + (int)(s->code_end() - s->entry_point()), + (int)(s->code_end() - __ pc())); + } + guarantee(__ pc() <= s->code_end(), "overflowed buffer"); + s->set_exception_points(npe_addr, ame_addr); return s; } @@ -113,9 +122,9 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { // NOTE: %%%% if any change is made to this stub make sure that the function // pd_code_size_limit is changed to ensure the correct size for VtableStub -VtableStub* VtableStubs::create_itable_stub(int vtable_index) { +VtableStub* VtableStubs::create_itable_stub(int itable_index) { const int sparc_code_length = VtableStub::pd_code_size_limit(false); - VtableStub* s = new(sparc_code_length) VtableStub(false, vtable_index); + VtableStub* s = new(sparc_code_length) VtableStub(false, itable_index); ResourceMark rm; CodeBuffer cb(s->entry_point(), sparc_code_length); MacroAssembler* masm = new MacroAssembler(&cb); @@ -139,7 +148,6 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { // are passed in the %o registers. Instead, longs are passed in G1 and G4 // and so those registers are not available here. __ save(SP,-frame::register_save_words*wordSize,SP); - Register I0_receiver = I0; // Location of receiver after save #ifndef PRODUCT if (CountCompiledCalls) { @@ -151,63 +159,31 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { } #endif /* PRODUCT */ - // load start of itable entries into L0 register - const int base = instanceKlass::vtable_start_offset() * wordSize; - __ ld(Address(G3_klassOop, 0, instanceKlass::vtable_length_offset() * wordSize), L0); - - // %%% Could store the aligned, prescaled offset in the klassoop. - __ sll(L0, exact_log2(vtableEntry::size() * wordSize), L0); - // see code for instanceKlass::start_of_itable! - const int vtable_alignment = align_object_offset(1); - assert(vtable_alignment == 1 || vtable_alignment == 2, ""); - const int odd_bit = vtableEntry::size() * wordSize; - if (vtable_alignment == 2) { - __ and3(L0, odd_bit, L1); // isolate the odd bit - } - __ add(G3_klassOop, L0, L0); - if (vtable_alignment == 2) { - __ add(L0, L1, L0); // double the odd bit, to align up - } - - // Loop over all itable entries until desired interfaceOop (G5_interface) found - __ bind(search); - - // %%%% Could load both offset and interface in one ldx, if they were - // in the opposite order. This would save a load. - __ ld_ptr(L0, base + itableOffsetEntry::interface_offset_in_bytes(), L1); - - // If the entry is NULL then we've reached the end of the table - // without finding the expected interface, so throw an exception Label throw_icce; - __ bpr(Assembler::rc_z, false, Assembler::pn, L1, throw_icce); - __ delayed()->cmp(G5_interface, L1); - __ brx(Assembler::notEqual, true, Assembler::pn, search); - __ delayed()->add(L0, itableOffsetEntry::size() * wordSize, L0); - // entry found and L0 points to it, move offset of vtable for interface into L0 - __ ld(L0, base + itableOffsetEntry::offset_offset_in_bytes(), L0); - - // Compute itableMethodEntry and get methodOop(G5_method) and entrypoint(L0) for compiler - const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes(); - __ add(G3_klassOop, L0, L1); - __ ld_ptr(L1, method_offset, G5_method); + Register L5_method = L5; + __ lookup_interface_method(// inputs: rec. class, interface, itable index + G3_klassOop, G5_interface, itable_index, + // outputs: method, scan temp. reg + L5_method, L2, L3, + throw_icce); #ifndef PRODUCT if (DebugVtables) { Label L01; - __ ld_ptr(L1, method_offset, G5_method); - __ bpr(Assembler::rc_nz, false, Assembler::pt, G5_method, L01); + __ bpr(Assembler::rc_nz, false, Assembler::pt, L5_method, L01); __ delayed()->nop(); __ stop("methodOop is null"); __ bind(L01); - __ verify_oop(G5_method); + __ verify_oop(L5_method); } #endif // If the following load is through a NULL pointer, we'll take an OS // exception that should translate into an AbstractMethodError. We need the // window count to be correct at that time. - __ restore(); // Restore registers BEFORE the AME point + __ restore(L5_method, 0, G5_method); + // Restore registers *before* the AME point. address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract __ ld_ptr(G5_method, in_bytes(methodOopDesc::from_compiled_offset()), G3_scratch); @@ -225,6 +201,12 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { masm->flush(); + if (PrintMiscellaneous && (WizardMode || Verbose)) { + tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d", + itable_index, s->entry_point(), + (int)(s->code_end() - s->entry_point()), + (int)(s->code_end() - __ pc())); + } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); @@ -239,14 +221,15 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { if (is_vtable_stub) { // ld;ld;ld,jmp,nop const int basic = 5*BytesPerInstWord + - // shift;add for load_klass - (UseCompressedOops ? 2*BytesPerInstWord : 0); + // shift;add for load_klass (only shift with zero heap based) + (UseCompressedOops ? + ((Universe::narrow_oop_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); return basic + slop; } else { - // save, ld, ld, sll, and, add, add, ld, cmp, br, add, ld, add, ld, ld, jmp, restore, sethi, jmpl, restore - const int basic = (20 LP64_ONLY(+ 6)) * BytesPerInstWord + - // shift;add for load_klass - (UseCompressedOops ? 2*BytesPerInstWord : 0); + const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord + + // shift;add for load_klass (only shift with zero heap based) + (UseCompressedOops ? + ((Universe::narrow_oop_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); return (basic + slop); } } diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index d6433f0e176..35ee7e54019 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,13 +129,19 @@ Address::Address(address loc, RelocationHolder spec) { // Convert the raw encoding form into the form expected by the constructor for // Address. An index of 4 (rsp) corresponds to having no index, so convert // that to noreg for the Address constructor. -Address Address::make_raw(int base, int index, int scale, int disp) { +Address Address::make_raw(int base, int index, int scale, int disp, bool disp_is_oop) { + RelocationHolder rspec; + if (disp_is_oop) { + rspec = Relocation::spec_simple(relocInfo::oop_type); + } bool valid_index = index != rsp->encoding(); if (valid_index) { Address madr(as_Register(base), as_Register(index), (Address::ScaleFactor)scale, in_ByteSize(disp)); + madr._rspec = rspec; return madr; } else { Address madr(as_Register(base), noreg, Address::no_scale, in_ByteSize(disp)); + madr._rspec = rspec; return madr; } } @@ -721,7 +727,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { } #ifdef _LP64 - assert(false, "fix locate_operand"); + assert(which == narrow_oop_operand && !is_64bit, "instruction is not a movl adr, imm32"); #else assert(which == imm_operand, "instruction has only an imm field"); #endif // LP64 @@ -1432,26 +1438,12 @@ void Assembler::lock() { } } -// Serializes memory. +// Emit mfence instruction void Assembler::mfence() { - // Memory barriers are only needed on multiprocessors - if (os::is_MP()) { - if( LP64_ONLY(true ||) VM_Version::supports_sse2() ) { - emit_byte( 0x0F ); // MFENCE; faster blows no regs - emit_byte( 0xAE ); - emit_byte( 0xF0 ); - } else { - // 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. - // This is conveniently otherwise a no-op except for blowing - // flags (which we save and restore.) - pushf(); // Save eflags register - lock(); - addl(Address(rsp, 0), 0);// Assert the lock# signal here - popf(); // Restore eflags register - } - } + NOT_LP64(assert(VM_Version::supports_sse2(), "unsupported");) + emit_byte( 0x0F ); + emit_byte( 0xAE ); + emit_byte( 0xF0 ); } void Assembler::mov(Register dst, Register src) { @@ -2181,12 +2173,56 @@ void Assembler::orl(Register dst, Register src) { emit_arith(0x0B, 0xC0, dst, src); } +void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) { + assert(VM_Version::supports_sse4_2(), ""); + + InstructionMark im(this); + emit_byte(0x66); + prefix(src, dst); + emit_byte(0x0F); + emit_byte(0x3A); + emit_byte(0x61); + emit_operand(dst, src); + emit_byte(imm8); +} + +void Assembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) { + assert(VM_Version::supports_sse4_2(), ""); + + emit_byte(0x66); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0x3A); + emit_byte(0x61); + emit_byte(0xC0 | encode); + emit_byte(imm8); +} + // generic void Assembler::pop(Register dst) { int encode = prefix_and_encode(dst->encoding()); emit_byte(0x58 | encode); } +void Assembler::popcntl(Register dst, Address src) { + assert(VM_Version::supports_popcnt(), "must support"); + InstructionMark im(this); + emit_byte(0xF3); + prefix(src, dst); + emit_byte(0x0F); + emit_byte(0xB8); + emit_operand(dst, src); +} + +void Assembler::popcntl(Register dst, Register src) { + assert(VM_Version::supports_popcnt(), "must support"); + emit_byte(0xF3); + int encode = prefix_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0xB8); + emit_byte(0xC0 | encode); +} + void Assembler::popf() { emit_byte(0x9D); } @@ -2319,6 +2355,29 @@ void Assembler::psrlq(XMMRegister dst, int shift) { emit_byte(shift); } +void Assembler::ptest(XMMRegister dst, Address src) { + assert(VM_Version::supports_sse4_1(), ""); + + InstructionMark im(this); + emit_byte(0x66); + prefix(src, dst); + emit_byte(0x0F); + emit_byte(0x38); + emit_byte(0x17); + emit_operand(dst, src); +} + +void Assembler::ptest(XMMRegister dst, XMMRegister src) { + assert(VM_Version::supports_sse4_1(), ""); + + emit_byte(0x66); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0x38); + emit_byte(0x17); + emit_byte(0xC0 | encode); +} + void Assembler::punpcklbw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); emit_byte(0x66); @@ -3218,12 +3277,6 @@ void Assembler::fyl2x() { emit_byte(0xF1); } -void Assembler::mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec, int format) { - InstructionMark im(this); - int encode = prefix_and_encode(dst->encoding()); - emit_byte(0xB8 | encode); - emit_data((int)imm32, rspec, format); -} #ifndef _LP64 @@ -3243,6 +3296,12 @@ void Assembler::mov_literal32(Address dst, int32_t imm32, RelocationHolder cons emit_data((int)imm32, rspec, 0); } +void Assembler::mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + int encode = prefix_and_encode(dst->encoding()); + emit_byte(0xB8 | encode); + emit_data((int)imm32, rspec, 0); +} void Assembler::popa() { // 32bit emit_byte(0x61); @@ -3851,6 +3910,37 @@ void Assembler::mov_literal64(Register dst, intptr_t imm64, RelocationHolder con emit_data64(imm64, rspec); } +void Assembler::mov_narrow_oop(Register dst, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + int encode = prefix_and_encode(dst->encoding()); + emit_byte(0xB8 | encode); + emit_data((int)imm32, rspec, narrow_oop_operand); +} + +void Assembler::mov_narrow_oop(Address dst, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + prefix(dst); + emit_byte(0xC7); + emit_operand(rax, dst, 4); + emit_data((int)imm32, rspec, narrow_oop_operand); +} + +void Assembler::cmp_narrow_oop(Register src1, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + int encode = prefix_and_encode(src1->encoding()); + emit_byte(0x81); + emit_byte(0xF8 | encode); + emit_data((int)imm32, rspec, narrow_oop_operand); +} + +void Assembler::cmp_narrow_oop(Address src1, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + prefix(src1); + emit_byte(0x81); + emit_operand(rax, src1, 4); + emit_data((int)imm32, rspec, narrow_oop_operand); +} + void Assembler::movdq(XMMRegister dst, Register src) { // table D-1 says MMX/SSE2 NOT_LP64(assert(VM_Version::supports_sse2() || VM_Version::supports_mmx(), "")); @@ -3892,6 +3982,21 @@ void Assembler::movq(Address dst, Register src) { emit_operand(src, dst); } +void Assembler::movsbq(Register dst, Address src) { + InstructionMark im(this); + prefixq(src, dst); + emit_byte(0x0F); + emit_byte(0xBE); + emit_operand(dst, src); +} + +void Assembler::movsbq(Register dst, Register src) { + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0xBE); + emit_byte(0xC0 | encode); +} + void Assembler::movslq(Register dst, int32_t imm32) { // dbx shows movslq(rcx, 3) as movq $0x0000000049000000,(%rbx) // and movslq(r8, 3); as movl $0x0000000048000000,(%rbx) @@ -3925,6 +4030,51 @@ void Assembler::movslq(Register dst, Register src) { emit_byte(0xC0 | encode); } +void Assembler::movswq(Register dst, Address src) { + InstructionMark im(this); + prefixq(src, dst); + emit_byte(0x0F); + emit_byte(0xBF); + emit_operand(dst, src); +} + +void Assembler::movswq(Register dst, Register src) { + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0xBF); + emit_byte(0xC0 | encode); +} + +void Assembler::movzbq(Register dst, Address src) { + InstructionMark im(this); + prefixq(src, dst); + emit_byte(0x0F); + emit_byte(0xB6); + emit_operand(dst, src); +} + +void Assembler::movzbq(Register dst, Register src) { + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0xB6); + emit_byte(0xC0 | encode); +} + +void Assembler::movzwq(Register dst, Address src) { + InstructionMark im(this); + prefixq(src, dst); + emit_byte(0x0F); + emit_byte(0xB7); + emit_operand(dst, src); +} + +void Assembler::movzwq(Register dst, Register src) { + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0xB7); + emit_byte(0xC0 | encode); +} + void Assembler::negq(Register dst) { int encode = prefixq_and_encode(dst->encoding()); emit_byte(0xF7); @@ -3983,6 +4133,25 @@ void Assembler::popa() { // 64bit addq(rsp, 16 * wordSize); } +void Assembler::popcntq(Register dst, Address src) { + assert(VM_Version::supports_popcnt(), "must support"); + InstructionMark im(this); + emit_byte(0xF3); + prefixq(src, dst); + emit_byte(0x0F); + emit_byte(0xB8); + emit_operand(dst, src); +} + +void Assembler::popcntq(Register dst, Register src) { + assert(VM_Version::supports_popcnt(), "must support"); + emit_byte(0xF3); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0xB8); + emit_byte(0xC0 | encode); +} + void Assembler::popq(Address dst) { InstructionMark im(this); prefixq(dst); @@ -6197,8 +6366,11 @@ int MacroAssembler::load_signed_byte(Register dst, Address src) { return off; } -// word => int32 which seems bad for 64bit -int MacroAssembler::load_signed_word(Register dst, Address src) { +// Note: load_signed_short used to be called load_signed_word. +// Although the 'w' in x86 opcodes refers to the term "word" in the assembler +// manual, which means 16 bits, that usage is found nowhere in HotSpot code. +// The term "word" in HotSpot means a 32- or 64-bit machine word. +int MacroAssembler::load_signed_short(Register dst, Address src) { int off; if (LP64_ONLY(true ||) VM_Version::is_P6()) { // This is dubious to me since it seems safe to do a signed 16 => 64 bit @@ -6207,7 +6379,7 @@ int MacroAssembler::load_signed_word(Register dst, Address src) { off = offset(); movswl(dst, src); // movsxw } else { - off = load_unsigned_word(dst, src); + off = load_unsigned_short(dst, src); shll(dst, 16); sarl(dst, 16); } @@ -6229,7 +6401,8 @@ int MacroAssembler::load_unsigned_byte(Register dst, Address src) { return off; } -int MacroAssembler::load_unsigned_word(Register dst, Address src) { +// Note: load_unsigned_short used to be called load_unsigned_word. +int MacroAssembler::load_unsigned_short(Register dst, Address src) { // According to Intel Doc. AP-526, "Zero-Extension of Short", p.16, // and "3.9 Partial Register Penalties", p. 22). int off; @@ -6244,6 +6417,28 @@ int MacroAssembler::load_unsigned_word(Register dst, Address src) { return off; } +void MacroAssembler::load_sized_value(Register dst, Address src, + int size_in_bytes, bool is_signed) { + switch (size_in_bytes ^ (is_signed ? -1 : 0)) { +#ifndef _LP64 + // For case 8, caller is responsible for manually loading + // the second word into another register. + case ~8: // fall through: + case 8: movl( dst, src ); break; +#else + case ~8: // fall through: + case 8: movq( dst, src ); break; +#endif + case ~4: // fall through: + case 4: movl( dst, src ); break; + case ~2: load_signed_short( dst, src ); break; + case 2: load_unsigned_short( dst, src ); break; + case ~1: load_signed_byte( dst, src ); break; + case 1: load_unsigned_byte( dst, src ); break; + default: ShouldNotReachHere(); + } +} + void MacroAssembler::mov32(AddressLiteral dst, Register src) { if (reachable(dst)) { movl(as_Address(dst), src); @@ -6463,7 +6658,8 @@ void MacroAssembler::serialize_memory(Register thread, Register tmp) { Address index(noreg, tmp, Address::times_1); ExternalAddress page(os::get_memory_serialize_page()); - movptr(ArrayAddress(page, index), tmp); + // Size of store must match masking code above + movl(as_Address(ArrayAddress(page, index)), tmp); } // Calls to C land @@ -7049,6 +7245,300 @@ void MacroAssembler::trigfunc(char trig, int num_fpu_regs_in_use) { } +// Look up the method for a megamorphic invokeinterface call. +// The target method is determined by . +// The receiver klass is in recv_klass. +// On success, the result will be in method_result, and execution falls through. +// On failure, execution transfers to the given label. +void MacroAssembler::lookup_interface_method(Register recv_klass, + Register intf_klass, + RegisterOrConstant itable_index, + Register method_result, + Register scan_temp, + Label& L_no_such_interface) { + assert_different_registers(recv_klass, intf_klass, method_result, scan_temp); + assert(itable_index.is_constant() || itable_index.as_register() == method_result, + "caller must use same register for non-constant itable index as for method"); + + // Compute start of first itableOffsetEntry (which is at the end of the vtable) + int vtable_base = instanceKlass::vtable_start_offset() * wordSize; + int itentry_off = itableMethodEntry::method_offset_in_bytes(); + int scan_step = itableOffsetEntry::size() * wordSize; + int vte_size = vtableEntry::size() * wordSize; + Address::ScaleFactor times_vte_scale = Address::times_ptr; + assert(vte_size == wordSize, "else adjust times_vte_scale"); + + movl(scan_temp, Address(recv_klass, instanceKlass::vtable_length_offset() * wordSize)); + + // %%% Could store the aligned, prescaled offset in the klassoop. + lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base)); + if (HeapWordsPerLong > 1) { + // Round up to align_object_offset boundary + // see code for instanceKlass::start_of_itable! + round_to(scan_temp, BytesPerLong); + } + + // Adjust recv_klass by scaled itable_index, so we can free itable_index. + assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); + lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off)); + + // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) { + // if (scan->interface() == intf) { + // result = (klass + scan->offset() + itable_index); + // } + // } + Label search, found_method; + + for (int peel = 1; peel >= 0; peel--) { + movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes())); + cmpptr(intf_klass, method_result); + + if (peel) { + jccb(Assembler::equal, found_method); + } else { + jccb(Assembler::notEqual, search); + // (invert the test to fall through to found_method...) + } + + if (!peel) break; + + bind(search); + + // Check that the previous entry is non-null. A null entry means that + // the receiver class doesn't implement the interface, and wasn't the + // same as when the caller was compiled. + testptr(method_result, method_result); + jcc(Assembler::zero, L_no_such_interface); + addptr(scan_temp, scan_step); + } + + bind(found_method); + + // Got a hit. + movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes())); + movptr(method_result, Address(recv_klass, scan_temp, Address::times_1)); +} + + +void MacroAssembler::check_klass_subtype(Register sub_klass, + Register super_klass, + Register temp_reg, + Label& L_success) { + Label L_failure; + check_klass_subtype_fast_path(sub_klass, super_klass, temp_reg, &L_success, &L_failure, NULL); + check_klass_subtype_slow_path(sub_klass, super_klass, temp_reg, noreg, &L_success, NULL); + bind(L_failure); +} + + +void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterOrConstant super_check_offset) { + assert_different_registers(sub_klass, super_klass, temp_reg); + bool must_load_sco = (super_check_offset.constant_or_zero() == -1); + if (super_check_offset.is_register()) { + assert_different_registers(sub_klass, super_klass, + super_check_offset.as_register()); + } else if (must_load_sco) { + assert(temp_reg != noreg, "supply either a temp or a register offset"); + } + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1, "at most one NULL in the batch"); + + int sc_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_super_cache_offset_in_bytes()); + int sco_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::super_check_offset_offset_in_bytes()); + Address super_check_offset_addr(super_klass, sco_offset); + + // Hacked jcc, which "knows" that L_fallthrough, at least, is in + // range of a jccb. If this routine grows larger, reconsider at + // least some of these. +#define local_jcc(assembler_cond, label) \ + if (&(label) == &L_fallthrough) jccb(assembler_cond, label); \ + else jcc( assembler_cond, label) /*omit semi*/ + + // Hacked jmp, which may only be used just before L_fallthrough. +#define final_jmp(label) \ + if (&(label) == &L_fallthrough) { /*do nothing*/ } \ + else jmp(label) /*omit semi*/ + + // If the pointers are equal, we are done (e.g., String[] elements). + // This self-check enables sharing of secondary supertype arrays among + // non-primary types such as array-of-interface. Otherwise, each such + // type would need its own customized SSA. + // We move this check to the front of the fast path because many + // type checks are in fact trivially successful in this manner, + // so we get a nicely predicted branch right at the start of the check. + cmpptr(sub_klass, super_klass); + local_jcc(Assembler::equal, *L_success); + + // Check the supertype display: + if (must_load_sco) { + // Positive movl does right thing on LP64. + movl(temp_reg, super_check_offset_addr); + super_check_offset = RegisterOrConstant(temp_reg); + } + Address super_check_addr(sub_klass, super_check_offset, Address::times_1, 0); + cmpptr(super_klass, super_check_addr); // load displayed supertype + + // This check has worked decisively for primary supers. + // Secondary supers are sought in the super_cache ('super_cache_addr'). + // (Secondary supers are interfaces and very deeply nested subtypes.) + // This works in the same check above because of a tricky aliasing + // between the super_cache and the primary super display elements. + // (The 'super_check_addr' can address either, as the case requires.) + // Note that the cache is updated below if it does not help us find + // what we need immediately. + // So if it was a primary super, we can just fail immediately. + // Otherwise, it's the slow path for us (no success at this point). + + if (super_check_offset.is_register()) { + local_jcc(Assembler::equal, *L_success); + cmpl(super_check_offset.as_register(), sc_offset); + if (L_failure == &L_fallthrough) { + local_jcc(Assembler::equal, *L_slow_path); + } else { + local_jcc(Assembler::notEqual, *L_failure); + final_jmp(*L_slow_path); + } + } else if (super_check_offset.as_constant() == sc_offset) { + // Need a slow path; fast failure is impossible. + if (L_slow_path == &L_fallthrough) { + local_jcc(Assembler::equal, *L_success); + } else { + local_jcc(Assembler::notEqual, *L_slow_path); + final_jmp(*L_success); + } + } else { + // No slow path; it's a fast decision. + if (L_failure == &L_fallthrough) { + local_jcc(Assembler::equal, *L_success); + } else { + local_jcc(Assembler::notEqual, *L_failure); + final_jmp(*L_success); + } + } + + bind(L_fallthrough); + +#undef local_jcc +#undef final_jmp +} + + +void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label* L_success, + Label* L_failure, + bool set_cond_codes) { + assert_different_registers(sub_klass, super_klass, temp_reg); + if (temp2_reg != noreg) + assert_different_registers(sub_klass, super_klass, temp_reg, temp2_reg); +#define IS_A_TEMP(reg) ((reg) == temp_reg || (reg) == temp2_reg) + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1, "at most one NULL in the batch"); + + // a couple of useful fields in sub_klass: + int ss_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_supers_offset_in_bytes()); + int sc_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_super_cache_offset_in_bytes()); + Address secondary_supers_addr(sub_klass, ss_offset); + Address super_cache_addr( sub_klass, sc_offset); + + // Do a linear scan of the secondary super-klass chain. + // This code is rarely used, so simplicity is a virtue here. + // The repne_scan instruction uses fixed registers, which we must spill. + // Don't worry too much about pre-existing connections with the input regs. + + assert(sub_klass != rax, "killed reg"); // killed by mov(rax, super) + assert(sub_klass != rcx, "killed reg"); // killed by lea(rcx, &pst_counter) + + // Get super_klass value into rax (even if it was in rdi or rcx). + bool pushed_rax = false, pushed_rcx = false, pushed_rdi = false; + if (super_klass != rax || UseCompressedOops) { + if (!IS_A_TEMP(rax)) { push(rax); pushed_rax = true; } + mov(rax, super_klass); + } + if (!IS_A_TEMP(rcx)) { push(rcx); pushed_rcx = true; } + if (!IS_A_TEMP(rdi)) { push(rdi); pushed_rdi = true; } + +#ifndef PRODUCT + int* pst_counter = &SharedRuntime::_partial_subtype_ctr; + ExternalAddress pst_counter_addr((address) pst_counter); + NOT_LP64( incrementl(pst_counter_addr) ); + LP64_ONLY( lea(rcx, pst_counter_addr) ); + LP64_ONLY( incrementl(Address(rcx, 0)) ); +#endif //PRODUCT + + // We will consult the secondary-super array. + movptr(rdi, secondary_supers_addr); + // Load the array length. (Positive movl does right thing on LP64.) + movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); + // Skip to start of data. + addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + + // Scan RCX words at [RDI] for an occurrence of RAX. + // Set NZ/Z based on last compare. +#ifdef _LP64 + // This part is tricky, as values in supers array could be 32 or 64 bit wide + // and we store values in objArrays always encoded, thus we need to encode + // the value of rax before repne. Note that rax is dead after the repne. + if (UseCompressedOops) { + encode_heap_oop_not_null(rax); + // The superclass is never null; it would be a basic system error if a null + // pointer were to sneak in here. Note that we have already loaded the + // Klass::super_check_offset from the super_klass in the fast path, + // so if there is a null in that register, we are already in the afterlife. + repne_scanl(); + } else +#endif // _LP64 + repne_scan(); + + // Unspill the temp. registers: + if (pushed_rdi) pop(rdi); + if (pushed_rcx) pop(rcx); + if (pushed_rax) pop(rax); + + if (set_cond_codes) { + // Special hack for the AD files: rdi is guaranteed non-zero. + assert(!pushed_rdi, "rdi must be left non-NULL"); + // Also, the condition codes are properly set Z/NZ on succeed/failure. + } + + if (L_failure == &L_fallthrough) + jccb(Assembler::notEqual, *L_failure); + else jcc(Assembler::notEqual, *L_failure); + + // Success. Cache the super we found and proceed in triumph. + movptr(super_cache_addr, super_klass); + + if (L_success != &L_fallthrough) { + jmp(*L_success); + } + +#undef IS_A_TEMP + + bind(L_fallthrough); +} + + void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src) { ucomisd(dst, as_Address(src)); } @@ -7094,6 +7584,31 @@ void MacroAssembler::verify_oop(Register reg, const char* s) { } +RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, + Register tmp, + int offset) { + intptr_t value = *delayed_value_addr; + if (value != 0) + return RegisterOrConstant(value + offset); + + // load indirectly to solve generation ordering problem + movptr(tmp, ExternalAddress((address) delayed_value_addr)); + +#ifdef ASSERT + Label L; + testl(tmp, tmp); + jccb(Assembler::notZero, L); + hlt(); + bind(L); +#endif + + if (offset != 0) + addptr(tmp, offset); + + return RegisterOrConstant(tmp); +} + + void MacroAssembler::verify_oop_addr(Address addr, const char* s) { if (!VerifyOops) return; @@ -7517,14 +8032,21 @@ void MacroAssembler::load_klass(Register dst, Register src) { void MacroAssembler::load_prototype_header(Register dst, Register src) { #ifdef _LP64 if (UseCompressedOops) { + assert (Universe::heap() != NULL, "java heap should be initialized"); movl(dst, Address(src, oopDesc::klass_offset_in_bytes())); - movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + if (Universe::narrow_oop_shift() != 0) { + assert(Address::times_8 == LogMinObjAlignmentInBytes && + Address::times_8 == Universe::narrow_oop_shift(), "decode alg wrong"); + movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + } else { + movq(dst, Address(dst, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + } } else #endif - { - movptr(dst, Address(src, oopDesc::klass_offset_in_bytes())); - movptr(dst, Address(dst, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); - } + { + movptr(dst, Address(src, oopDesc::klass_offset_in_bytes())); + movptr(dst, Address(dst, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + } } void MacroAssembler::store_klass(Register dst, Register src) { @@ -7567,11 +8089,20 @@ void MacroAssembler::store_heap_oop(Address dst, Register src) { // Algorithm must match oop.inline.hpp encode_heap_oop. void MacroAssembler::encode_heap_oop(Register r) { assert (UseCompressedOops, "should be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + if (Universe::narrow_oop_base() == NULL) { + verify_oop(r, "broken oop in encode_heap_oop"); + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shrq(r, LogMinObjAlignmentInBytes); + } + return; + } #ifdef ASSERT if (CheckCompressedOops) { Label ok; push(rscratch1); // cmpptr trashes rscratch1 - cmpptr(r12_heapbase, ExternalAddress((address)Universe::heap_base_addr())); + cmpptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); jcc(Assembler::equal, ok); stop("MacroAssembler::encode_heap_oop: heap base corrupted?"); bind(ok); @@ -7587,6 +8118,7 @@ void MacroAssembler::encode_heap_oop(Register r) { void MacroAssembler::encode_heap_oop_not_null(Register r) { assert (UseCompressedOops, "should be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); #ifdef ASSERT if (CheckCompressedOops) { Label ok; @@ -7597,12 +8129,18 @@ void MacroAssembler::encode_heap_oop_not_null(Register r) { } #endif verify_oop(r, "broken oop in encode_heap_oop_not_null"); - subq(r, r12_heapbase); - shrq(r, LogMinObjAlignmentInBytes); + if (Universe::narrow_oop_base() != NULL) { + subq(r, r12_heapbase); + } + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shrq(r, LogMinObjAlignmentInBytes); + } } void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { assert (UseCompressedOops, "should be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); #ifdef ASSERT if (CheckCompressedOops) { Label ok; @@ -7616,18 +8154,32 @@ void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { if (dst != src) { movq(dst, src); } - subq(dst, r12_heapbase); - shrq(dst, LogMinObjAlignmentInBytes); + if (Universe::narrow_oop_base() != NULL) { + subq(dst, r12_heapbase); + } + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shrq(dst, LogMinObjAlignmentInBytes); + } } void MacroAssembler::decode_heap_oop(Register r) { assert (UseCompressedOops, "should be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + if (Universe::narrow_oop_base() == NULL) { + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shlq(r, LogMinObjAlignmentInBytes); + } + verify_oop(r, "broken oop in decode_heap_oop"); + return; + } #ifdef ASSERT if (CheckCompressedOops) { Label ok; push(rscratch1); cmpptr(r12_heapbase, - ExternalAddress((address)Universe::heap_base_addr())); + ExternalAddress((address)Universe::narrow_oop_base_addr())); jcc(Assembler::equal, ok); stop("MacroAssembler::decode_heap_oop: heap base corrupted?"); bind(ok); @@ -7651,32 +8203,76 @@ void MacroAssembler::decode_heap_oop(Register r) { void MacroAssembler::decode_heap_oop_not_null(Register r) { assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. - assert(Address::times_8 == LogMinObjAlignmentInBytes, "decode alg wrong"); - leaq(r, Address(r12_heapbase, r, Address::times_8, 0)); + if (Universe::narrow_oop_base() == NULL) { + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shlq(r, LogMinObjAlignmentInBytes); + } + } else { + assert (Address::times_8 == LogMinObjAlignmentInBytes && + Address::times_8 == Universe::narrow_oop_shift(), "decode alg wrong"); + leaq(r, Address(r12_heapbase, r, Address::times_8, 0)); + } } void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) { assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. - assert(Address::times_8 == LogMinObjAlignmentInBytes, "decode alg wrong"); - leaq(dst, Address(r12_heapbase, src, Address::times_8, 0)); + if (Universe::narrow_oop_shift() != 0) { + assert (Address::times_8 == LogMinObjAlignmentInBytes && + Address::times_8 == Universe::narrow_oop_shift(), "decode alg wrong"); + leaq(dst, Address(r12_heapbase, src, Address::times_8, 0)); + } else if (dst != src) { + movq(dst, src); + } } void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { - assert(oop_recorder() != NULL, "this assembler needs an OopRecorder"); + assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); int oop_index = oop_recorder()->find_index(obj); RelocationHolder rspec = oop_Relocation::spec(oop_index); - mov_literal32(dst, oop_index, rspec, narrow_oop_operand); + mov_narrow_oop(dst, oop_index, rspec); +} + +void MacroAssembler::set_narrow_oop(Address dst, jobject obj) { + assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int oop_index = oop_recorder()->find_index(obj); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + mov_narrow_oop(dst, oop_index, rspec); +} + +void MacroAssembler::cmp_narrow_oop(Register dst, jobject obj) { + assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int oop_index = oop_recorder()->find_index(obj); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + Assembler::cmp_narrow_oop(dst, oop_index, rspec); +} + +void MacroAssembler::cmp_narrow_oop(Address dst, jobject obj) { + assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int oop_index = oop_recorder()->find_index(obj); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + Assembler::cmp_narrow_oop(dst, oop_index, rspec); } void MacroAssembler::reinit_heapbase() { if (UseCompressedOops) { - movptr(r12_heapbase, ExternalAddress((address)Universe::heap_base_addr())); + movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); } } #endif // _LP64 diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 32cb356a1a1..89ac6dd5326 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,6 +153,21 @@ class Address VALUE_OBJ_CLASS_SPEC { times_8 = 3, times_ptr = LP64_ONLY(times_8) NOT_LP64(times_4) }; + static ScaleFactor times(int size) { + assert(size >= 1 && size <= 8 && is_power_of_2(size), "bad scale size"); + if (size == 8) return times_8; + if (size == 4) return times_4; + if (size == 2) return times_2; + return times_1; + } + static int scale_size(ScaleFactor scale) { + assert(scale != no_scale, ""); + assert(((1 << (int)times_1) == 1 && + (1 << (int)times_2) == 2 && + (1 << (int)times_4) == 4 && + (1 << (int)times_8) == 8), ""); + return (1 << (int)scale); + } private: Register _base; @@ -197,6 +212,22 @@ class Address VALUE_OBJ_CLASS_SPEC { "inconsistent address"); } + Address(Register base, RegisterOrConstant index, ScaleFactor scale = times_1, int disp = 0) + : _base (base), + _index(index.register_or_noreg()), + _scale(scale), + _disp (disp + (index.constant_or_zero() * scale_size(scale))) { + if (!index.is_register()) scale = Address::no_scale; + assert(!_index->is_valid() == (scale == Address::no_scale), + "inconsistent address"); + } + + Address plus_disp(int disp) const { + Address a = (*this); + a._disp += disp; + return a; + } + // The following two overloads are used in connection with the // ByteSize type (see sizes.hpp). They simplify the use of // ByteSize'd arguments in assembly code. Note that their equivalent @@ -224,6 +255,17 @@ class Address VALUE_OBJ_CLASS_SPEC { assert(!index->is_valid() == (scale == Address::no_scale), "inconsistent address"); } + + Address(Register base, RegisterOrConstant index, ScaleFactor scale, ByteSize disp) + : _base (base), + _index(index.register_or_noreg()), + _scale(scale), + _disp (in_bytes(disp) + (index.constant_or_zero() * scale_size(scale))) { + if (!index.is_register()) scale = Address::no_scale; + assert(!_index->is_valid() == (scale == Address::no_scale), + "inconsistent address"); + } + #endif // ASSERT // accessors @@ -236,11 +278,10 @@ class Address VALUE_OBJ_CLASS_SPEC { // Convert the raw encoding form into the form expected by the constructor for // Address. An index of 4 (rsp) corresponds to having no index, so convert // that to noreg for the Address constructor. - static Address make_raw(int base, int index, int scale, int disp); + static Address make_raw(int base, int index, int scale, int disp, bool disp_is_oop); static Address make_array(ArrayAddress); - private: bool base_needs_rex() const { return _base != noreg && _base->encoding() >= 8; @@ -537,20 +578,25 @@ private: // These are all easily abused and hence protected - void mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec, int format = 0); - // 32BIT ONLY SECTION #ifndef _LP64 // Make these disappear in 64bit mode since they would never be correct void cmp_literal32(Register src1, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY void cmp_literal32(Address src1, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY + void mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY void mov_literal32(Address dst, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY void push_literal32(int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY #else // 64BIT ONLY SECTION void mov_literal64(Register dst, intptr_t imm64, RelocationHolder const& rspec); // 64BIT ONLY + + void cmp_narrow_oop(Register src1, int32_t imm32, RelocationHolder const& rspec); + void cmp_narrow_oop(Address src1, int32_t imm32, RelocationHolder const& rspec); + + void mov_narrow_oop(Register dst, int32_t imm32, RelocationHolder const& rspec); + void mov_narrow_oop(Address dst, int32_t imm32, RelocationHolder const& rspec); #endif // _LP64 // These are unique in that we are ensured by the caller that the 32bit @@ -1022,15 +1068,23 @@ private: LoadLoad = 1 << 0 }; - // Serializes memory. + // Serializes memory and blows flags void membar(Membar_mask_bits order_constraint) { - // We only have to handle StoreLoad and LoadLoad - if (order_constraint & StoreLoad) { - // MFENCE subsumes LFENCE - mfence(); - } /* [jk] not needed currently: else if (order_constraint & LoadLoad) { - lfence(); - } */ + if (os::is_MP()) { + // We only have to handle StoreLoad + 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. + // This is conveniently otherwise a no-op except for blowing + // flags. + // Any change to this code may need to revisit other places in + // the code where this idiom is used, in particular the + // orderAccess code. + lock(); + addl(Address(rsp, 0), 0);// Assert the lock# signal here + } + } } void mfence(); @@ -1097,6 +1151,9 @@ private: void movsbl(Register dst, Register src); #ifdef _LP64 + void movsbq(Register dst, Address src); + void movsbq(Register dst, Register src); + // Move signed 32bit immediate to 64bit extending sign void movslq(Address dst, int32_t imm64); void movslq(Register dst, int32_t imm64); @@ -1109,6 +1166,11 @@ private: void movswl(Register dst, Address src); void movswl(Register dst, Register src); +#ifdef _LP64 + void movswq(Register dst, Address src); + void movswq(Register dst, Register src); +#endif + void movw(Address dst, int imm16); void movw(Register dst, Address src); void movw(Address dst, Register src); @@ -1116,9 +1178,19 @@ private: void movzbl(Register dst, Address src); void movzbl(Register dst, Register src); +#ifdef _LP64 + void movzbq(Register dst, Address src); + void movzbq(Register dst, Register src); +#endif + void movzwl(Register dst, Address src); void movzwl(Register dst, Register src); +#ifdef _LP64 + void movzwq(Register dst, Address src); + void movzwq(Register dst, Register src); +#endif + void mull(Address src); void mull(Register src); @@ -1154,12 +1226,24 @@ private: void orq(Register dst, Address src); void orq(Register dst, Register src); + // SSE4.2 string instructions + void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8); + void pcmpestri(XMMRegister xmm1, Address src, int imm8); + void popl(Address dst); #ifdef _LP64 void popq(Address dst); #endif + void popcntl(Register dst, Address src); + void popcntl(Register dst, Register src); + +#ifdef _LP64 + void popcntq(Register dst, Address src); + void popcntq(Register dst, Register src); +#endif + // Prefetches (SSE, SSE2, 3DNOW only) void prefetchnta(Address src); @@ -1180,6 +1264,10 @@ private: // Shift Right Logical Quadword Immediate void psrlq(XMMRegister dst, int shift); + // Logical Compare Double Quadword + void ptest(XMMRegister dst, XMMRegister src); + void ptest(XMMRegister dst, Address src); + // Interleave Low Bytes void punpcklbw(XMMRegister dst, XMMRegister src); @@ -1393,17 +1481,20 @@ class MacroAssembler: public Assembler { // The following 4 methods return the offset of the appropriate move instruction - // Support for fast byte/word loading with zero extension (depending on particular CPU) + // Support for fast byte/short loading with zero extension (depending on particular CPU) int load_unsigned_byte(Register dst, Address src); - int load_unsigned_word(Register dst, Address src); + int load_unsigned_short(Register dst, Address src); - // Support for fast byte/word loading with sign extension (depending on particular CPU) + // Support for fast byte/short loading with sign extension (depending on particular CPU) int load_signed_byte(Register dst, Address src); - int load_signed_word(Register dst, Address src); + int load_signed_short(Register dst, Address src); // Support for sign-extension (hi:lo = extend_sign(lo)) void extend_sign(Register hi, Register lo); + // Loading values by size and signed-ness + void load_sized_value(Register dst, Address src, int size_in_bytes, bool is_signed); + // Support for inc/dec with optimal instruction selection depending on value void increment(Register reg, int value = 1) { LP64_ONLY(incrementq(reg, value)) NOT_LP64(incrementl(reg, value)) ; } @@ -1585,6 +1676,9 @@ class MacroAssembler: public Assembler { void decode_heap_oop_not_null(Register dst, Register src); void set_narrow_oop(Register dst, jobject obj); + void set_narrow_oop(Address dst, jobject obj); + void cmp_narrow_oop(Register dst, jobject obj); + void cmp_narrow_oop(Address dst, jobject obj); // if heap base register is used - reinit it with the correct value void reinit_heapbase(); @@ -1721,6 +1815,48 @@ class MacroAssembler: public Assembler { ); void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); + // interface method calling + void lookup_interface_method(Register recv_klass, + Register intf_klass, + RegisterOrConstant itable_index, + Register method_result, + Register scan_temp, + Label& no_such_interface); + + // Test sub_klass against super_klass, with fast and slow paths. + + // The fast path produces a tri-state answer: yes / no / maybe-slow. + // One of the three labels can be NULL, meaning take the fall-through. + // If super_check_offset is -1, the value is loaded up from super_klass. + // No registers are killed, except temp_reg. + void check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterOrConstant super_check_offset = RegisterOrConstant(-1)); + + // The rest of the type check; must be wired to a corresponding fast path. + // It does not repeat the fast path logic, so don't use it standalone. + // The temp_reg and temp2_reg can be noreg, if no temps are available. + // Updates the sub's secondary super cache as necessary. + // If set_cond_codes, condition codes will be Z on success, NZ on failure. + void check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label* L_success, + Label* L_failure, + bool set_cond_codes = false); + + // Simplified, combined version, good for typical uses. + // Falls through on failure. + void check_klass_subtype(Register sub_klass, + Register super_klass, + Register temp_reg, + Label& L_success); + //---- void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0 @@ -1763,6 +1899,10 @@ class MacroAssembler: public Assembler { // stack overflow + shadow pages. Also, clobbers tmp void bang_stack_size(Register size, Register tmp); + virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, + Register tmp, + int offset); + // Support for serializing memory accesses between threads void serialize_memory(Register thread, Register tmp); diff --git a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp index f66bfd4d309..388e1cfd967 100644 --- a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index cdf508fab01..51a951d9725 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -554,8 +554,8 @@ void LIR_Assembler::emit_string_compare(LIR_Opr arg0, LIR_Opr arg1, LIR_Opr dst, __ jcc (Assembler::zero, noLoop); // compare first characters - __ load_unsigned_word(rcx, Address(rdi, 0)); - __ load_unsigned_word(rbx, Address(rsi, 0)); + __ load_unsigned_short(rcx, Address(rdi, 0)); + __ load_unsigned_short(rbx, Address(rsi, 0)); __ subl(rcx, rbx); __ jcc(Assembler::notZero, haveResult); // starting loop @@ -574,8 +574,8 @@ void LIR_Assembler::emit_string_compare(LIR_Opr arg0, LIR_Opr arg1, LIR_Opr dst, Label loop; __ align(wordSize); __ bind(loop); - __ load_unsigned_word(rcx, Address(rdi, rax, Address::times_2, 0)); - __ load_unsigned_word(rbx, Address(rsi, rax, Address::times_2, 0)); + __ load_unsigned_short(rcx, Address(rdi, rax, Address::times_2, 0)); + __ load_unsigned_short(rbx, Address(rsi, rax, Address::times_2, 0)); __ subl(rcx, rbx); __ jcc(Assembler::notZero, haveResult); __ increment(rax); @@ -1598,18 +1598,9 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { // get instance klass __ movptr(k_RInfo, Address(k_RInfo, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc))); - // get super_check_offset - __ movl(Rtmp1, Address(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes())); - // See if we get an immediate positive hit - __ cmpptr(k_RInfo, Address(klass_RInfo, Rtmp1, Address::times_1)); - __ jcc(Assembler::equal, done); - // check for immediate negative hit - __ cmpl(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ jcc(Assembler::notEqual, *stub->entry()); - // check for self - __ cmpptr(klass_RInfo, k_RInfo); - __ jcc(Assembler::equal, done); - + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, &done, stub->entry(), NULL); + // call out-of-line instance of __ check_klass_subtype_slow_path(...): __ push(klass_RInfo); __ push(k_RInfo); __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); @@ -1735,17 +1726,9 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { } __ bind(done); } else { - __ movl(Rtmp1, Address(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes())); - // See if we get an immediate positive hit - __ cmpptr(k_RInfo, Address(klass_RInfo, Rtmp1, Address::times_1)); - __ jcc(Assembler::equal, done); - // check for immediate negative hit - __ cmpl(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ jcc(Assembler::notEqual, *stub->entry()); - // check for self - __ cmpptr(klass_RInfo, k_RInfo); - __ jcc(Assembler::equal, done); - + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, &done, stub->entry(), NULL); + // call out-of-line instance of __ check_klass_subtype_slow_path(...): __ push(klass_RInfo); __ push(k_RInfo); __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); @@ -1821,23 +1804,15 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ pop(dst); __ jmp(done); } - } else { -#else - { // YUCK + } + else // next block is unconditional if LP64: #endif // LP64 + { assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers"); - __ movl(dst, Address(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes())); - // See if we get an immediate positive hit - __ cmpptr(k_RInfo, Address(klass_RInfo, dst, Address::times_1)); - __ jcc(Assembler::equal, one); - // check for immediate negative hit - __ cmpl(dst, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ jcc(Assembler::notEqual, zero); - // check for self - __ cmpptr(klass_RInfo, k_RInfo); - __ jcc(Assembler::equal, one); - + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, dst, &one, &zero, NULL); + // call out-of-line instance of __ check_klass_subtype_slow_path(...): __ push(klass_RInfo); __ push(k_RInfo); __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); diff --git a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index 26acffbb321..5b46c4a88ce 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -501,7 +501,7 @@ void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) { LIRItem right(x->y(), this); left.load_item(); - // dont load constants to save register + // don't load constants to save register right.load_nonconstant(); rlock_result(x); arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL); diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index 12aea3fde07..3a447754ede 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1354,6 +1354,13 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { case slow_subtype_check_id: { + // Typical calling sequence: + // __ push(klass_RInfo); // object klass or other subclass + // __ push(sup_k_RInfo); // array element klass or other superclass + // __ call(slow_subtype_check); + // Note that the subclass is pushed first, and is therefore deepest. + // Previous versions of this code reversed the names 'sub' and 'super'. + // This was operationally harmless but made the code unreadable. enum layout { rax_off, SLOT2(raxH_off) rcx_off, SLOT2(rcxH_off) @@ -1361,9 +1368,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { rdi_off, SLOT2(rdiH_off) // saved_rbp_off, SLOT2(saved_rbpH_off) return_off, SLOT2(returnH_off) - sub_off, SLOT2(subH_off) - super_off, SLOT2(superH_off) - framesize + sup_k_off, SLOT2(sup_kH_off) + klass_off, SLOT2(superH_off) + framesize, + result_off = klass_off // deepest argument is also the return value }; __ set_info("slow_subtype_check", dont_gc_arguments); @@ -1373,19 +1381,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ push(rax); // This is called by pushing args and not with C abi - __ movptr(rsi, Address(rsp, (super_off) * VMRegImpl::stack_slot_size)); // super - __ movptr(rax, Address(rsp, (sub_off ) * VMRegImpl::stack_slot_size)); // sub - - __ movptr(rdi,Address(rsi,sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())); - // since size is postive movl does right thing on 64bit - __ movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); - __ addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ movptr(rsi, Address(rsp, (klass_off) * VMRegImpl::stack_slot_size)); // subclass + __ movptr(rax, Address(rsp, (sup_k_off) * VMRegImpl::stack_slot_size)); // superclass Label miss; - __ repne_scan(); - __ jcc(Assembler::notEqual, miss); - __ movptr(Address(rsi,sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()), rax); - __ movptr(Address(rsp, (super_off) * VMRegImpl::stack_slot_size), 1); // result + __ check_klass_subtype_slow_path(rsi, rax, rcx, rdi, NULL, &miss); + + // fallthrough on success: + __ movptr(Address(rsp, (result_off) * VMRegImpl::stack_slot_size), 1); // result __ pop(rax); __ pop(rcx); __ pop(rsi); @@ -1393,7 +1396,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ ret(0); __ bind(miss); - __ movptr(Address(rsp, (super_off) * VMRegImpl::stack_slot_size), NULL_WORD); // result + __ movptr(Address(rsp, (result_off) * VMRegImpl::stack_slot_size), NULL_WORD); // result __ pop(rax); __ pop(rcx); __ pop(rsi); diff --git a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp index a3621ad886c..31afca77377 100644 --- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp +++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -513,7 +513,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register // compute full expression stack limit const Address size_of_stack (rbx, methodOopDesc::max_stack_offset()); - __ load_unsigned_word(rdx, size_of_stack); // get size of expression stack in words + __ load_unsigned_short(rdx, size_of_stack); // get size of expression stack in words __ negptr(rdx); // so we can subtract in next step // Allocate expression stack __ lea(rsp, Address(rsp, rdx, Address::times_ptr)); @@ -523,7 +523,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register #ifdef _LP64 // Make sure stack is properly aligned and sized for the abi __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows - __ andptr(rsp, -16); // must be 16 byte boundry (see amd64 ABI) + __ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI) #endif // _LP64 @@ -659,7 +659,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { // Always give one monitor to allow us to start interp if sync method. // Any additional monitors need a check when moving the expression stack const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize; - __ load_unsigned_word(rax, size_of_stack); // get size of expression stack in words + __ load_unsigned_short(rax, size_of_stack); // get size of expression stack in words __ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor)); __ lea(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size)); @@ -863,13 +863,13 @@ address InterpreterGenerator::generate_accessor_entry(void) { __ bind(notByte); __ cmpl(rdx, stos); __ jcc(Assembler::notEqual, notShort); - __ load_signed_word(rax, field_address); + __ load_signed_short(rax, field_address); __ jmp(xreturn_path); __ bind(notShort); __ cmpl(rdx, ctos); __ jcc(Assembler::notEqual, notChar); - __ load_unsigned_word(rax, field_address); + __ load_unsigned_short(rax, field_address); __ jmp(xreturn_path); __ bind(notChar); @@ -937,7 +937,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { const Register locals = rdi; // get parameter size (always needed) - __ load_unsigned_word(rcx, size_of_parameters); + __ load_unsigned_short(rcx, size_of_parameters); // rbx: methodOop // rcx: size of parameters @@ -970,7 +970,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { #ifdef _LP64 // duplicate the alignment rsp got after setting stack_base __ subptr(rax, frame::arg_reg_save_area_bytes); // windows - __ andptr(rax, -16); // must be 16 byte boundry (see amd64 ABI) + __ andptr(rax, -16); // must be 16 byte boundary (see amd64 ABI) #endif // _LP64 __ cmpptr(rax, rsp); __ jcc(Assembler::equal, L); @@ -1062,12 +1062,12 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // allocate space for parameters __ movptr(method, STATE(_method)); __ verify_oop(method); - __ load_unsigned_word(t, Address(method, methodOopDesc::size_of_parameters_offset())); + __ load_unsigned_short(t, Address(method, methodOopDesc::size_of_parameters_offset())); __ shll(t, 2); #ifdef _LP64 __ subptr(rsp, t); __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows - __ andptr(rsp, -16); // must be 16 byte boundry (see amd64 ABI) + __ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI) #else __ addptr(t, 2*wordSize); // allocate two more slots for JNIEnv and possible mirror __ subptr(rsp, t); @@ -1659,11 +1659,11 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { // const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * wordSize - (int)sizeof(BasicObjectLock)); // get parameter size (always needed) - __ load_unsigned_word(rcx, size_of_parameters); + __ load_unsigned_short(rcx, size_of_parameters); // rbx: methodOop // rcx: size of parameters - __ load_unsigned_word(rdx, size_of_locals); // get size of locals in words + __ load_unsigned_short(rdx, size_of_locals); // get size of locals in words __ subptr(rdx, rcx); // rdx = no. of additional locals @@ -1949,7 +1949,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { __ movptr(rbx, STATE(_result._to_call._callee)); // callee left args on top of expression stack, remove them - __ load_unsigned_word(rcx, Address(rbx, methodOopDesc::size_of_parameters_offset())); + __ load_unsigned_short(rcx, Address(rbx, methodOopDesc::size_of_parameters_offset())); __ lea(rsp, Address(rsp, rcx, Address::times_ptr)); __ movl(rcx, Address(rbx, methodOopDesc::result_index_offset())); @@ -2119,7 +2119,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { // Make it look like call_stub calling conventions // Get (potential) receiver - __ load_unsigned_word(rcx, size_of_parameters); // get size of parameters in words + __ load_unsigned_short(rcx, size_of_parameters); // get size of parameters in words ExternalAddress recursive(CAST_FROM_FN_PTR(address, RecursiveInterpreterActivation)); __ pushptr(recursive.addr()); // make it look good in the debugger diff --git a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp index 82c37fd41da..c3bfdae6d01 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index 67f27d68125..9d6d0292eab 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -60,6 +60,7 @@ define_pd_global(uintx, NewSize, 1024 * K); define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1)); #endif // AMD64 define_pd_global(intx, InlineFrequencyCount, 100); +define_pd_global(intx, InlineSmallCode, 1000); define_pd_global(intx, PreInflateSpin, 10); define_pd_global(intx, StackYellowPages, 2); diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp index c11c3bc5404..bb14db9056f 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -192,7 +192,7 @@ void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp(Register reg, i void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset) { assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); assert(cache != index, "must use different registers"); - load_unsigned_word(index, Address(rsi, bcp_offset)); + load_unsigned_short(index, Address(rsi, bcp_offset)); movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below"); shlptr(index, 2); // convert from field index to ConstantPoolCacheEntry index @@ -202,7 +202,7 @@ void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Regis void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset) { assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); assert(cache != tmp, "must use different register"); - load_unsigned_word(tmp, Address(rsi, bcp_offset)); + load_unsigned_short(tmp, Address(rsi, bcp_offset)); assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below"); // convert from field index to ConstantPoolCacheEntry index // and from word offset to byte offset @@ -219,47 +219,16 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, R // Resets EDI to locals. Register sub_klass cannot be any of the above. void InterpreterMacroAssembler::gen_subtype_check( Register Rsub_klass, Label &ok_is_subtype ) { assert( Rsub_klass != rax, "rax, holds superklass" ); - assert( Rsub_klass != rcx, "rcx holds 2ndary super array length" ); - assert( Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr" ); - Label not_subtype, loop; + assert( Rsub_klass != rcx, "used as a temp" ); + assert( Rsub_klass != rdi, "used as a temp, restored from locals" ); // Profile the not-null value's klass. - profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, rdi + profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi - // Load the super-klass's check offset into ECX - movl( rcx, Address(rax, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes() ) ); - // Load from the sub-klass's super-class display list, or a 1-word cache of - // the secondary superclass list, or a failing value with a sentinel offset - // if the super-klass is an interface or exceptionally deep in the Java - // hierarchy and we have to scan the secondary superclass list the hard way. - // See if we get an immediate positive hit - cmpptr( rax, Address(Rsub_klass,rcx,Address::times_1) ); - jcc( Assembler::equal,ok_is_subtype ); + // Do the check. + check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx - // Check for immediate negative hit - cmpl( rcx, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); - jcc( Assembler::notEqual, not_subtype ); - // Check for self - cmpptr( Rsub_klass, rax ); - jcc( Assembler::equal, ok_is_subtype ); - - // Now do a linear scan of the secondary super-klass chain. - movptr( rdi, Address(Rsub_klass, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes()) ); - // EDI holds the objArrayOop of secondary supers. - movl( rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes()));// Load the array length - // Skip to start of data; also clear Z flag incase ECX is zero - addptr( rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT) ); - // Scan ECX words at [EDI] for occurance of EAX - // Set NZ/Z based on last compare - repne_scan(); - restore_locals(); // Restore EDI; Must not blow flags - // Not equal? - jcc( Assembler::notEqual, not_subtype ); - // Must be equal but missed in cache. Update cache. - movptr( Address(Rsub_klass, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()), rax ); - jmp( ok_is_subtype ); - - bind(not_subtype); + // Profile the failure of the check. profile_typecheck_failed(rcx); // blows rcx } @@ -1031,7 +1000,7 @@ void InterpreterMacroAssembler::verify_method_data_pointer() { // If the mdp is valid, it will point to a DataLayout header which is // consistent with the bcp. The converse is highly probable also. - load_unsigned_word(rdx, Address(rcx, in_bytes(DataLayout::bci_offset()))); + load_unsigned_short(rdx, Address(rcx, in_bytes(DataLayout::bci_offset()))); addptr(rdx, Address(rbx, methodOopDesc::const_offset())); lea(rdx, Address(rdx, constMethodOopDesc::codes_offset())); cmpptr(rdx, rsi); @@ -1512,6 +1481,15 @@ void InterpreterMacroAssembler::notify_method_entry() { call_VM_leaf( CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), rcx, rbx); } + + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + get_thread(rcx); + get_method(rbx); + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + rcx, rbx); + } } diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp index 57cd7f325fe..dc6c7bce25c 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp index ebcac0fddf9..56bd0c8c9eb 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -190,7 +190,7 @@ void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, int bcp_offset) { assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); assert(cache != index, "must use different registers"); - load_unsigned_word(index, Address(r13, bcp_offset)); + load_unsigned_short(index, Address(r13, bcp_offset)); movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); // convert from field index to ConstantPoolCacheEntry index @@ -203,7 +203,7 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, int bcp_offset) { assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); assert(cache != tmp, "must use different register"); - load_unsigned_word(tmp, Address(r13, bcp_offset)); + load_unsigned_short(tmp, Address(r13, bcp_offset)); assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); // convert from field index to ConstantPoolCacheEntry index // and from word offset to byte offset @@ -232,65 +232,13 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, assert(Rsub_klass != rcx, "rcx holds 2ndary super array length"); assert(Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr"); - Label not_subtype, not_subtype_pop, loop; - // Profile the not-null value's klass. - profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, rdi + profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi - // Load the super-klass's check offset into rcx - movl(rcx, Address(rax, sizeof(oopDesc) + - Klass::super_check_offset_offset_in_bytes())); - // Load from the sub-klass's super-class display list, or a 1-word - // cache of the secondary superclass list, or a failing value with a - // sentinel offset if the super-klass is an interface or - // exceptionally deep in the Java hierarchy and we have to scan the - // secondary superclass list the hard way. See if we get an - // immediate positive hit - cmpptr(rax, Address(Rsub_klass, rcx, Address::times_1)); - jcc(Assembler::equal,ok_is_subtype); + // Do the check. + check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx - // Check for immediate negative hit - cmpl(rcx, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - jcc( Assembler::notEqual, not_subtype ); - // Check for self - cmpptr(Rsub_klass, rax); - jcc(Assembler::equal, ok_is_subtype); - - // Now do a linear scan of the secondary super-klass chain. - movptr(rdi, Address(Rsub_klass, sizeof(oopDesc) + - Klass::secondary_supers_offset_in_bytes())); - // rdi holds the objArrayOop of secondary supers. - // Load the array length - movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); - // Skip to start of data; also clear Z flag incase rcx is zero - addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - // Scan rcx words at [rdi] for occurance of rax - // Set NZ/Z based on last compare - - // this part is kind tricky, as values in supers array could be 32 or 64 bit wide - // and we store values in objArrays always encoded, thus we need to encode value - // before repne - if (UseCompressedOops) { - push(rax); - encode_heap_oop(rax); - repne_scanl(); - // Not equal? - jcc(Assembler::notEqual, not_subtype_pop); - // restore heap oop here for movq - pop(rax); - } else { - repne_scan(); - jcc(Assembler::notEqual, not_subtype); - } - // Must be equal but missed in cache. Update cache. - movptr(Address(Rsub_klass, sizeof(oopDesc) + - Klass::secondary_super_cache_offset_in_bytes()), rax); - jmp(ok_is_subtype); - - bind(not_subtype_pop); - // restore heap oop here for miss - if (UseCompressedOops) pop(rax); - bind(not_subtype); + // Profile the failure of the check. profile_typecheck_failed(rcx); // blows rcx } @@ -1063,8 +1011,8 @@ void InterpreterMacroAssembler::verify_method_data_pointer() { // If the mdp is valid, it will point to a DataLayout header which is // consistent with the bcp. The converse is highly probable also. - load_unsigned_word(c_rarg2, - Address(c_rarg3, in_bytes(DataLayout::bci_offset()))); + load_unsigned_short(c_rarg2, + Address(c_rarg3, in_bytes(DataLayout::bci_offset()))); addptr(c_rarg2, Address(rbx, methodOopDesc::const_offset())); lea(c_rarg2, Address(c_rarg2, constMethodOopDesc::codes_offset())); cmpptr(c_rarg2, r13); @@ -1593,6 +1541,14 @@ void InterpreterMacroAssembler::notify_method_entry() { call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), r15_thread, c_rarg1); } + + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + get_method(c_rarg1); + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + r15_thread, c_rarg1); + } } diff --git a/hotspot/src/cpu/x86/vm/interpreterRT_x86_32.cpp b/hotspot/src/cpu/x86/vm/interpreterRT_x86_32.cpp index 60af2f45735..2faa99b294c 100644 --- a/hotspot/src/cpu/x86/vm/interpreterRT_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interpreterRT_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/cpu/x86/vm/interpreterRT_x86_64.cpp b/hotspot/src/cpu/x86/vm/interpreterRT_x86_64.cpp index e3c8c6be94b..04f87f3bbab 100644 --- a/hotspot/src/cpu/x86/vm/interpreterRT_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interpreterRT_x86_64.cpp @@ -349,7 +349,7 @@ class SlowSignatureHandler if (_num_args < Argument::n_float_register_parameters_c-1) { *_reg_args++ = from_obj; - *_fp_identifiers |= (0x01 << (_num_args*2)); // mark as float + *_fp_identifiers |= (intptr_t)(0x01 << (_num_args*2)); // mark as float _num_args++; } else { *_to++ = from_obj; @@ -364,7 +364,7 @@ class SlowSignatureHandler if (_num_args < Argument::n_float_register_parameters_c-1) { *_reg_args++ = from_obj; - *_fp_identifiers |= (0x3 << (_num_args*2)); // mark as double + *_fp_identifiers |= (intptr_t)(0x3 << (_num_args*2)); // mark as double _num_args++; } else { *_to++ = from_obj; diff --git a/hotspot/src/cpu/x86/vm/jni_x86.h b/hotspot/src/cpu/x86/vm/jni_x86.h index 625562bb3f2..3156a94aa92 100644 --- a/hotspot/src/cpu/x86/vm/jni_x86.h +++ b/hotspot/src/cpu/x86/vm/jni_x86.h @@ -1,5 +1,5 @@ /* - * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp b/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp index 6a92a2c053e..5a0de22f475 100644 --- a/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 3cf22d7fa05..de240202957 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1534,6 +1534,13 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, thread, rax); } + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + __ movoop(rax, JNIHandles::make_local(method())); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + thread, rax); + } // These are register definitions we need for locking/unlocking const Register swap_reg = rax; // Must use rax, for cmpxchg instruction diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 7fc2b6685e4..57fa4a480ca 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1350,7 +1350,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, { Label L; __ mov(rax, rsp); - __ andptr(rax, -16); // must be 16 byte boundry (see amd64 ABI) + __ andptr(rax, -16); // must be 16 byte boundary (see amd64 ABI) __ cmpptr(rax, rsp); __ jcc(Assembler::equal, L); __ stop("improperly aligned stack"); @@ -1508,6 +1508,17 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, restore_args(masm, total_c_args, c_arg, out_regs); } + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + // protect the args we've loaded + save_args(masm, total_c_args, c_arg, out_regs); + __ movoop(c_rarg1, JNIHandles::make_local(method())); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + r15_thread, c_rarg1); + restore_args(masm, total_c_args, c_arg, out_regs); + } + // Lock a synchronized method // Register definitions used by locking and unlocking @@ -2680,7 +2691,7 @@ void SharedRuntime::generate_deopt_blob() { __ mov(rdi, rax); Label noException; - __ cmpl(r12, Deoptimization::Unpack_exception); // Was exception pending? + __ cmpl(r14, Deoptimization::Unpack_exception); // Was exception pending? __ jcc(Assembler::notEqual, noException); __ movptr(rax, Address(r15_thread, JavaThread::exception_oop_offset())); // QQQ this is useless it was NULL above diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp index 9b220e20449..aca93778050 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1310,81 +1310,51 @@ class StubGenerator: public StubCodeGenerator { Address& super_check_offset_addr, Address& super_klass_addr, Register temp, - Label* L_success_ptr, Label* L_failure_ptr) { + Label* L_success, Label* L_failure) { BLOCK_COMMENT("type_check:"); Label L_fallthrough; - bool fall_through_on_success = (L_success_ptr == NULL); - if (fall_through_on_success) { - L_success_ptr = &L_fallthrough; - } else { - L_failure_ptr = &L_fallthrough; - } - Label& L_success = *L_success_ptr; - Label& L_failure = *L_failure_ptr; +#define LOCAL_JCC(assembler_con, label_ptr) \ + if (label_ptr != NULL) __ jcc(assembler_con, *(label_ptr)); \ + else __ jcc(assembler_con, L_fallthrough) /*omit semi*/ + // The following is a strange variation of the fast path which requires + // one less register, because needed values are on the argument stack. + // __ check_klass_subtype_fast_path(sub_klass, *super_klass*, temp, + // L_success, L_failure, NULL); assert_different_registers(sub_klass, temp); - // a couple of useful fields in sub_klass: - int ss_offset = (klassOopDesc::header_size() * HeapWordSize + - Klass::secondary_supers_offset_in_bytes()); int sc_offset = (klassOopDesc::header_size() * HeapWordSize + Klass::secondary_super_cache_offset_in_bytes()); - Address secondary_supers_addr(sub_klass, ss_offset); - Address super_cache_addr( sub_klass, sc_offset); // if the pointers are equal, we are done (e.g., String[] elements) __ cmpptr(sub_klass, super_klass_addr); - __ jcc(Assembler::equal, L_success); + LOCAL_JCC(Assembler::equal, L_success); // check the supertype display: __ movl2ptr(temp, super_check_offset_addr); Address super_check_addr(sub_klass, temp, Address::times_1, 0); __ movptr(temp, super_check_addr); // load displayed supertype __ cmpptr(temp, super_klass_addr); // test the super type - __ jcc(Assembler::equal, L_success); + LOCAL_JCC(Assembler::equal, L_success); // if it was a primary super, we can just fail immediately __ cmpl(super_check_offset_addr, sc_offset); - __ jcc(Assembler::notEqual, L_failure); + LOCAL_JCC(Assembler::notEqual, L_failure); - // Now do a linear scan of the secondary super-klass chain. - // This code is rarely used, so simplicity is a virtue here. - inc_counter_np(SharedRuntime::_partial_subtype_ctr); - { - // The repne_scan instruction uses fixed registers, which we must spill. - // (We need a couple more temps in any case.) - __ push(rax); - __ push(rcx); - __ push(rdi); - assert_different_registers(sub_klass, rax, rcx, rdi); + // The repne_scan instruction uses fixed registers, which will get spilled. + // We happen to know this works best when super_klass is in rax. + Register super_klass = temp; + __ movptr(super_klass, super_klass_addr); + __ check_klass_subtype_slow_path(sub_klass, super_klass, noreg, noreg, + L_success, L_failure); - __ movptr(rdi, secondary_supers_addr); - // Load the array length. - __ movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); - // Skip to start of data. - __ addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - // Scan rcx words at [edi] for occurance of rax, - // Set NZ/Z based on last compare - __ movptr(rax, super_klass_addr); - __ repne_scan(); - - // Unspill the temp. registers: - __ pop(rdi); - __ pop(rcx); - __ pop(rax); - } - __ jcc(Assembler::notEqual, L_failure); - - // Success. Cache the super we found and proceed in triumph. - __ movptr(temp, super_klass_addr); // note: rax, is dead - __ movptr(super_cache_addr, temp); - - if (!fall_through_on_success) - __ jmp(L_success); - - // Fall through on failure! __ bind(L_fallthrough); + + if (L_success == NULL) { BLOCK_COMMENT("L_success:"); } + if (L_failure == NULL) { BLOCK_COMMENT("L_failure:"); } + +#undef LOCAL_JCC } // diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 6c2fb5694e8..ec322b527d1 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -637,7 +637,7 @@ class StubGenerator: public StubCodeGenerator { address generate_orderaccess_fence() { StubCodeMark mark(this, "StubRoutines", "orderaccess_fence"); address start = __ pc(); - __ mfence(); + __ membar(Assembler::StoreLoad); __ ret(0); return start; @@ -2091,66 +2091,9 @@ class StubGenerator: public StubCodeGenerator { Label L_miss; - // a couple of useful fields in sub_klass: - int ss_offset = (klassOopDesc::header_size() * HeapWordSize + - Klass::secondary_supers_offset_in_bytes()); - int sc_offset = (klassOopDesc::header_size() * HeapWordSize + - Klass::secondary_super_cache_offset_in_bytes()); - Address secondary_supers_addr(sub_klass, ss_offset); - Address super_cache_addr( sub_klass, sc_offset); - - // if the pointers are equal, we are done (e.g., String[] elements) - __ cmpptr(super_klass, sub_klass); - __ jcc(Assembler::equal, L_success); - - // check the supertype display: - Address super_check_addr(sub_klass, super_check_offset, Address::times_1, 0); - __ cmpptr(super_klass, super_check_addr); // test the super type - __ jcc(Assembler::equal, L_success); - - // if it was a primary super, we can just fail immediately - __ cmpl(super_check_offset, sc_offset); - __ jcc(Assembler::notEqual, L_miss); - - // Now do a linear scan of the secondary super-klass chain. - // The repne_scan instruction uses fixed registers, which we must spill. - // (We need a couple more temps in any case.) - // This code is rarely used, so simplicity is a virtue here. - inc_counter_np(SharedRuntime::_partial_subtype_ctr); - { - __ push(rax); - __ push(rcx); - __ push(rdi); - assert_different_registers(sub_klass, super_klass, rax, rcx, rdi); - - __ movptr(rdi, secondary_supers_addr); - // Load the array length. - __ movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); - // Skip to start of data. - __ addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - // Scan rcx words at [rdi] for occurance of rax - // Set NZ/Z based on last compare - __ movptr(rax, super_klass); - if (UseCompressedOops) { - // Compare against compressed form. Don't need to uncompress because - // looks like orig rax is restored in popq below. - __ encode_heap_oop(rax); - __ repne_scanl(); - } else { - __ repne_scan(); - } - - // Unspill the temp. registers: - __ pop(rdi); - __ pop(rcx); - __ pop(rax); - - __ jcc(Assembler::notEqual, L_miss); - } - - // Success. Cache the super we found and proceed in triumph. - __ movptr(super_cache_addr, super_klass); // note: rax is dead - __ jmp(L_success); + __ check_klass_subtype_fast_path(sub_klass, super_klass, noreg, &L_success, &L_miss, NULL, + super_check_offset); + __ check_klass_subtype_slow_path(sub_klass, super_klass, noreg, noreg, &L_success, NULL); // Fall through on failure! __ BIND(L_miss); diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index ed40fb70124..8d94671e6be 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -662,13 +662,13 @@ address InterpreterGenerator::generate_accessor_entry(void) { __ bind(notByte); __ cmpl(rdx, stos); __ jcc(Assembler::notEqual, notShort); - __ load_signed_word(rax, field_address); + __ load_signed_short(rax, field_address); __ jmp(xreturn_path); __ bind(notShort); __ cmpl(rdx, ctos); __ jcc(Assembler::notEqual, notChar); - __ load_unsigned_word(rax, field_address); + __ load_unsigned_short(rax, field_address); __ jmp(xreturn_path); __ bind(notChar); @@ -723,7 +723,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { const Address access_flags (rbx, methodOopDesc::access_flags_offset()); // get parameter size (always needed) - __ load_unsigned_word(rcx, size_of_parameters); + __ load_unsigned_short(rcx, size_of_parameters); // native calls don't need the stack size check since they have no expression stack // and the arguments are already on the stack and we only add a handful of words @@ -838,7 +838,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // allocate space for parameters __ get_method(method); __ verify_oop(method); - __ load_unsigned_word(t, Address(method, methodOopDesc::size_of_parameters_offset())); + __ load_unsigned_short(t, Address(method, methodOopDesc::size_of_parameters_offset())); __ shlptr(t, Interpreter::logStackElementSize()); __ addptr(t, 2*wordSize); // allocate two more slots for JNIEnv and possible mirror __ subptr(rsp, t); @@ -1155,14 +1155,14 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { const Address access_flags (rbx, methodOopDesc::access_flags_offset()); // get parameter size (always needed) - __ load_unsigned_word(rcx, size_of_parameters); + __ load_unsigned_short(rcx, size_of_parameters); // rbx,: methodOop // rcx: size of parameters // rsi: sender_sp (could differ from sp+wordSize if we were called via c2i ) - __ load_unsigned_word(rdx, size_of_locals); // get size of locals in words + __ load_unsigned_short(rdx, size_of_locals); // get size of locals in words __ subl(rdx, rcx); // rdx = no. of additional locals // see if we've got enough room on the stack for locals plus overhead. @@ -1558,7 +1558,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // Compute size of arguments for saving when returning to deoptimized caller __ get_method(rax); __ verify_oop(rax); - __ load_unsigned_word(rax, Address(rax, in_bytes(methodOopDesc::size_of_parameters_offset()))); + __ load_unsigned_short(rax, Address(rax, in_bytes(methodOopDesc::size_of_parameters_offset()))); __ shlptr(rax, Interpreter::logStackElementSize()); __ restore_locals(); __ subptr(rdi, rax); diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 9caf33f6b09..330dce0c51b 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -650,7 +650,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { __ cmpl(rdx, stos); __ jcc(Assembler::notEqual, notShort); // stos - __ load_signed_word(rax, field_address); + __ load_signed_short(rax, field_address); __ jmp(xreturn_path); __ bind(notShort); @@ -662,7 +662,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { __ bind(okay); #endif // ctos - __ load_unsigned_word(rax, field_address); + __ load_unsigned_short(rax, field_address); __ bind(xreturn_path); @@ -702,7 +702,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { const Address access_flags (rbx, methodOopDesc::access_flags_offset()); // get parameter size (always needed) - __ load_unsigned_word(rcx, size_of_parameters); + __ load_unsigned_short(rcx, size_of_parameters); // native calls don't need the stack size check since they have no // expression stack and the arguments are already on the stack and @@ -819,14 +819,14 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // allocate space for parameters __ get_method(method); __ verify_oop(method); - __ load_unsigned_word(t, - Address(method, - methodOopDesc::size_of_parameters_offset())); + __ load_unsigned_short(t, + Address(method, + methodOopDesc::size_of_parameters_offset())); __ shll(t, Interpreter::logStackElementSize()); __ subptr(rsp, t); __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows - __ andptr(rsp, -16); // must be 16 byte boundry (see amd64 ABI) + __ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI) // get signature handler { @@ -1165,13 +1165,13 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { const Address access_flags(rbx, methodOopDesc::access_flags_offset()); // get parameter size (always needed) - __ load_unsigned_word(rcx, size_of_parameters); + __ load_unsigned_short(rcx, size_of_parameters); // rbx: methodOop // rcx: size of parameters // r13: sender_sp (could differ from sp+wordSize if we were called via c2i ) - __ load_unsigned_word(rdx, size_of_locals); // get size of locals in words + __ load_unsigned_short(rdx, size_of_locals); // get size of locals in words __ subl(rdx, rcx); // rdx = no. of additional locals // YYY @@ -1583,7 +1583,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // Compute size of arguments for saving when returning to // deoptimized caller __ get_method(rax); - __ load_unsigned_word(rax, Address(rax, in_bytes(methodOopDesc:: + __ load_unsigned_short(rax, Address(rax, in_bytes(methodOopDesc:: size_of_parameters_offset()))); __ shll(rax, Interpreter::logStackElementSize()); __ restore_locals(); // XXX do we need this? diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp index 13242651c7e..7c40e41af92 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -296,7 +296,7 @@ void TemplateTable::bipush() { void TemplateTable::sipush() { transition(vtos, itos); - __ load_unsigned_word(rax, at_bcp(1)); + __ load_unsigned_short(rax, at_bcp(1)); __ bswapl(rax); __ sarl(rax, 16); } @@ -662,7 +662,7 @@ void TemplateTable::caload() { index_check(rdx, rax); // kills rbx, // rax,: index // can do better code for P5 - may want to improve this at some point - __ load_unsigned_word(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR))); + __ load_unsigned_short(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR))); __ mov(rax, rbx); } @@ -677,7 +677,7 @@ void TemplateTable::fast_icaload() { // rdx: array index_check(rdx, rax); // rax,: index - __ load_unsigned_word(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR))); + __ load_unsigned_short(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR))); __ mov(rax, rbx); } @@ -687,7 +687,7 @@ void TemplateTable::saload() { index_check(rdx, rax); // kills rbx, // rax,: index // can do better code for P5 - may want to improve this at some point - __ load_signed_word(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_SHORT))); + __ load_signed_short(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_SHORT))); __ mov(rax, rbx); } @@ -1586,7 +1586,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Handle all the JSR stuff here, then exit. // It's much shorter and cleaner than intermingling with the - // non-JSR normal-branch stuff occuring below. + // non-JSR normal-branch stuff occurring below. if (is_jsr) { // Pre-load the next target bytecode into EBX __ load_unsigned_byte(rbx, Address(rsi, rdx, Address::times_1, 0)); @@ -2310,7 +2310,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) { __ cmpl(flags, ctos ); __ jcc(Assembler::notEqual, notChar); - __ load_unsigned_word(rax, lo ); + __ load_unsigned_short(rax, lo ); __ push(ctos); if (!is_static) { patch_bytecode(Bytecodes::_fast_cgetfield, rcx, rbx); @@ -2322,7 +2322,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) { __ cmpl(flags, stos ); __ jcc(Assembler::notEqual, notShort); - __ load_signed_word(rax, lo ); + __ load_signed_short(rax, lo ); __ push(stos); if (!is_static) { patch_bytecode(Bytecodes::_fast_sgetfield, rcx, rbx); @@ -2830,8 +2830,8 @@ void TemplateTable::fast_accessfield(TosState state) { // access field switch (bytecode()) { case Bytecodes::_fast_bgetfield: __ movsbl(rax, lo ); break; - case Bytecodes::_fast_sgetfield: __ load_signed_word(rax, lo ); break; - case Bytecodes::_fast_cgetfield: __ load_unsigned_word(rax, lo ); break; + case Bytecodes::_fast_sgetfield: __ load_signed_short(rax, lo ); break; + case Bytecodes::_fast_cgetfield: __ load_unsigned_short(rax, lo ); break; case Bytecodes::_fast_igetfield: __ movl(rax, lo); break; case Bytecodes::_fast_lgetfield: __ stop("should not be rewritten"); break; case Bytecodes::_fast_fgetfield: __ fld_s(lo); break; @@ -3055,35 +3055,44 @@ void TemplateTable::invokeinterface(int byte_no) { // profile this call __ profile_virtual_call(rdx, rsi, rdi); - __ mov(rdi, rdx); // Save klassOop in rdi + Label no_such_interface, no_such_method; - // Compute start of first itableOffsetEntry (which is at the end of the vtable) - const int base = instanceKlass::vtable_start_offset() * wordSize; - assert(vtableEntry::size() * wordSize == (1 << (int)Address::times_ptr), "adjust the scaling in the code below"); - __ movl(rsi, Address(rdx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable - __ lea(rdx, Address(rdx, rsi, Address::times_4, base)); - if (HeapWordsPerLong > 1) { - // Round up to align_object_offset boundary - __ round_to(rdx, BytesPerLong); - } + __ lookup_interface_method(// inputs: rec. class, interface, itable index + rdx, rax, rbx, + // outputs: method, scan temp. reg + rbx, rsi, + no_such_interface); - Label entry, search, interface_ok; + // rbx,: methodOop to call + // rcx: receiver + // Check for abstract method error + // Note: This should be done more efficiently via a throw_abstract_method_error + // interpreter entry point and a conditional jump to it in case of a null + // method. + __ testptr(rbx, rbx); + __ jcc(Assembler::zero, no_such_method); - __ jmpb(entry); - __ bind(search); - __ addptr(rdx, itableOffsetEntry::size() * wordSize); + // do the call + // rcx: receiver + // rbx,: methodOop + __ jump_from_interpreted(rbx, rdx); + __ should_not_reach_here(); - __ bind(entry); + // exception handling code follows... + // note: must restore interpreter registers to canonical + // state for exception handling to work correctly! - // Check that the entry is non-null. A null entry means that the receiver - // class doesn't implement the interface, and wasn't the same as the - // receiver class checked when the interface was resolved. - __ push(rdx); - __ movptr(rdx, Address(rdx, itableOffsetEntry::interface_offset_in_bytes())); - __ testptr(rdx, rdx); - __ jcc(Assembler::notZero, interface_ok); + __ bind(no_such_method); + // throw exception + __ pop(rbx); // pop return address (pushed by prepare_invoke) + __ restore_bcp(); // rsi must be correct for exception handler (was destroyed) + __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + + __ bind(no_such_interface); // throw exception - __ pop(rdx); // pop saved register first. __ pop(rbx); // pop return address (pushed by prepare_invoke) __ restore_bcp(); // rsi must be correct for exception handler (was destroyed) __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) @@ -3091,42 +3100,6 @@ void TemplateTable::invokeinterface(int byte_no) { InterpreterRuntime::throw_IncompatibleClassChangeError)); // the call_VM checks for exception, so we should never return here. __ should_not_reach_here(); - __ bind(interface_ok); - - __ pop(rdx); - - __ cmpptr(rax, Address(rdx, itableOffsetEntry::interface_offset_in_bytes())); - __ jcc(Assembler::notEqual, search); - - __ movl(rdx, Address(rdx, itableOffsetEntry::offset_offset_in_bytes())); - __ addptr(rdx, rdi); // Add offset to klassOop - assert(itableMethodEntry::size() * wordSize == (1 << (int)Address::times_ptr), "adjust the scaling in the code below"); - __ movptr(rbx, Address(rdx, rbx, Address::times_ptr)); - // rbx,: methodOop to call - // rcx: receiver - // Check for abstract method error - // Note: This should be done more efficiently via a throw_abstract_method_error - // interpreter entry point and a conditional jump to it in case of a null - // method. - { Label L; - __ testptr(rbx, rbx); - __ jcc(Assembler::notZero, L); - // throw exception - // note: must restore interpreter registers to canonical - // state for exception handling to work correctly! - __ pop(rbx); // pop return address (pushed by prepare_invoke) - __ restore_bcp(); // rsi must be correct for exception handler (was destroyed) - __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); - // the call_VM checks for exception, so we should never return here. - __ should_not_reach_here(); - __ bind(L); - } - - // do the call - // rcx: receiver - // rbx,: methodOop - __ jump_from_interpreted(rbx, rdx); } //---------------------------------------------------------------------------------------------------- diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp index e4b4cb96980..048b8bb1176 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -307,7 +307,7 @@ void TemplateTable::bipush() { void TemplateTable::sipush() { transition(vtos, itos); - __ load_unsigned_word(rax, at_bcp(1)); + __ load_unsigned_short(rax, at_bcp(1)); __ bswapl(rax); __ sarl(rax, 16); } @@ -645,10 +645,10 @@ void TemplateTable::caload() { // eax: index // rdx: array index_check(rdx, rax); // kills rbx - __ load_unsigned_word(rax, - Address(rdx, rax, - Address::times_2, - arrayOopDesc::base_offset_in_bytes(T_CHAR))); + __ load_unsigned_short(rax, + Address(rdx, rax, + Address::times_2, + arrayOopDesc::base_offset_in_bytes(T_CHAR))); } // iload followed by caload frequent pair @@ -663,10 +663,10 @@ void TemplateTable::fast_icaload() { // rdx: array __ pop_ptr(rdx); index_check(rdx, rax); // kills rbx - __ load_unsigned_word(rax, - Address(rdx, rax, - Address::times_2, - arrayOopDesc::base_offset_in_bytes(T_CHAR))); + __ load_unsigned_short(rax, + Address(rdx, rax, + Address::times_2, + arrayOopDesc::base_offset_in_bytes(T_CHAR))); } void TemplateTable::saload() { @@ -675,10 +675,10 @@ void TemplateTable::saload() { // eax: index // rdx: array index_check(rdx, rax); // kills rbx - __ load_signed_word(rax, - Address(rdx, rax, - Address::times_2, - arrayOopDesc::base_offset_in_bytes(T_SHORT))); + __ load_signed_short(rax, + Address(rdx, rax, + Address::times_2, + arrayOopDesc::base_offset_in_bytes(T_SHORT))); } void TemplateTable::iload(int n) { @@ -1559,7 +1559,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Handle all the JSR stuff here, then exit. // It's much shorter and cleaner than intermingling with the non-JSR - // normal-branch stuff occuring below. + // normal-branch stuff occurring below. if (is_jsr) { // Pre-load the next target bytecode into rbx __ load_unsigned_byte(rbx, Address(r13, rdx, Address::times_1, 0)); @@ -2276,7 +2276,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) { __ cmpl(flags, ctos); __ jcc(Assembler::notEqual, notChar); // ctos - __ load_unsigned_word(rax, field); + __ load_unsigned_short(rax, field); __ push(ctos); // Rewrite bytecode to be faster if (!is_static) { @@ -2288,7 +2288,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) { __ cmpl(flags, stos); __ jcc(Assembler::notEqual, notShort); // stos - __ load_signed_word(rax, field); + __ load_signed_short(rax, field); __ push(stos); // Rewrite bytecode to be faster if (!is_static) { @@ -2751,10 +2751,10 @@ void TemplateTable::fast_accessfield(TosState state) { __ movsbl(rax, field); break; case Bytecodes::_fast_sgetfield: - __ load_signed_word(rax, field); + __ load_signed_short(rax, field); break; case Bytecodes::_fast_cgetfield: - __ load_unsigned_word(rax, field); + __ load_unsigned_short(rax, field); break; case Bytecodes::_fast_fgetfield: __ movflt(xmm0, field); @@ -3010,97 +3010,55 @@ void TemplateTable::invokeinterface(int byte_no) { // profile this call __ profile_virtual_call(rdx, r13, r14); - __ mov(r14, rdx); // Save klassOop in r14 + Label no_such_interface, no_such_method; - // Compute start of first itableOffsetEntry (which is at the end of - // the vtable) - const int base = instanceKlass::vtable_start_offset() * wordSize; - // Get length of vtable - assert(vtableEntry::size() * wordSize == 8, - "adjust the scaling in the code below"); - __ movl(r13, Address(rdx, - instanceKlass::vtable_length_offset() * wordSize)); - __ lea(rdx, Address(rdx, r13, Address::times_8, base)); + __ lookup_interface_method(// inputs: rec. class, interface, itable index + rdx, rax, rbx, + // outputs: method, scan temp. reg + rbx, r13, + no_such_interface); - if (HeapWordsPerLong > 1) { - // Round up to align_object_offset boundary - __ round_to(rdx, BytesPerLong); - } + // rbx,: methodOop to call + // rcx: receiver + // Check for abstract method error + // Note: This should be done more efficiently via a throw_abstract_method_error + // interpreter entry point and a conditional jump to it in case of a null + // method. + __ testptr(rbx, rbx); + __ jcc(Assembler::zero, no_such_method); - Label entry, search, interface_ok; + // do the call + // rcx: receiver + // rbx,: methodOop + __ jump_from_interpreted(rbx, rdx); + __ should_not_reach_here(); - __ jmpb(entry); - __ bind(search); - __ addptr(rdx, itableOffsetEntry::size() * wordSize); + // exception handling code follows... + // note: must restore interpreter registers to canonical + // state for exception handling to work correctly! - __ bind(entry); - - // Check that the entry is non-null. A null entry means that the - // receiver class doesn't implement the interface, and wasn't the - // same as the receiver class checked when the interface was - // resolved. - __ push(rdx); - __ movptr(rdx, Address(rdx, itableOffsetEntry::interface_offset_in_bytes())); - __ testptr(rdx, rdx); - __ jcc(Assembler::notZero, interface_ok); + __ bind(no_such_method); // throw exception - __ pop(rdx); // pop saved register first. - __ pop(rbx); // pop return address (pushed by prepare_invoke) - __ restore_bcp(); // r13 must be correct for exception handler (was - // destroyed) - __ restore_locals(); // make sure locals pointer is correct as well - // (was destroyed) + __ pop(rbx); // pop return address (pushed by prepare_invoke) + __ restore_bcp(); // r13 must be correct for exception handler (was destroyed) + __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + + __ bind(no_such_interface); + // throw exception + __ pop(rbx); // pop return address (pushed by prepare_invoke) + __ restore_bcp(); // r13 must be correct for exception handler (was destroyed) + __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); // the call_VM checks for exception, so we should never return here. __ should_not_reach_here(); - __ bind(interface_ok); - - __ pop(rdx); - - __ cmpptr(rax, Address(rdx, itableOffsetEntry::interface_offset_in_bytes())); - __ jcc(Assembler::notEqual, search); - - __ movl(rdx, Address(rdx, itableOffsetEntry::offset_offset_in_bytes())); - - __ addptr(rdx, r14); // Add offset to klassOop - assert(itableMethodEntry::size() * wordSize == 8, - "adjust the scaling in the code below"); - __ movptr(rbx, Address(rdx, rbx, Address::times_8)); - // rbx: methodOop to call - // rcx: receiver - // Check for abstract method error - // Note: This should be done more efficiently via a - // throw_abstract_method_error interpreter entry point and a - // conditional jump to it in case of a null method. - { - Label L; - __ testptr(rbx, rbx); - __ jcc(Assembler::notZero, L); - // throw exception - // note: must restore interpreter registers to canonical - // state for exception handling to work correctly! - __ pop(rbx); // pop return address (pushed by prepare_invoke) - __ restore_bcp(); // r13 must be correct for exception handler - // (was destroyed) - __ restore_locals(); // make sure locals pointer is correct as - // well (was destroyed) - __ call_VM(noreg, - CAST_FROM_FN_PTR(address, - InterpreterRuntime::throw_AbstractMethodError)); - // the call_VM checks for exception, so we should never return here. - __ should_not_reach_here(); - __ bind(L); - } - - __ movptr(rcx, Address(rbx, methodOopDesc::interpreter_entry_offset())); - - // do the call - // rcx: receiver - // rbx: methodOop - __ jump_from_interpreted(rbx, rdx); + return; } + //----------------------------------------------------------------------------- // Allocation diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86_32.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp similarity index 89% rename from hotspot/src/cpu/x86/vm/vm_version_x86_32.cpp rename to hotspot/src/cpu/x86/vm/vm_version_x86.cpp index edd1da4e31f..ccf6b429282 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ */ # include "incls/_precompiled.incl" -# include "incls/_vm_version_x86_32.cpp.incl" +# include "incls/_vm_version_x86.cpp.incl" int VM_Version::_cpu; @@ -67,8 +67,14 @@ class VM_Version_StubGenerator: public StubCodeGenerator { // // void getPsrInfo(VM_Version::CpuidInfo* cpuid_info); // + // LP64: rcx and rdx are first and second argument registers on windows + __ push(rbp); +#ifdef _LP64 + __ mov(rbp, c_rarg0); // cpuid_info address +#else __ movptr(rbp, Address(rsp, 8)); // cpuid_info address +#endif __ push(rbx); __ push(rsi); __ pushf(); // preserve rbx, and flags @@ -110,12 +116,12 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ jmp(done); // - // at this point, we have a chip which supports the "cpuid" instruction + // At this point, we have a chip which supports the "cpuid" instruction // __ bind(detect_586); - __ xorptr(rax, rax); + __ xorl(rax, rax); __ cpuid(); - __ orptr(rax, rax); + __ orl(rax, rax); __ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input // value of at least 1, we give up and // assume a 486 @@ -131,12 +137,12 @@ class VM_Version_StubGenerator: public StubCodeGenerator { // // cpuid(0x4) Deterministic cache params // - __ movl(rax, 4); // and rcx already set to 0x0 - __ xorl(rcx, rcx); + __ movl(rax, 4); + __ xorl(rcx, rcx); // L1 cache __ cpuid(); __ push(rax); __ andl(rax, 0x1f); // Determine if valid cache parameters used - __ orl(rax, rax); // rax,[4:0] == 0 indicates invalid cache + __ orl(rax, rax); // eax[4:0] == 0 indicates invalid cache __ pop(rax); __ jccb(Assembler::equal, std_cpuid1); @@ -225,6 +231,7 @@ void VM_Version::get_processor_features() { _stepping = 0; _cpuFeatures = 0; _logical_processors_per_package = 1; + if (!Use486InstrsOnly) { // Get raw processor info getPsrInfo_stub(&_cpuid_info); @@ -232,6 +239,7 @@ void VM_Version::get_processor_features() { _cpu = extended_cpu_family(); _model = extended_cpu_model(); _stepping = cpu_stepping(); + if (cpu_family() > 4) { // it supports CPUID _cpuFeatures = feature_flags(); // Logical processors are only available on P4s and above, @@ -239,21 +247,34 @@ void VM_Version::get_processor_features() { _logical_processors_per_package = logical_processor_count(); } } + _supports_cx8 = supports_cmpxchg8(); - // if the OS doesn't support SSE, we can't use this feature even if the HW does - if( !os::supports_sse()) + +#ifdef _LP64 + // OS should support SSE for x64 and hardware should support at least SSE2. + if (!VM_Version::supports_sse2()) { + vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported"); + } +#endif + + // If the OS doesn't support SSE, we can't use this feature even if the HW does + if (!os::supports_sse()) _cpuFeatures &= ~(CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE4A|CPU_SSE4_1|CPU_SSE4_2); + if (UseSSE < 4) { _cpuFeatures &= ~CPU_SSE4_1; _cpuFeatures &= ~CPU_SSE4_2; } + if (UseSSE < 3) { _cpuFeatures &= ~CPU_SSE3; _cpuFeatures &= ~CPU_SSSE3; _cpuFeatures &= ~CPU_SSE4A; } + if (UseSSE < 2) _cpuFeatures &= ~CPU_SSE2; + if (UseSSE < 1) _cpuFeatures &= ~CPU_SSE; @@ -263,7 +284,7 @@ void VM_Version::get_processor_features() { } char buf[256]; - jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, (supports_cmov() ? ", cmov" : ""), @@ -276,6 +297,7 @@ void VM_Version::get_processor_features() { (supports_ssse3()? ", ssse3": ""), (supports_sse4_1() ? ", sse4.1" : ""), (supports_sse4_2() ? ", sse4.2" : ""), + (supports_popcnt() ? ", popcnt" : ""), (supports_mmx_ext() ? ", mmxext" : ""), (supports_3dnow() ? ", 3dnow" : ""), (supports_3dnow2() ? ", 3dnowext" : ""), @@ -386,6 +408,18 @@ void VM_Version::get_processor_features() { UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus } } + if( supports_sse4_2() && UseSSE >= 4 ) { + if( FLAG_IS_DEFAULT(UseSSE42Intrinsics)) { + UseSSE42Intrinsics = true; + } + } + } + } + + // Use population count instruction if available. + if (supports_popcnt()) { + if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { + UsePopCountInstruction = true; } } @@ -418,10 +452,21 @@ void VM_Version::get_processor_features() { if( AllocatePrefetchStyle == 2 && is_intel() && cpu_family() == 6 && supports_sse3() ) { // watermark prefetching on Core +#ifdef _LP64 + AllocatePrefetchDistance = 384; +#else AllocatePrefetchDistance = 320; +#endif } assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value"); +#ifdef _LP64 + // Prefetch settings + PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes(); + PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes(); + PrefetchFieldsAhead = prefetch_fields_ahead(); +#endif + #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("Logical CPUs per core: %u", @@ -450,6 +495,16 @@ void VM_Version::get_processor_features() { tty->print_cr(" %d, one line", AllocatePrefetchDistance); } } + + if (PrefetchCopyIntervalInBytes > 0) { + tty->print_cr("PrefetchCopyIntervalInBytes %d", PrefetchCopyIntervalInBytes); + } + if (PrefetchScanIntervalInBytes > 0) { + tty->print_cr("PrefetchScanIntervalInBytes %d", PrefetchScanIntervalInBytes); + } + if (PrefetchFieldsAhead > 0) { + tty->print_cr("PrefetchFieldsAhead %d", PrefetchFieldsAhead); + } } #endif // !PRODUCT } diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86_64.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp similarity index 90% rename from hotspot/src/cpu/x86/vm/vm_version_x86_64.hpp rename to hotspot/src/cpu/x86/vm/vm_version_x86.hpp index 43492f5fb16..7b6206b0e32 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86_64.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,7 +70,9 @@ public: dca : 1, sse4_1 : 1, sse4_2 : 1, - : 11; + : 2, + popcnt : 1, + : 8; } bits; }; @@ -112,20 +114,6 @@ public: } bits; }; - union ExtCpuid1Edx { - uint32_t value; - struct { - uint32_t : 22, - mmx_amd : 1, - mmx : 1, - fxsr : 1, - : 4, - long_mode : 1, - tdnow2 : 1, - tdnow : 1; - } bits; - }; - union ExtCpuid1Ecx { uint32_t value; struct { @@ -140,6 +128,20 @@ public: } bits; }; + union ExtCpuid1Edx { + uint32_t value; + struct { + uint32_t : 22, + mmx_amd : 1, + mmx : 1, + fxsr : 1, + : 4, + long_mode : 1, + tdnow2 : 1, + tdnow : 1; + } bits; + }; + union ExtCpuid5Ex { uint32_t value; struct { @@ -167,19 +169,20 @@ protected: static const char* _features_str; enum { - CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX) - CPU_CMOV = (1 << 1), - CPU_FXSR = (1 << 2), - CPU_HT = (1 << 3), - CPU_MMX = (1 << 4), - CPU_3DNOW= (1 << 5), - CPU_SSE = (1 << 6), - CPU_SSE2 = (1 << 7), - CPU_SSE3 = (1 << 8), - CPU_SSSE3= (1 << 9), - CPU_SSE4A= (1 <<10), + CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX) + CPU_CMOV = (1 << 1), + CPU_FXSR = (1 << 2), + CPU_HT = (1 << 3), + CPU_MMX = (1 << 4), + CPU_3DNOW = (1 << 5), // 3DNow comes from cpuid 0x80000001 (EDX) + CPU_SSE = (1 << 6), + CPU_SSE2 = (1 << 7), + CPU_SSE3 = (1 << 8), // SSE3 comes from cpuid 1 (ECX) + CPU_SSSE3 = (1 << 9), + CPU_SSE4A = (1 << 10), CPU_SSE4_1 = (1 << 11), - CPU_SSE4_2 = (1 << 12) + CPU_SSE4_2 = (1 << 12), + CPU_POPCNT = (1 << 13) } cpuFeatureFlags; // cpuid information block. All info derived from executing cpuid with @@ -290,6 +293,8 @@ protected: result |= CPU_SSE4_1; if (_cpuid_info.std_cpuid1_ecx.bits.sse4_2 != 0) result |= CPU_SSE4_2; + if (_cpuid_info.std_cpuid1_ecx.bits.popcnt != 0) + result |= CPU_POPCNT; return result; } @@ -360,7 +365,7 @@ public: result = _cpuid_info.ext_cpuid5_ecx.bits.L1_line_size; } if (result < 32) // not defined ? - result = 32; // 32 bytes by default for other x64 + result = 32; // 32 bytes by default on x86 and other x64 return result; } @@ -379,6 +384,7 @@ public: static bool supports_ssse3() { return (_cpuFeatures & CPU_SSSE3)!= 0; } static bool supports_sse4_1() { return (_cpuFeatures & CPU_SSE4_1) != 0; } static bool supports_sse4_2() { return (_cpuFeatures & CPU_SSE4_2) != 0; } + static bool supports_popcnt() { return (_cpuFeatures & CPU_POPCNT) != 0; } // // AMD features // @@ -395,26 +401,36 @@ public: // This method should be called before allocate_prefetch_style(). // // Hardware prefetching (distance/size in bytes): + // Pentium 3 - 64 / 32 // Pentium 4 - 256 / 128 + // Athlon - 64 / 32 ???? // Opteron - 128 / 64 only when 2 sequential cache lines accessed // Core - 128 / 64 // // Software prefetching (distance in bytes / instruction with best score): + // Pentium 3 - 128 / prefetchnta // Pentium 4 - 512 / prefetchnta + // Athlon - 128 / prefetchnta // Opteron - 256 / prefetchnta // Core - 256 / prefetchnta // It will be used only when AllocatePrefetchStyle > 0 intx count = AllocatePrefetchDistance; - if (count < 0) { // default ? - if (is_amd()) { // AMD - count = 256; // Opteron - } else { // Intel - if (cpu_family() == 6) { - count = 256;// Pentium M, Core, Core2 - } else { - count = 512;// Pentium 4 - } + if (count < 0) { // default ? + if (is_amd()) { // AMD + if (supports_sse2()) + count = 256; // Opteron + else + count = 128; // Athlon + } else { // Intel + if (supports_sse2()) + if (cpu_family() == 6) { + count = 256; // Pentium M, Core, Core2 + } else { + count = 512; // Pentium 4 + } + else + count = 128; // Pentium 3 (and all other old CPUs) } } return count; diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86_32.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86_32.hpp deleted file mode 100644 index 54b3cb0370d..00000000000 --- a/hotspot/src/cpu/x86/vm/vm_version_x86_32.hpp +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * - */ - -class VM_Version: public Abstract_VM_Version { -public: - // cpuid result register layouts. These are all unions of a uint32_t - // (in case anyone wants access to the register as a whole) and a bitfield. - - union StdCpuid1Eax { - uint32_t value; - struct { - uint32_t stepping : 4, - model : 4, - family : 4, - proc_type : 2, - : 2, - ext_model : 4, - ext_family : 8, - : 4; - } bits; - }; - - union StdCpuid1Ebx { // example, unused - uint32_t value; - struct { - uint32_t brand_id : 8, - clflush_size : 8, - threads_per_cpu : 8, - apic_id : 8; - } bits; - }; - - union StdCpuid1Ecx { - uint32_t value; - struct { - uint32_t sse3 : 1, - : 2, - monitor : 1, - : 1, - vmx : 1, - : 1, - est : 1, - : 1, - ssse3 : 1, - cid : 1, - : 2, - cmpxchg16: 1, - : 4, - dca : 1, - sse4_1 : 1, - sse4_2 : 1, - : 11; - } bits; - }; - - union StdCpuid1Edx { - uint32_t value; - struct { - uint32_t : 4, - tsc : 1, - : 3, - cmpxchg8 : 1, - : 6, - cmov : 1, - : 7, - mmx : 1, - fxsr : 1, - sse : 1, - sse2 : 1, - : 1, - ht : 1, - : 3; - } bits; - }; - - union DcpCpuid4Eax { - uint32_t value; - struct { - uint32_t cache_type : 5, - : 21, - cores_per_cpu : 6; - } bits; - }; - - union DcpCpuid4Ebx { - uint32_t value; - struct { - uint32_t L1_line_size : 12, - partitions : 10, - associativity : 10; - } bits; - }; - - union ExtCpuid1Ecx { - uint32_t value; - struct { - uint32_t LahfSahf : 1, - CmpLegacy : 1, - : 4, - abm : 1, - sse4a : 1, - misalignsse : 1, - prefetchw : 1, - : 22; - } bits; - }; - - union ExtCpuid1Edx { - uint32_t value; - struct { - uint32_t : 22, - mmx_amd : 1, - mmx : 1, - fxsr : 1, - : 4, - long_mode : 1, - tdnow2 : 1, - tdnow : 1; - } bits; - }; - - union ExtCpuid5Ex { - uint32_t value; - struct { - uint32_t L1_line_size : 8, - L1_tag_lines : 8, - L1_assoc : 8, - L1_size : 8; - } bits; - }; - - union ExtCpuid8Ecx { - uint32_t value; - struct { - uint32_t cores_per_cpu : 8, - : 24; - } bits; - }; - -protected: - static int _cpu; - static int _model; - static int _stepping; - static int _cpuFeatures; // features returned by the "cpuid" instruction - // 0 if this instruction is not available - static const char* _features_str; - - enum { - CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX) - CPU_CMOV = (1 << 1), - CPU_FXSR = (1 << 2), - CPU_HT = (1 << 3), - CPU_MMX = (1 << 4), - CPU_3DNOW= (1 << 5), // 3DNow comes from cpuid 0x80000001 (EDX) - CPU_SSE = (1 << 6), - CPU_SSE2 = (1 << 7), - CPU_SSE3 = (1 << 8), // sse3 comes from cpuid 1 (ECX) - CPU_SSSE3= (1 << 9), - CPU_SSE4A= (1 <<10), - CPU_SSE4_1 = (1 << 11), - CPU_SSE4_2 = (1 << 12) - } cpuFeatureFlags; - - // cpuid information block. All info derived from executing cpuid with - // various function numbers is stored here. Intel and AMD info is - // merged in this block: accessor methods disentangle it. - // - // The info block is laid out in subblocks of 4 dwords corresponding to - // rax, rbx, rcx and rdx, whether or not they contain anything useful. - struct CpuidInfo { - // cpuid function 0 - uint32_t std_max_function; - uint32_t std_vendor_name_0; - uint32_t std_vendor_name_1; - uint32_t std_vendor_name_2; - - // cpuid function 1 - StdCpuid1Eax std_cpuid1_rax; - StdCpuid1Ebx std_cpuid1_rbx; - StdCpuid1Ecx std_cpuid1_rcx; - StdCpuid1Edx std_cpuid1_rdx; - - // cpuid function 4 (deterministic cache parameters) - DcpCpuid4Eax dcp_cpuid4_rax; - DcpCpuid4Ebx dcp_cpuid4_rbx; - uint32_t dcp_cpuid4_rcx; // unused currently - uint32_t dcp_cpuid4_rdx; // unused currently - - // cpuid function 0x80000000 // example, unused - uint32_t ext_max_function; - uint32_t ext_vendor_name_0; - uint32_t ext_vendor_name_1; - uint32_t ext_vendor_name_2; - - // cpuid function 0x80000001 - uint32_t ext_cpuid1_rax; // reserved - uint32_t ext_cpuid1_rbx; // reserved - ExtCpuid1Ecx ext_cpuid1_rcx; - ExtCpuid1Edx ext_cpuid1_rdx; - - // cpuid functions 0x80000002 thru 0x80000004: example, unused - uint32_t proc_name_0, proc_name_1, proc_name_2, proc_name_3; - uint32_t proc_name_4, proc_name_5, proc_name_6, proc_name_7; - uint32_t proc_name_8, proc_name_9, proc_name_10,proc_name_11; - - // cpuid function 0x80000005 //AMD L1, Intel reserved - uint32_t ext_cpuid5_rax; // unused currently - uint32_t ext_cpuid5_rbx; // reserved - ExtCpuid5Ex ext_cpuid5_rcx; // L1 data cache info (AMD) - ExtCpuid5Ex ext_cpuid5_rdx; // L1 instruction cache info (AMD) - - // cpuid function 0x80000008 - uint32_t ext_cpuid8_rax; // unused currently - uint32_t ext_cpuid8_rbx; // reserved - ExtCpuid8Ecx ext_cpuid8_rcx; - uint32_t ext_cpuid8_rdx; // reserved - }; - - // The actual cpuid info block - static CpuidInfo _cpuid_info; - - // Extractors and predicates - static uint32_t extended_cpu_family() { - uint32_t result = _cpuid_info.std_cpuid1_rax.bits.family; - result += _cpuid_info.std_cpuid1_rax.bits.ext_family; - return result; - } - static uint32_t extended_cpu_model() { - uint32_t result = _cpuid_info.std_cpuid1_rax.bits.model; - result |= _cpuid_info.std_cpuid1_rax.bits.ext_model << 4; - return result; - } - static uint32_t cpu_stepping() { - uint32_t result = _cpuid_info.std_cpuid1_rax.bits.stepping; - return result; - } - static uint logical_processor_count() { - uint result = threads_per_core(); - return result; - } - static uint32_t feature_flags() { - uint32_t result = 0; - if (_cpuid_info.std_cpuid1_rdx.bits.cmpxchg8 != 0) - result |= CPU_CX8; - if (_cpuid_info.std_cpuid1_rdx.bits.cmov != 0) - result |= CPU_CMOV; - if (_cpuid_info.std_cpuid1_rdx.bits.fxsr != 0 || is_amd() && - _cpuid_info.ext_cpuid1_rdx.bits.fxsr != 0) - result |= CPU_FXSR; - // HT flag is set for multi-core processors also. - if (threads_per_core() > 1) - result |= CPU_HT; - if (_cpuid_info.std_cpuid1_rdx.bits.mmx != 0 || is_amd() && - _cpuid_info.ext_cpuid1_rdx.bits.mmx != 0) - result |= CPU_MMX; - if (is_amd() && _cpuid_info.ext_cpuid1_rdx.bits.tdnow != 0) - result |= CPU_3DNOW; - if (_cpuid_info.std_cpuid1_rdx.bits.sse != 0) - result |= CPU_SSE; - if (_cpuid_info.std_cpuid1_rdx.bits.sse2 != 0) - result |= CPU_SSE2; - if (_cpuid_info.std_cpuid1_rcx.bits.sse3 != 0) - result |= CPU_SSE3; - if (_cpuid_info.std_cpuid1_rcx.bits.ssse3 != 0) - result |= CPU_SSSE3; - if (is_amd() && _cpuid_info.ext_cpuid1_rcx.bits.sse4a != 0) - result |= CPU_SSE4A; - if (_cpuid_info.std_cpuid1_rcx.bits.sse4_1 != 0) - result |= CPU_SSE4_1; - if (_cpuid_info.std_cpuid1_rcx.bits.sse4_2 != 0) - result |= CPU_SSE4_2; - return result; - } - - static void get_processor_features(); - -public: - // Offsets for cpuid asm stub - static ByteSize std_cpuid0_offset() { return byte_offset_of(CpuidInfo, std_max_function); } - static ByteSize std_cpuid1_offset() { return byte_offset_of(CpuidInfo, std_cpuid1_rax); } - static ByteSize dcp_cpuid4_offset() { return byte_offset_of(CpuidInfo, dcp_cpuid4_rax); } - static ByteSize ext_cpuid1_offset() { return byte_offset_of(CpuidInfo, ext_cpuid1_rax); } - static ByteSize ext_cpuid5_offset() { return byte_offset_of(CpuidInfo, ext_cpuid5_rax); } - static ByteSize ext_cpuid8_offset() { return byte_offset_of(CpuidInfo, ext_cpuid8_rax); } - - // Initialization - static void initialize(); - - // Asserts - static void assert_is_initialized() { - assert(_cpuid_info.std_cpuid1_rax.bits.family != 0, "VM_Version not initialized"); - } - - // - // Processor family: - // 3 - 386 - // 4 - 486 - // 5 - Pentium - // 6 - PentiumPro, Pentium II, Celeron, Xeon, Pentium III, Athlon, - // Pentium M, Core Solo, Core Duo, Core2 Duo - // family 6 model: 9, 13, 14, 15 - // 0x0f - Pentium 4, Opteron - // - // Note: The cpu family should be used to select between - // instruction sequences which are valid on all Intel - // processors. Use the feature test functions below to - // determine whether a particular instruction is supported. - // - static int cpu_family() { return _cpu;} - static bool is_P6() { return cpu_family() >= 6; } - - static bool is_amd() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x68747541; } // 'htuA' - static bool is_intel() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x756e6547; } // 'uneG' - - static uint cores_per_cpu() { - uint result = 1; - if (is_intel()) { - result = (_cpuid_info.dcp_cpuid4_rax.bits.cores_per_cpu + 1); - } else if (is_amd()) { - result = (_cpuid_info.ext_cpuid8_rcx.bits.cores_per_cpu + 1); - } - return result; - } - - static uint threads_per_core() { - uint result = 1; - if (_cpuid_info.std_cpuid1_rdx.bits.ht != 0) { - result = _cpuid_info.std_cpuid1_rbx.bits.threads_per_cpu / - cores_per_cpu(); - } - return result; - } - - static intx L1_data_cache_line_size() { - intx result = 0; - if (is_intel()) { - result = (_cpuid_info.dcp_cpuid4_rbx.bits.L1_line_size + 1); - } else if (is_amd()) { - result = _cpuid_info.ext_cpuid5_rcx.bits.L1_line_size; - } - if (result < 32) // not defined ? - result = 32; // 32 bytes by default on x86 - return result; - } - - // - // Feature identification - // - static bool supports_cpuid() { return _cpuFeatures != 0; } - static bool supports_cmpxchg8() { return (_cpuFeatures & CPU_CX8) != 0; } - static bool supports_cmov() { return (_cpuFeatures & CPU_CMOV) != 0; } - static bool supports_fxsr() { return (_cpuFeatures & CPU_FXSR) != 0; } - static bool supports_ht() { return (_cpuFeatures & CPU_HT) != 0; } - static bool supports_mmx() { return (_cpuFeatures & CPU_MMX) != 0; } - static bool supports_sse() { return (_cpuFeatures & CPU_SSE) != 0; } - static bool supports_sse2() { return (_cpuFeatures & CPU_SSE2) != 0; } - static bool supports_sse3() { return (_cpuFeatures & CPU_SSE3) != 0; } - static bool supports_ssse3() { return (_cpuFeatures & CPU_SSSE3)!= 0; } - static bool supports_sse4_1() { return (_cpuFeatures & CPU_SSE4_1) != 0; } - static bool supports_sse4_2() { return (_cpuFeatures & CPU_SSE4_2) != 0; } - // - // AMD features - // - static bool supports_3dnow() { return (_cpuFeatures & CPU_3DNOW) != 0; } - static bool supports_mmx_ext() { return is_amd() && _cpuid_info.ext_cpuid1_rdx.bits.mmx_amd != 0; } - static bool supports_3dnow2() { return is_amd() && _cpuid_info.ext_cpuid1_rdx.bits.tdnow2 != 0; } - static bool supports_sse4a() { return (_cpuFeatures & CPU_SSE4A) != 0; } - - static bool supports_compare_and_exchange() { return true; } - - static const char* cpu_features() { return _features_str; } - - static intx allocate_prefetch_distance() { - // This method should be called before allocate_prefetch_style(). - // - // Hardware prefetching (distance/size in bytes): - // Pentium 3 - 64 / 32 - // Pentium 4 - 256 / 128 - // Athlon - 64 / 32 ???? - // Opteron - 128 / 64 only when 2 sequential cache lines accessed - // Core - 128 / 64 - // - // Software prefetching (distance in bytes / instruction with best score): - // Pentium 3 - 128 / prefetchnta - // Pentium 4 - 512 / prefetchnta - // Athlon - 128 / prefetchnta - // Opteron - 256 / prefetchnta - // Core - 256 / prefetchnta - // It will be used only when AllocatePrefetchStyle > 0 - - intx count = AllocatePrefetchDistance; - if (count < 0) { // default ? - if (is_amd()) { // AMD - if (supports_sse2()) - count = 256; // Opteron - else - count = 128; // Athlon - } else { // Intel - if (supports_sse2()) - if (cpu_family() == 6) { - count = 256; // Pentium M, Core, Core2 - } else { - count = 512; // Pentium 4 - } - else - count = 128; // Pentium 3 (and all other old CPUs) - } - } - return count; - } - static intx allocate_prefetch_style() { - assert(AllocatePrefetchStyle >= 0, "AllocatePrefetchStyle should be positive"); - // Return 0 if AllocatePrefetchDistance was not defined or - // prefetch instruction is not supported. - return (AllocatePrefetchDistance > 0 && - (supports_3dnow() || supports_sse())) ? AllocatePrefetchStyle : 0; - } -}; diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86_64.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86_64.cpp deleted file mode 100644 index 7994aab7a78..00000000000 --- a/hotspot/src/cpu/x86/vm/vm_version_x86_64.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * - */ - -# include "incls/_precompiled.incl" -# include "incls/_vm_version_x86_64.cpp.incl" - -int VM_Version::_cpu; -int VM_Version::_model; -int VM_Version::_stepping; -int VM_Version::_cpuFeatures; -const char* VM_Version::_features_str = ""; -VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, }; - -static BufferBlob* stub_blob; -static const int stub_size = 300; - -extern "C" { - typedef void (*getPsrInfo_stub_t)(void*); -} -static getPsrInfo_stub_t getPsrInfo_stub = NULL; - - -class VM_Version_StubGenerator: public StubCodeGenerator { - public: - - VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {} - - address generate_getPsrInfo() { - - Label std_cpuid1, ext_cpuid1, ext_cpuid5, done; - - StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub"); -# define __ _masm-> - - address start = __ pc(); - - // - // void getPsrInfo(VM_Version::CpuidInfo* cpuid_info); - // - // rcx and rdx are first and second argument registers on windows - - __ push(rbp); - __ mov(rbp, c_rarg0); // cpuid_info address - __ push(rbx); - __ push(rsi); - - // - // we have a chip which supports the "cpuid" instruction - // - __ xorl(rax, rax); - __ cpuid(); - __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); - __ movl(Address(rsi, 0), rax); - __ movl(Address(rsi, 4), rbx); - __ movl(Address(rsi, 8), rcx); - __ movl(Address(rsi,12), rdx); - - __ cmpl(rax, 3); // Is cpuid(0x4) supported? - __ jccb(Assembler::belowEqual, std_cpuid1); - - // - // cpuid(0x4) Deterministic cache params - // - __ movl(rax, 4); - __ xorl(rcx, rcx); // L1 cache - __ cpuid(); - __ push(rax); - __ andl(rax, 0x1f); // Determine if valid cache parameters used - __ orl(rax, rax); // eax[4:0] == 0 indicates invalid cache - __ pop(rax); - __ jccb(Assembler::equal, std_cpuid1); - - __ lea(rsi, Address(rbp, in_bytes(VM_Version::dcp_cpuid4_offset()))); - __ movl(Address(rsi, 0), rax); - __ movl(Address(rsi, 4), rbx); - __ movl(Address(rsi, 8), rcx); - __ movl(Address(rsi,12), rdx); - - // - // Standard cpuid(0x1) - // - __ bind(std_cpuid1); - __ movl(rax, 1); - __ cpuid(); - __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); - __ movl(Address(rsi, 0), rax); - __ movl(Address(rsi, 4), rbx); - __ movl(Address(rsi, 8), rcx); - __ movl(Address(rsi,12), rdx); - - __ movl(rax, 0x80000000); - __ cpuid(); - __ cmpl(rax, 0x80000000); // Is cpuid(0x80000001) supported? - __ jcc(Assembler::belowEqual, done); - __ cmpl(rax, 0x80000004); // Is cpuid(0x80000005) supported? - __ jccb(Assembler::belowEqual, ext_cpuid1); - __ cmpl(rax, 0x80000007); // Is cpuid(0x80000008) supported? - __ jccb(Assembler::belowEqual, ext_cpuid5); - // - // Extended cpuid(0x80000008) - // - __ movl(rax, 0x80000008); - __ cpuid(); - __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid8_offset()))); - __ movl(Address(rsi, 0), rax); - __ movl(Address(rsi, 4), rbx); - __ movl(Address(rsi, 8), rcx); - __ movl(Address(rsi,12), rdx); - - // - // Extended cpuid(0x80000005) - // - __ bind(ext_cpuid5); - __ movl(rax, 0x80000005); - __ cpuid(); - __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid5_offset()))); - __ movl(Address(rsi, 0), rax); - __ movl(Address(rsi, 4), rbx); - __ movl(Address(rsi, 8), rcx); - __ movl(Address(rsi,12), rdx); - - // - // Extended cpuid(0x80000001) - // - __ bind(ext_cpuid1); - __ movl(rax, 0x80000001); - __ cpuid(); - __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid1_offset()))); - __ movl(Address(rsi, 0), rax); - __ movl(Address(rsi, 4), rbx); - __ movl(Address(rsi, 8), rcx); - __ movl(Address(rsi,12), rdx); - - // - // return - // - __ bind(done); - __ pop(rsi); - __ pop(rbx); - __ pop(rbp); - __ ret(0); - -# undef __ - - return start; - }; -}; - - -void VM_Version::get_processor_features() { - - _logical_processors_per_package = 1; - // Get raw processor info - getPsrInfo_stub(&_cpuid_info); - assert_is_initialized(); - _cpu = extended_cpu_family(); - _model = extended_cpu_model(); - _stepping = cpu_stepping(); - _cpuFeatures = feature_flags(); - // Logical processors are only available on P4s and above, - // and only if hyperthreading is available. - _logical_processors_per_package = logical_processor_count(); - _supports_cx8 = supports_cmpxchg8(); - // OS should support SSE for x64 and hardware should support at least SSE2. - if (!VM_Version::supports_sse2()) { - vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported"); - } - if (UseSSE < 4) { - _cpuFeatures &= ~CPU_SSE4_1; - _cpuFeatures &= ~CPU_SSE4_2; - } - if (UseSSE < 3) { - _cpuFeatures &= ~CPU_SSE3; - _cpuFeatures &= ~CPU_SSSE3; - _cpuFeatures &= ~CPU_SSE4A; - } - if (UseSSE < 2) - _cpuFeatures &= ~CPU_SSE2; - if (UseSSE < 1) - _cpuFeatures &= ~CPU_SSE; - - if (logical_processors_per_package() == 1) { - // HT processor could be installed on a system which doesn't support HT. - _cpuFeatures &= ~CPU_HT; - } - - char buf[256]; - jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - cores_per_cpu(), threads_per_core(), - cpu_family(), _model, _stepping, - (supports_cmov() ? ", cmov" : ""), - (supports_cmpxchg8() ? ", cx8" : ""), - (supports_fxsr() ? ", fxsr" : ""), - (supports_mmx() ? ", mmx" : ""), - (supports_sse() ? ", sse" : ""), - (supports_sse2() ? ", sse2" : ""), - (supports_sse3() ? ", sse3" : ""), - (supports_ssse3()? ", ssse3": ""), - (supports_sse4_1() ? ", sse4.1" : ""), - (supports_sse4_2() ? ", sse4.2" : ""), - (supports_mmx_ext() ? ", mmxext" : ""), - (supports_3dnow() ? ", 3dnow" : ""), - (supports_3dnow2() ? ", 3dnowext" : ""), - (supports_sse4a() ? ", sse4a": ""), - (supports_ht() ? ", ht": "")); - _features_str = strdup(buf); - - // UseSSE is set to the smaller of what hardware supports and what - // the command line requires. I.e., you cannot set UseSSE to 2 on - // older Pentiums which do not support it. - if( UseSSE > 4 ) UseSSE=4; - if( UseSSE < 0 ) UseSSE=0; - if( !supports_sse4_1() ) // Drop to 3 if no SSE4 support - UseSSE = MIN2((intx)3,UseSSE); - if( !supports_sse3() ) // Drop to 2 if no SSE3 support - UseSSE = MIN2((intx)2,UseSSE); - if( !supports_sse2() ) // Drop to 1 if no SSE2 support - UseSSE = MIN2((intx)1,UseSSE); - if( !supports_sse () ) // Drop to 0 if no SSE support - UseSSE = 0; - - // On new cpus instructions which update whole XMM register should be used - // to prevent partial register stall due to dependencies on high half. - // - // UseXmmLoadAndClearUpper == true --> movsd(xmm, mem) - // UseXmmLoadAndClearUpper == false --> movlpd(xmm, mem) - // UseXmmRegToRegMoveAll == true --> movaps(xmm, xmm), movapd(xmm, xmm). - // UseXmmRegToRegMoveAll == false --> movss(xmm, xmm), movsd(xmm, xmm). - - if( is_amd() ) { // AMD cpus specific settings - if( FLAG_IS_DEFAULT(UseAddressNop) ) { - // Use it on all AMD cpus starting from Opteron (don't need - // a cpu check since only Opteron and new cpus support 64-bits mode). - UseAddressNop = true; - } - if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) { - if( supports_sse4a() ) { - UseXmmLoadAndClearUpper = true; // use movsd only on '10h' Opteron - } else { - UseXmmLoadAndClearUpper = false; - } - } - if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) { - if( supports_sse4a() ) { - UseXmmRegToRegMoveAll = true; // use movaps, movapd only on '10h' - } else { - UseXmmRegToRegMoveAll = false; - } - } - if( FLAG_IS_DEFAULT(UseXmmI2F) ) { - if( supports_sse4a() ) { - UseXmmI2F = true; - } else { - UseXmmI2F = false; - } - } - if( FLAG_IS_DEFAULT(UseXmmI2D) ) { - if( supports_sse4a() ) { - UseXmmI2D = true; - } else { - UseXmmI2D = false; - } - } - } - - if( is_intel() ) { // Intel cpus specific settings - if( FLAG_IS_DEFAULT(UseStoreImmI16) ) { - UseStoreImmI16 = false; // don't use it on Intel cpus - } - if( FLAG_IS_DEFAULT(UseAddressNop) ) { - // Use it on all Intel cpus starting from PentiumPro - // (don't need a cpu check since only new cpus support 64-bits mode). - UseAddressNop = true; - } - if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) { - UseXmmLoadAndClearUpper = true; // use movsd on all Intel cpus - } - if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) { - if( supports_sse3() ) { - UseXmmRegToRegMoveAll = true; // use movaps, movapd on new Intel cpus - } else { - UseXmmRegToRegMoveAll = false; - } - } - if( cpu_family() == 6 && supports_sse3() ) { // New Intel cpus -#ifdef COMPILER2 - if( FLAG_IS_DEFAULT(MaxLoopPad) ) { - // For new Intel cpus do the next optimization: - // don't align the beginning of a loop if there are enough instructions - // left (NumberOfLoopInstrToAlign defined in c2_globals.hpp) - // in current fetch line (OptoLoopAlignment) or the padding - // is big (> MaxLoopPad). - // Set MaxLoopPad to 11 for new Intel cpus to reduce number of - // generated NOP instructions. 11 is the largest size of one - // address NOP instruction '0F 1F' (see Assembler::nop(i)). - MaxLoopPad = 11; - } -#endif // COMPILER2 - if( FLAG_IS_DEFAULT(UseXMMForArrayCopy) ) { - UseXMMForArrayCopy = true; // use SSE2 movq on new Intel cpus - } - if( supports_sse4_2() && supports_ht() ) { // Newest Intel cpus - if( FLAG_IS_DEFAULT(UseUnalignedLoadStores) && UseXMMForArrayCopy ) { - UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus - } - } - } - } - - assert(0 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value"); - assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value"); - - // set valid Prefetch instruction - if( ReadPrefetchInstr < 0 ) ReadPrefetchInstr = 0; - if( ReadPrefetchInstr > 3 ) ReadPrefetchInstr = 3; - if( ReadPrefetchInstr == 3 && !supports_3dnow() ) ReadPrefetchInstr = 0; - - if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0; - if( AllocatePrefetchInstr > 3 ) AllocatePrefetchInstr = 3; - if( AllocatePrefetchInstr == 3 && !supports_3dnow() ) AllocatePrefetchInstr=0; - - // Allocation prefetch settings - intx cache_line_size = L1_data_cache_line_size(); - if( cache_line_size > AllocatePrefetchStepSize ) - AllocatePrefetchStepSize = cache_line_size; - if( FLAG_IS_DEFAULT(AllocatePrefetchLines) ) - AllocatePrefetchLines = 3; // Optimistic value - assert(AllocatePrefetchLines > 0, "invalid value"); - if( AllocatePrefetchLines < 1 ) // set valid value in product VM - AllocatePrefetchLines = 1; // Conservative value - - AllocatePrefetchDistance = allocate_prefetch_distance(); - AllocatePrefetchStyle = allocate_prefetch_style(); - - if( AllocatePrefetchStyle == 2 && is_intel() && - cpu_family() == 6 && supports_sse3() ) { // watermark prefetching on Core - AllocatePrefetchDistance = 384; - } - assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value"); - - // Prefetch settings - PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes(); - PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes(); - PrefetchFieldsAhead = prefetch_fields_ahead(); - -#ifndef PRODUCT - if (PrintMiscellaneous && Verbose) { - tty->print_cr("Logical CPUs per core: %u", - logical_processors_per_package()); - tty->print_cr("UseSSE=%d",UseSSE); - tty->print("Allocation: "); - if (AllocatePrefetchStyle <= 0) { - tty->print_cr("no prefetching"); - } else { - if (AllocatePrefetchInstr == 0) { - tty->print("PREFETCHNTA"); - } else if (AllocatePrefetchInstr == 1) { - tty->print("PREFETCHT0"); - } else if (AllocatePrefetchInstr == 2) { - tty->print("PREFETCHT2"); - } else if (AllocatePrefetchInstr == 3) { - tty->print("PREFETCHW"); - } - if (AllocatePrefetchLines > 1) { - tty->print_cr(" %d, %d lines with step %d bytes", AllocatePrefetchDistance, AllocatePrefetchLines, AllocatePrefetchStepSize); - } else { - tty->print_cr(" %d, one line", AllocatePrefetchDistance); - } - } - if (PrefetchCopyIntervalInBytes > 0) { - tty->print_cr("PrefetchCopyIntervalInBytes %d", PrefetchCopyIntervalInBytes); - } - if (PrefetchScanIntervalInBytes > 0) { - tty->print_cr("PrefetchScanIntervalInBytes %d", PrefetchScanIntervalInBytes); - } - if (PrefetchFieldsAhead > 0) { - tty->print_cr("PrefetchFieldsAhead %d", PrefetchFieldsAhead); - } - } -#endif // !PRODUCT -} - -void VM_Version::initialize() { - ResourceMark rm; - // Making this stub must be FIRST use of assembler - - stub_blob = BufferBlob::create("getPsrInfo_stub", stub_size); - if (stub_blob == NULL) { - vm_exit_during_initialization("Unable to allocate getPsrInfo_stub"); - } - CodeBuffer c(stub_blob->instructions_begin(), - stub_blob->instructions_size()); - VM_Version_StubGenerator g(&c); - getPsrInfo_stub = CAST_TO_FN_PTR(getPsrInfo_stub_t, - g.generate_getPsrInfo()); - - get_processor_features(); -} diff --git a/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp b/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp index c077929db1a..dbc5e262a81 100644 --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp @@ -34,10 +34,16 @@ extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index); #endif -// used by compiler only; may use only caller saved registers rax, rbx, rcx. -// rdx holds first int arg, rsi, rdi, rbp are callee-save & must be preserved. -// Leave receiver in rcx; required behavior when +OptoArgsInRegisters -// is modifed to put first oop in rcx. +// These stubs are used by the compiler only. +// Argument registers, which must be preserved: +// rcx - receiver (always first argument) +// rdx - second argument (if any) +// Other registers that might be usable: +// rax - inline cache register (is interface for itable stub) +// rbx - method (used when calling out to interpreter) +// Available now, but may become callee-save at some point: +// rsi, rdi +// Note that rax and rdx are also used for return values. // VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { const int i486_code_length = VtableStub::pd_code_size_limit(true); @@ -94,16 +100,25 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { __ jmp( Address(method, methodOopDesc::from_compiled_offset())); masm->flush(); + + if (PrintMiscellaneous && (WizardMode || Verbose)) { + tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d", + vtable_index, s->entry_point(), + (int)(s->code_end() - s->entry_point()), + (int)(s->code_end() - __ pc())); + } + guarantee(__ pc() <= s->code_end(), "overflowed buffer"); + s->set_exception_points(npe_addr, ame_addr); return s; } -VtableStub* VtableStubs::create_itable_stub(int vtable_index) { +VtableStub* VtableStubs::create_itable_stub(int itable_index) { // Note well: pd_code_size_limit is the absolute minimum we can get away with. If you // add code here, bump the code stub size returned by pd_code_size_limit! const int i486_code_length = VtableStub::pd_code_size_limit(false); - VtableStub* s = new(i486_code_length) VtableStub(false, vtable_index); + VtableStub* s = new(i486_code_length) VtableStub(false, itable_index); ResourceMark rm; CodeBuffer cb(s->entry_point(), i486_code_length); MacroAssembler* masm = new MacroAssembler(&cb); @@ -123,50 +138,19 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { // get receiver klass (also an implicit null-check) address npe_addr = __ pc(); - __ movptr(rbx, Address(rcx, oopDesc::klass_offset_in_bytes())); + __ movptr(rsi, Address(rcx, oopDesc::klass_offset_in_bytes())); - __ mov(rsi, rbx); // Save klass in free register - // Most registers are in use, so save a few - __ push(rdx); - // compute itable entry offset (in words) - const int base = instanceKlass::vtable_start_offset() * wordSize; - assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below"); - __ movl(rdx, Address(rbx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable - __ lea(rbx, Address(rbx, rdx, Address::times_ptr, base)); - if (HeapWordsPerLong > 1) { - // Round up to align_object_offset boundary - __ round_to(rbx, BytesPerLong); - } - - Label hit, next, entry, throw_icce; - - __ jmpb(entry); - - __ bind(next); - __ addptr(rbx, itableOffsetEntry::size() * wordSize); - - __ bind(entry); - - // If the entry is NULL then we've reached the end of the table - // without finding the expected interface, so throw an exception - __ movptr(rdx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); - __ testptr(rdx, rdx); - __ jcc(Assembler::zero, throw_icce); - __ cmpptr(rax, rdx); - __ jcc(Assembler::notEqual, next); - - // We found a hit, move offset into rbx, - __ movl(rdx, Address(rbx, itableOffsetEntry::offset_offset_in_bytes())); - - // Compute itableMethodEntry. - const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes(); + // Most registers are in use; we'll use rax, rbx, rsi, rdi + // (If we need to make rsi, rdi callee-save, do a push/pop here.) + const Register method = rbx; + Label throw_icce; // Get methodOop and entrypoint for compiler - const Register method = rbx; - __ movptr(method, Address(rsi, rdx, Address::times_1, method_offset)); - - // Restore saved register, before possible trap. - __ pop(rdx); + __ lookup_interface_method(// inputs: rec. class, interface, itable index + rsi, rax, itable_index, + // outputs: method, scan temp. reg + method, rdi, + throw_icce); // method (rbx): methodOop // rcx: receiver @@ -187,12 +171,15 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { __ jmp(Address(method, methodOopDesc::from_compiled_offset())); __ bind(throw_icce); - // Restore saved register - __ pop(rdx); __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); - masm->flush(); + if (PrintMiscellaneous && (WizardMode || Verbose)) { + tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d", + itable_index, s->entry_point(), + (int)(s->code_end() - s->entry_point()), + (int)(s->code_end() - __ pc())); + } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); @@ -207,7 +194,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0); } else { // Itable stub size - return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0); + return (DebugVtables ? 256 : 66) + (CountCompiledCalls ? 6 : 0); } } diff --git a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp index 7ae875b73cc..927bff5ca9e 100644 --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp @@ -98,17 +98,26 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { __ jmp( Address(rbx, methodOopDesc::from_compiled_offset())); __ flush(); + + if (PrintMiscellaneous && (WizardMode || Verbose)) { + tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d", + vtable_index, s->entry_point(), + (int)(s->code_end() - s->entry_point()), + (int)(s->code_end() - __ pc())); + } + guarantee(__ pc() <= s->code_end(), "overflowed buffer"); + s->set_exception_points(npe_addr, ame_addr); return s; } -VtableStub* VtableStubs::create_itable_stub(int vtable_index) { +VtableStub* VtableStubs::create_itable_stub(int itable_index) { // Note well: pd_code_size_limit is the absolute minimum we can get // away with. If you add code here, bump the code stub size // returned by pd_code_size_limit! const int amd64_code_length = VtableStub::pd_code_size_limit(false); - VtableStub* s = new(amd64_code_length) VtableStub(false, vtable_index); + VtableStub* s = new(amd64_code_length) VtableStub(false, itable_index); ResourceMark rm; CodeBuffer cb(s->entry_point(), amd64_code_length); MacroAssembler* masm = new MacroAssembler(&cb); @@ -131,68 +140,28 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { // get receiver klass (also an implicit null-check) address npe_addr = __ pc(); - __ load_klass(rbx, j_rarg0); + // Most registers are in use; we'll use rax, rbx, r10, r11 + // (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them) + __ load_klass(r10, j_rarg0); // If we take a trap while this arg is on the stack we will not // be able to walk the stack properly. This is not an issue except // when there are mistakes in this assembly code that could generate // a spurious fault. Ask me how I know... - __ push(j_rarg1); // Most registers are in use, so save one - - // compute itable entry offset (in words) - const int base = instanceKlass::vtable_start_offset() * wordSize; - assert(vtableEntry::size() * wordSize == 8, - "adjust the scaling in the code below"); - // Get length of vtable - __ movl(j_rarg1, - Address(rbx, instanceKlass::vtable_length_offset() * wordSize)); - __ lea(rbx, Address(rbx, j_rarg1, Address::times_8, base)); - - if (HeapWordsPerLong > 1) { - // Round up to align_object_offset boundary - __ round_to(rbx, BytesPerLong); - } - Label hit, next, entry, throw_icce; - - __ jmpb(entry); - - __ bind(next); - __ addptr(rbx, itableOffsetEntry::size() * wordSize); - - __ bind(entry); - - // If the entry is NULL then we've reached the end of the table - // without finding the expected interface, so throw an exception - __ movptr(j_rarg1, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); - __ testptr(j_rarg1, j_rarg1); - __ jcc(Assembler::zero, throw_icce); - __ cmpptr(rax, j_rarg1); - __ jccb(Assembler::notEqual, next); - - // We found a hit, move offset into j_rarg1 - __ movl(j_rarg1, Address(rbx, itableOffsetEntry::offset_offset_in_bytes())); - - // Compute itableMethodEntry - const int method_offset = - (itableMethodEntry::size() * wordSize * vtable_index) + - itableMethodEntry::method_offset_in_bytes(); + const Register method = rbx; + Label throw_icce; // Get methodOop and entrypoint for compiler - - // Get klass pointer again - __ load_klass(rax, j_rarg0); - - const Register method = rbx; - __ movptr(method, Address(rax, j_rarg1, Address::times_1, method_offset)); - - // Restore saved register, before possible trap. - __ pop(j_rarg1); + __ lookup_interface_method(// inputs: rec. class, interface, itable index + r10, rax, itable_index, + // outputs: method, scan temp. reg + method, r11, + throw_icce); // method (rbx): methodOop // j_rarg0: receiver - #ifdef ASSERT if (DebugVtables) { Label L2; @@ -211,12 +180,16 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { __ jmp(Address(method, methodOopDesc::from_compiled_offset())); __ bind(throw_icce); - // Restore saved register - __ pop(j_rarg1); __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); __ flush(); + if (PrintMiscellaneous && (WizardMode || Verbose)) { + tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d", + itable_index, s->entry_point(), + (int)(s->code_end() - s->entry_point()), + (int)(s->code_end() - __ pc())); + } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); @@ -230,7 +203,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { (UseCompressedOops ? 16 : 0); // 1 leaq can be 3 bytes + 1 long } else { // Itable stub size - return (DebugVtables ? 636 : 72) + (CountCompiledCalls ? 13 : 0) + + return (DebugVtables ? 512 : 72) + (CountCompiledCalls ? 13 : 0) + (UseCompressedOops ? 32 : 0); // 2 leaqs } } diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index edc6a63e79f..509a39972fe 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -1,5 +1,5 @@ // -// Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -130,7 +130,7 @@ reg_def XMM7b( SOC, SOC, Op_RegF, 7, xmm7->as_VMReg()->next()); // allocation. Highest priority is first. A useful heuristic is to // give registers a low priority when they are required by machine // instructions, like EAX and EDX. Registers which are used as -// pairs must fall on an even boundry (witness the FPR#L's in this list). +// pairs must fall on an even boundary (witness the FPR#L's in this list). // For the Intel integer registers, the equivalent Long pairs are // EDX:EAX, EBX:ECX, and EDI:EBP. alloc_class chunk0( ECX, EBX, EBP, EDI, EAX, EDX, ESI, ESP, @@ -1483,16 +1483,20 @@ encode %{ // main source block for now. In future, we can generalize this by // adding a syntax that specifies the sizes of fields in an order, // so that the adlc can build the emit functions automagically - enc_class OpcP %{ // Emit opcode - emit_opcode(cbuf,$primary); + + // Emit primary opcode + enc_class OpcP %{ + emit_opcode(cbuf, $primary); %} - enc_class OpcS %{ // Emit opcode - emit_opcode(cbuf,$secondary); + // Emit secondary opcode + enc_class OpcS %{ + emit_opcode(cbuf, $secondary); %} - enc_class Opcode(immI d8 ) %{ // Emit opcode - emit_opcode(cbuf,$d8$$constant); + // Emit opcode directly + enc_class Opcode(immI d8) %{ + emit_opcode(cbuf, $d8$$constant); %} enc_class SizePrefix %{ @@ -1688,26 +1692,15 @@ encode %{ Register Reax = as_Register(EAX_enc); // super class Register Recx = as_Register(ECX_enc); // killed Register Resi = as_Register(ESI_enc); // sub class - Label hit, miss; + Label miss; MacroAssembler _masm(&cbuf); - // Compare super with sub directly, since super is not in its own SSA. - // The compiler used to emit this test, but we fold it in here, - // to allow platform-specific tweaking on sparc. - __ cmpptr(Reax, Resi); - __ jcc(Assembler::equal, hit); -#ifndef PRODUCT - __ incrementl(ExternalAddress((address)&SharedRuntime::_partial_subtype_ctr)); -#endif //PRODUCT - __ movptr(Redi,Address(Resi,sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())); - __ movl(Recx,Address(Redi,arrayOopDesc::length_offset_in_bytes())); - __ addptr(Redi,arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - __ repne_scan(); - __ jcc(Assembler::notEqual, miss); - __ movptr(Address(Resi,sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()),Reax); - __ bind(hit); - if( $primary ) - __ xorptr(Redi,Redi); + __ check_klass_subtype_slow_path(Resi, Reax, Recx, Redi, + NULL, &miss, + /*set_cond_codes:*/ true); + if ($primary) { + __ xorptr(Redi, Redi); + } __ bind(miss); %} @@ -3126,14 +3119,12 @@ encode %{ enc_class movq_ld(regXD dst, memory mem) %{ MacroAssembler _masm(&cbuf); - Address madr = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - __ movq(as_XMMRegister($dst$$reg), madr); + __ movq($dst$$XMMRegister, $mem$$Address); %} enc_class movq_st(memory mem, regXD src) %{ MacroAssembler _masm(&cbuf); - Address madr = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - __ movq(madr, as_XMMRegister($src$$reg)); + __ movq($mem$$Address, $src$$XMMRegister); %} enc_class pshufd_8x8(regX dst, regX src) %{ @@ -3703,12 +3694,16 @@ encode %{ } %} - enc_class enc_String_Compare() %{ + enc_class enc_String_Compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2, + eAXRegI tmp3, eBXRegI tmp4, eCXRegI result) %{ Label ECX_GOOD_LABEL, LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, CONT_LABEL, WHILE_HEAD_LABEL; MacroAssembler masm(&cbuf); + XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); + XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); + // Get the first character position in both strings // [8] char array, [12] offset, [16] count int value_offset = java_lang_String::value_offset_in_bytes(); @@ -3726,7 +3721,6 @@ encode %{ // Compute the minimum of the string lengths(rsi) and the // difference of the string lengths (stack) - if (VM_Version::supports_cmov()) { masm.movl(rdi, Address(rdi, count_offset)); masm.movl(rsi, Address(rsi, count_offset)); @@ -3740,7 +3734,7 @@ encode %{ masm.movl(rsi, rdi); masm.subl(rdi, rcx); masm.push(rdi); - masm.jcc(Assembler::lessEqual, ECX_GOOD_LABEL); + masm.jccb(Assembler::lessEqual, ECX_GOOD_LABEL); masm.movl(rsi, rcx); // rsi holds min, rcx is unused } @@ -3751,8 +3745,8 @@ encode %{ masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL); // Load first characters - masm.load_unsigned_word(rcx, Address(rbx, 0)); - masm.load_unsigned_word(rdi, Address(rax, 0)); + masm.load_unsigned_short(rcx, Address(rbx, 0)); + masm.load_unsigned_short(rdi, Address(rax, 0)); // Compare first characters masm.subl(rcx, rdi); @@ -3765,7 +3759,7 @@ encode %{ Label LSkip2; // Check if the strings start at same location masm.cmpptr(rbx,rax); - masm.jcc(Assembler::notEqual, LSkip2); + masm.jccb(Assembler::notEqual, LSkip2); // Check if the length difference is zero (from stack) masm.cmpl(Address(rsp, 0), 0x0); @@ -3775,103 +3769,382 @@ encode %{ masm.bind(LSkip2); } - // Shift rax, and rbx, to the end of the arrays, negate min - masm.lea(rax, Address(rax, rsi, Address::times_2, 2)); - masm.lea(rbx, Address(rbx, rsi, Address::times_2, 2)); + // Advance to next character + masm.addptr(rax, 2); + masm.addptr(rbx, 2); + + if (UseSSE42Intrinsics) { + // With SSE4.2, use double quad vector compare + Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL; + // Setup to compare 16-byte vectors + masm.movl(rdi, rsi); + masm.andl(rsi, 0xfffffff8); // rsi holds the vector count + masm.andl(rdi, 0x00000007); // rdi holds the tail count + masm.testl(rsi, rsi); + masm.jccb(Assembler::zero, COMPARE_TAIL); + + masm.lea(rax, Address(rax, rsi, Address::times_2)); + masm.lea(rbx, Address(rbx, rsi, Address::times_2)); + masm.negl(rsi); + + masm.bind(COMPARE_VECTORS); + masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2)); + masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2)); + masm.pxor(tmp1Reg, tmp2Reg); + masm.ptest(tmp1Reg, tmp1Reg); + masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL); + masm.addl(rsi, 8); + masm.jcc(Assembler::notZero, COMPARE_VECTORS); + masm.jmpb(COMPARE_TAIL); + + // Mismatched characters in the vectors + masm.bind(VECTOR_NOT_EQUAL); + masm.lea(rax, Address(rax, rsi, Address::times_2)); + masm.lea(rbx, Address(rbx, rsi, Address::times_2)); + masm.movl(rdi, 8); + + // Compare tail (< 8 chars), or rescan last vectors to + // find 1st mismatched characters + masm.bind(COMPARE_TAIL); + masm.testl(rdi, rdi); + masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL); + masm.movl(rsi, rdi); + // Fallthru to tail compare + } + + //Shift rax, and rbx, to the end of the arrays, negate min + masm.lea(rax, Address(rax, rsi, Address::times_2, 0)); + masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0)); masm.negl(rsi); // Compare the rest of the characters masm.bind(WHILE_HEAD_LABEL); - masm.load_unsigned_word(rcx, Address(rbx, rsi, Address::times_2, 0)); - masm.load_unsigned_word(rdi, Address(rax, rsi, Address::times_2, 0)); + masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0)); + masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0)); masm.subl(rcx, rdi); - masm.jcc(Assembler::notZero, POP_LABEL); + masm.jccb(Assembler::notZero, POP_LABEL); masm.incrementl(rsi); masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL); // Strings are equal up to min length. Return the length difference. masm.bind(LENGTH_DIFF_LABEL); masm.pop(rcx); - masm.jmp(DONE_LABEL); + masm.jmpb(DONE_LABEL); // Discard the stored length difference masm.bind(POP_LABEL); masm.addptr(rsp, 4); - + // That's it masm.bind(DONE_LABEL); %} - enc_class enc_Array_Equals(eDIRegP ary1, eSIRegP ary2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result) %{ - Label TRUE_LABEL, FALSE_LABEL, DONE_LABEL, COMPARE_LOOP_HDR, COMPARE_LOOP; + enc_class enc_String_Equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2, + eBXRegI tmp3, eCXRegI tmp4, eAXRegI result) %{ + Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR; MacroAssembler masm(&cbuf); - Register ary1Reg = as_Register($ary1$$reg); - Register ary2Reg = as_Register($ary2$$reg); - Register tmp1Reg = as_Register($tmp1$$reg); - Register tmp2Reg = as_Register($tmp2$$reg); - Register resultReg = as_Register($result$$reg); + XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); + XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); + + int value_offset = java_lang_String::value_offset_in_bytes(); + int offset_offset = java_lang_String::offset_offset_in_bytes(); + int count_offset = java_lang_String::count_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + + // does source == target string? + masm.cmpptr(rdi, rsi); + masm.jcc(Assembler::equal, RET_TRUE); + + // get and compare counts + masm.movl(rcx, Address(rdi, count_offset)); + masm.movl(rax, Address(rsi, count_offset)); + masm.cmpl(rcx, rax); + masm.jcc(Assembler::notEqual, RET_FALSE); + masm.testl(rax, rax); + masm.jcc(Assembler::zero, RET_TRUE); + + // get source string offset and value + masm.movptr(rbx, Address(rsi, value_offset)); + masm.movl(rax, Address(rsi, offset_offset)); + masm.leal(rsi, Address(rbx, rax, Address::times_2, base_offset)); + + // get compare string offset and value + masm.movptr(rbx, Address(rdi, value_offset)); + masm.movl(rax, Address(rdi, offset_offset)); + masm.leal(rdi, Address(rbx, rax, Address::times_2, base_offset)); + + // Set byte count + masm.shll(rcx, 1); + masm.movl(rax, rcx); + + if (UseSSE42Intrinsics) { + // With SSE4.2, use double quad vector compare + Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; + // Compare 16-byte vectors + masm.andl(rcx, 0xfffffff0); // vector count (in bytes) + masm.andl(rax, 0x0000000e); // tail count (in bytes) + masm.testl(rcx, rcx); + masm.jccb(Assembler::zero, COMPARE_TAIL); + masm.lea(rdi, Address(rdi, rcx, Address::times_1)); + masm.lea(rsi, Address(rsi, rcx, Address::times_1)); + masm.negl(rcx); + + masm.bind(COMPARE_WIDE_VECTORS); + masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1)); + masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1)); + masm.pxor(tmp1Reg, tmp2Reg); + masm.ptest(tmp1Reg, tmp1Reg); + masm.jccb(Assembler::notZero, RET_FALSE); + masm.addl(rcx, 16); + masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); + masm.bind(COMPARE_TAIL); + masm.movl(rcx, rax); + // Fallthru to tail compare + } + + // Compare 4-byte vectors + masm.andl(rcx, 0xfffffffc); // vector count (in bytes) + masm.andl(rax, 0x00000002); // tail char (in bytes) + masm.testl(rcx, rcx); + masm.jccb(Assembler::zero, COMPARE_CHAR); + masm.lea(rdi, Address(rdi, rcx, Address::times_1)); + masm.lea(rsi, Address(rsi, rcx, Address::times_1)); + masm.negl(rcx); + + masm.bind(COMPARE_VECTORS); + masm.movl(rbx, Address(rdi, rcx, Address::times_1)); + masm.cmpl(rbx, Address(rsi, rcx, Address::times_1)); + masm.jccb(Assembler::notEqual, RET_FALSE); + masm.addl(rcx, 4); + masm.jcc(Assembler::notZero, COMPARE_VECTORS); + + // Compare trailing char (final 2 bytes), if any + masm.bind(COMPARE_CHAR); + masm.testl(rax, rax); + masm.jccb(Assembler::zero, RET_TRUE); + masm.load_unsigned_short(rbx, Address(rdi, 0)); + masm.load_unsigned_short(rcx, Address(rsi, 0)); + masm.cmpl(rbx, rcx); + masm.jccb(Assembler::notEqual, RET_FALSE); + + masm.bind(RET_TRUE); + masm.movl(rax, 1); // return true + masm.jmpb(DONE); + + masm.bind(RET_FALSE); + masm.xorl(rax, rax); // return false + + masm.bind(DONE); + %} + + enc_class enc_String_IndexOf(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2, + eCXRegI tmp3, eDXRegI tmp4, eBXRegI result) %{ + // SSE4.2 version + Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR, + SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE; + MacroAssembler masm(&cbuf); + + XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); + + // Get the first character position in both strings + // [8] char array, [12] offset, [16] count + int value_offset = java_lang_String::value_offset_in_bytes(); + int offset_offset = java_lang_String::offset_offset_in_bytes(); + int count_offset = java_lang_String::count_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + + // Get counts for string and substr + masm.movl(rdx, Address(rsi, count_offset)); + masm.movl(rax, Address(rdi, count_offset)); + // Check for substr count > string count + masm.cmpl(rax, rdx); + masm.jcc(Assembler::greater, RET_NEG_ONE); + + // Start the indexOf operation + // Get start addr of string + masm.movptr(rbx, Address(rsi, value_offset)); + masm.movl(rcx, Address(rsi, offset_offset)); + masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset)); + masm.push(rsi); + + // Get start addr of substr + masm.movptr(rbx, Address(rdi, value_offset)); + masm.movl(rcx, Address(rdi, offset_offset)); + masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset)); + masm.push(rdi); + masm.push(rax); + masm.jmpb(PREP_FOR_SCAN); + + // Substr count saved at sp + // Substr saved at sp+4 + // String saved at sp+8 + + // Prep to load substr for scan + masm.bind(LOAD_SUBSTR); + masm.movptr(rdi, Address(rsp, 4)); + masm.movl(rax, Address(rsp, 0)); + + // Load substr + masm.bind(PREP_FOR_SCAN); + masm.movdqu(tmp1Reg, Address(rdi, 0)); + masm.addl(rdx, 8); // prime the loop + masm.subptr(rsi, 16); + + // Scan string for substr in 16-byte vectors + masm.bind(SCAN_TO_SUBSTR); + masm.subl(rdx, 8); + masm.addptr(rsi, 16); + masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d); + masm.jcc(Assembler::above, SCAN_TO_SUBSTR); // CF == 0 && ZF == 0 + masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0 + + // Fallthru: found a potential substr + + // Make sure string is still long enough + masm.subl(rdx, rcx); + masm.cmpl(rdx, rax); + masm.jccb(Assembler::negative, RET_NOT_FOUND); + // Compute start addr of substr + masm.lea(rsi, Address(rsi, rcx, Address::times_2)); + masm.movptr(rbx, rsi); + + // Compare potential substr + masm.addl(rdx, 8); // prime the loop + masm.addl(rax, 8); + masm.subptr(rsi, 16); + masm.subptr(rdi, 16); + + // Scan 16-byte vectors of string and substr + masm.bind(SCAN_SUBSTR); + masm.subl(rax, 8); + masm.subl(rdx, 8); + masm.addptr(rsi, 16); + masm.addptr(rdi, 16); + masm.movdqu(tmp1Reg, Address(rdi, 0)); + masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d); + masm.jcc(Assembler::noOverflow, LOAD_SUBSTR); // OF == 0 + masm.jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0 + + // Compute substr offset + masm.movptr(rsi, Address(rsp, 8)); + masm.subptr(rbx, rsi); + masm.shrl(rbx, 1); + masm.jmpb(CLEANUP); + + masm.bind(RET_NEG_ONE); + masm.movl(rbx, -1); + masm.jmpb(DONE); + + masm.bind(RET_NOT_FOUND); + masm.movl(rbx, -1); + + masm.bind(CLEANUP); + masm.addptr(rsp, 12); + + masm.bind(DONE); + %} + + enc_class enc_Array_Equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2, + eBXRegI tmp3, eDXRegI tmp4, eAXRegI result) %{ + Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR; + MacroAssembler masm(&cbuf); + + XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); + XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); + Register ary1Reg = as_Register($ary1$$reg); + Register ary2Reg = as_Register($ary2$$reg); + Register tmp3Reg = as_Register($tmp3$$reg); + Register tmp4Reg = as_Register($tmp4$$reg); + Register resultReg = as_Register($result$$reg); int length_offset = arrayOopDesc::length_offset_in_bytes(); int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); // Check the input args - masm.cmpl(ary1Reg, ary2Reg); + masm.cmpptr(ary1Reg, ary2Reg); masm.jcc(Assembler::equal, TRUE_LABEL); - masm.testl(ary1Reg, ary1Reg); + masm.testptr(ary1Reg, ary1Reg); masm.jcc(Assembler::zero, FALSE_LABEL); - masm.testl(ary2Reg, ary2Reg); + masm.testptr(ary2Reg, ary2Reg); masm.jcc(Assembler::zero, FALSE_LABEL); // Check the lengths - masm.movl(tmp2Reg, Address(ary1Reg, length_offset)); + masm.movl(tmp4Reg, Address(ary1Reg, length_offset)); masm.movl(resultReg, Address(ary2Reg, length_offset)); - masm.cmpl(tmp2Reg, resultReg); + masm.cmpl(tmp4Reg, resultReg); masm.jcc(Assembler::notEqual, FALSE_LABEL); masm.testl(resultReg, resultReg); masm.jcc(Assembler::zero, TRUE_LABEL); - // Get the number of 4 byte vectors to compare - masm.shrl(resultReg, 1); + // Load array addrs + masm.lea(ary1Reg, Address(ary1Reg, base_offset)); + masm.lea(ary2Reg, Address(ary2Reg, base_offset)); - // Check for odd-length arrays - masm.andl(tmp2Reg, 1); - masm.testl(tmp2Reg, tmp2Reg); - masm.jcc(Assembler::zero, COMPARE_LOOP_HDR); + // Set byte count + masm.shll(tmp4Reg, 1); + masm.movl(resultReg, tmp4Reg); - // Compare 2-byte "tail" at end of arrays - masm.load_unsigned_word(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset)); - masm.load_unsigned_word(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset)); - masm.cmpl(tmp1Reg, tmp2Reg); - masm.jcc(Assembler::notEqual, FALSE_LABEL); + if (UseSSE42Intrinsics) { + // With SSE4.2, use double quad vector compare + Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; + // Compare 16-byte vectors + masm.andl(tmp4Reg, 0xfffffff0); // vector count (in bytes) + masm.andl(resultReg, 0x0000000e); // tail count (in bytes) + masm.testl(tmp4Reg, tmp4Reg); + masm.jccb(Assembler::zero, COMPARE_TAIL); + masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); + masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); + masm.negl(tmp4Reg); + + masm.bind(COMPARE_WIDE_VECTORS); + masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); + masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); + masm.pxor(tmp1Reg, tmp2Reg); + masm.ptest(tmp1Reg, tmp1Reg); + + masm.jccb(Assembler::notZero, FALSE_LABEL); + masm.addl(tmp4Reg, 16); + masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); + masm.bind(COMPARE_TAIL); + masm.movl(tmp4Reg, resultReg); + // Fallthru to tail compare + } + + // Compare 4-byte vectors + masm.andl(tmp4Reg, 0xfffffffc); // vector count (in bytes) + masm.andl(resultReg, 0x00000002); // tail char (in bytes) + masm.testl(tmp4Reg, tmp4Reg); + masm.jccb(Assembler::zero, COMPARE_CHAR); + masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); + masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); + masm.negl(tmp4Reg); + + masm.bind(COMPARE_VECTORS); + masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); + masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); + masm.jccb(Assembler::notEqual, FALSE_LABEL); + masm.addl(tmp4Reg, 4); + masm.jcc(Assembler::notZero, COMPARE_VECTORS); + + // Compare trailing char (final 2 bytes), if any + masm.bind(COMPARE_CHAR); masm.testl(resultReg, resultReg); - masm.jcc(Assembler::zero, TRUE_LABEL); - - // Setup compare loop - masm.bind(COMPARE_LOOP_HDR); - // Shift tmp1Reg and tmp2Reg to the last 4-byte boundary of the arrays - masm.leal(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset)); - masm.leal(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset)); - masm.negl(resultReg); - - // 4-byte-wide compare loop - masm.bind(COMPARE_LOOP); - masm.movl(ary1Reg, Address(tmp1Reg, resultReg, Address::times_4, 0)); - masm.movl(ary2Reg, Address(tmp2Reg, resultReg, Address::times_4, 0)); - masm.cmpl(ary1Reg, ary2Reg); - masm.jcc(Assembler::notEqual, FALSE_LABEL); - masm.increment(resultReg); - masm.jcc(Assembler::notZero, COMPARE_LOOP); + masm.jccb(Assembler::zero, TRUE_LABEL); + masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0)); + masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0)); + masm.cmpl(tmp3Reg, tmp4Reg); + masm.jccb(Assembler::notEqual, FALSE_LABEL); masm.bind(TRUE_LABEL); masm.movl(resultReg, 1); // return true - masm.jmp(DONE_LABEL); + masm.jmpb(DONE); masm.bind(FALSE_LABEL); masm.xorl(resultReg, resultReg); // return false // That's it - masm.bind(DONE_LABEL); + masm.bind(DONE); %} enc_class enc_pop_rdx() %{ @@ -4297,24 +4570,6 @@ encode %{ emit_opcode(cbuf, 0xC8 + $src2$$reg); %} - enc_class enc_membar_acquire %{ - // Doug Lea believes this is not needed with current Sparcs and TSO. - // MacroAssembler masm(&cbuf); - // masm.membar(); - %} - - enc_class enc_membar_release %{ - // Doug Lea believes this is not needed with current Sparcs and TSO. - // MacroAssembler masm(&cbuf); - // masm.membar(); - %} - - enc_class enc_membar_volatile %{ - MacroAssembler masm(&cbuf); - masm.membar(Assembler::Membar_mask_bits(Assembler::StoreLoad | - Assembler::StoreStore)); - %} - // Atomically load the volatile long enc_class enc_loadL_volatile( memory mem, stackSlotL dst ) %{ emit_opcode(cbuf,0xDF); @@ -5857,7 +6112,7 @@ operand cmpOp_commute() %{ //----------OPERAND CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used as to simplify -// instruction definitions by not requiring the AD writer to specify seperate +// instruction definitions by not requiring the AD writer to specify separate // instructions for every form of operand when the instruction accepts // multiple operand types with the same basic encoding and format. The classic // case of this is memory operands. @@ -6389,6 +6644,67 @@ instruct bytes_reverse_long(eRegL dst) %{ %} +//---------- Population Count Instructions ------------------------------------- + +instruct popCountI(eRegI dst, eRegI src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI src)); + + format %{ "POPCNT $dst, $src" %} + ins_encode %{ + __ popcntl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct popCountI_mem(eRegI dst, memory mem) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI (LoadI mem))); + + format %{ "POPCNT $dst, $mem" %} + ins_encode %{ + __ popcntl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL(eRegI dst, eRegL src, eRegI tmp, eFlagsReg cr) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL src)); + effect(KILL cr, TEMP tmp, TEMP dst); + + format %{ "POPCNT $dst, $src.lo\n\t" + "POPCNT $tmp, $src.hi\n\t" + "ADD $dst, $tmp" %} + ins_encode %{ + __ popcntl($dst$$Register, $src$$Register); + __ popcntl($tmp$$Register, HIGH_FROM_LOW($src$$Register)); + __ addl($dst$$Register, $tmp$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL_mem(eRegI dst, memory mem, eRegI tmp, eFlagsReg cr) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL (LoadL mem))); + effect(KILL cr, TEMP tmp, TEMP dst); + + format %{ "POPCNT $dst, $mem\n\t" + "POPCNT $tmp, $mem+4\n\t" + "ADD $dst, $tmp" %} + ins_encode %{ + //__ popcntl($dst$$Register, $mem$$Address$$first); + //__ popcntl($tmp$$Register, $mem$$Address$$second); + __ popcntl($dst$$Register, Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, false)); + __ popcntl($tmp$$Register, Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, false)); + __ addl($dst$$Register, $tmp$$Register); + %} + ins_pipe(ialu_reg); +%} + + //----------Load/Store/Move Instructions--------------------------------------- //----------Load Instructions-------------------------------------------------- // Load Byte (8bit signed) @@ -6396,21 +6712,94 @@ instruct loadB(xRegI dst, memory mem) %{ match(Set dst (LoadB mem)); ins_cost(125); - format %{ "MOVSX8 $dst,$mem" %} - opcode(0xBE, 0x0F); - ins_encode( OpcS, OpcP, RegMem(dst,mem)); - ins_pipe( ialu_reg_mem ); + format %{ "MOVSX8 $dst,$mem\t# byte" %} + + ins_encode %{ + __ movsbl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); %} -// Load Byte (8bit UNsigned) -instruct loadUB(xRegI dst, memory mem, immI_255 bytemask) %{ - match(Set dst (AndI (LoadB mem) bytemask)); +// Load Byte (8bit signed) into Long Register +instruct loadB2L(eRegL dst, memory mem) %{ + match(Set dst (ConvI2L (LoadB mem))); + + ins_cost(375); + format %{ "MOVSX8 $dst.lo,$mem\t# byte -> long\n\t" + "MOV $dst.hi,$dst.lo\n\t" + "SAR $dst.hi,7" %} + + ins_encode %{ + __ movsbl($dst$$Register, $mem$$Address); + __ movl(HIGH_FROM_LOW($dst$$Register), $dst$$Register); // This is always a different register. + __ sarl(HIGH_FROM_LOW($dst$$Register), 7); // 24+1 MSB are already signed extended. + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Byte (8bit UNsigned) +instruct loadUB(xRegI dst, memory mem) %{ + match(Set dst (LoadUB mem)); ins_cost(125); - format %{ "MOVZX8 $dst,$mem" %} - opcode(0xB6, 0x0F); - ins_encode( OpcS, OpcP, RegMem(dst,mem)); - ins_pipe( ialu_reg_mem ); + format %{ "MOVZX8 $dst,$mem\t# ubyte -> int" %} + + ins_encode %{ + __ movzbl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Byte (8 bit UNsigned) into Long Register +instruct loadUB2L(eRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadUB mem))); + + ins_cost(250); + format %{ "MOVZX8 $dst.lo,$mem\t# ubyte -> long\n\t" + "XOR $dst.hi,$dst.hi" %} + + ins_encode %{ + __ movzbl($dst$$Register, $mem$$Address); + __ xorl(HIGH_FROM_LOW($dst$$Register), HIGH_FROM_LOW($dst$$Register)); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Short (16bit signed) +instruct loadS(eRegI dst, memory mem) %{ + match(Set dst (LoadS mem)); + + ins_cost(125); + format %{ "MOVSX $dst,$mem\t# short" %} + + ins_encode %{ + __ movswl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Short (16bit signed) into Long Register +instruct loadS2L(eRegL dst, memory mem) %{ + match(Set dst (ConvI2L (LoadS mem))); + + ins_cost(375); + format %{ "MOVSX $dst.lo,$mem\t# short -> long\n\t" + "MOV $dst.hi,$dst.lo\n\t" + "SAR $dst.hi,15" %} + + ins_encode %{ + __ movswl($dst$$Register, $mem$$Address); + __ movl(HIGH_FROM_LOW($dst$$Register), $dst$$Register); // This is always a different register. + __ sarl(HIGH_FROM_LOW($dst$$Register), 15); // 16+1 MSB are already signed extended. + %} + + ins_pipe(ialu_reg_mem); %} // Load Unsigned Short/Char (16bit unsigned) @@ -6418,10 +6807,30 @@ instruct loadUS(eRegI dst, memory mem) %{ match(Set dst (LoadUS mem)); ins_cost(125); - format %{ "MOVZX $dst,$mem" %} - opcode(0xB7, 0x0F); - ins_encode( OpcS, OpcP, RegMem(dst,mem)); - ins_pipe( ialu_reg_mem ); + format %{ "MOVZX $dst,$mem\t# ushort/char -> int" %} + + ins_encode %{ + __ movzwl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Short/Char (16 bit UNsigned) into Long Register +instruct loadUS2L(eRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadUS mem))); + + ins_cost(250); + format %{ "MOVZX $dst.lo,$mem\t# ushort/char -> long\n\t" + "XOR $dst.hi,$dst.hi" %} + + ins_encode %{ + __ movzwl($dst$$Register, $mem$$Address); + __ xorl(HIGH_FROM_LOW($dst$$Register), HIGH_FROM_LOW($dst$$Register)); + %} + + ins_pipe(ialu_reg_mem); %} // Load Integer @@ -6429,10 +6838,47 @@ instruct loadI(eRegI dst, memory mem) %{ match(Set dst (LoadI mem)); ins_cost(125); - format %{ "MOV $dst,$mem" %} - opcode(0x8B); - ins_encode( OpcP, RegMem(dst,mem)); - ins_pipe( ialu_reg_mem ); + format %{ "MOV $dst,$mem\t# int" %} + + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Integer into Long Register +instruct loadI2L(eRegL dst, memory mem) %{ + match(Set dst (ConvI2L (LoadI mem))); + + ins_cost(375); + format %{ "MOV $dst.lo,$mem\t# int -> long\n\t" + "MOV $dst.hi,$dst.lo\n\t" + "SAR $dst.hi,31" %} + + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + __ movl(HIGH_FROM_LOW($dst$$Register), $dst$$Register); // This is always a different register. + __ sarl(HIGH_FROM_LOW($dst$$Register), 31); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Integer into Long Register +instruct loadUI2L(eRegL dst, memory mem) %{ + match(Set dst (LoadUI2L mem)); + + ins_cost(250); + format %{ "MOV $dst.lo,$mem\t# uint -> long\n\t" + "XOR $dst.hi,$dst.hi" %} + + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + __ xorl(HIGH_FROM_LOW($dst$$Register), HIGH_FROM_LOW($dst$$Register)); + %} + + ins_pipe(ialu_reg_mem); %} // Load Long. Cannot clobber address while loading, so restrict address @@ -6442,11 +6888,17 @@ instruct loadL(eRegL dst, load_long_memory mem) %{ match(Set dst (LoadL mem)); ins_cost(250); - format %{ "MOV $dst.lo,$mem\n\t" + format %{ "MOV $dst.lo,$mem\t# long\n\t" "MOV $dst.hi,$mem+4" %} - opcode(0x8B, 0x8B); - ins_encode( OpcP, RegMem(dst,mem), OpcS, RegMem_Hi(dst,mem)); - ins_pipe( ialu_reg_long_mem ); + + ins_encode %{ + Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, false); + Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, false); + __ movl($dst$$Register, Amemlo); + __ movl(HIGH_FROM_LOW($dst$$Register), Amemhi); + %} + + ins_pipe(ialu_reg_long_mem); %} // Volatile Load Long. Must be atomic, so do 64-bit FILD @@ -6521,17 +6973,6 @@ instruct loadKlass(eRegP dst, memory mem) %{ ins_pipe( ialu_reg_mem ); %} -// Load Short (16bit signed) -instruct loadS(eRegI dst, memory mem) %{ - match(Set dst (LoadS mem)); - - ins_cost(125); - format %{ "MOVSX $dst,$mem" %} - opcode(0xBF, 0x0F); - ins_encode( OpcS, OpcP, RegMem(dst,mem)); - ins_pipe( ialu_reg_mem ); -%} - // Load Double instruct loadD(regD dst, memory mem) %{ predicate(UseSSE<=1); @@ -7321,9 +7762,9 @@ instruct membar_acquire() %{ ins_cost(400); size(0); - format %{ "MEMBAR-acquire" %} - ins_encode( enc_membar_acquire ); - ins_pipe(pipe_slow); + format %{ "MEMBAR-acquire ! (empty encoding)" %} + ins_encode(); + ins_pipe(empty); %} instruct membar_acquire_lock() %{ @@ -7342,9 +7783,9 @@ instruct membar_release() %{ ins_cost(400); size(0); - format %{ "MEMBAR-release" %} - ins_encode( enc_membar_release ); - ins_pipe(pipe_slow); + format %{ "MEMBAR-release ! (empty encoding)" %} + ins_encode( ); + ins_pipe(empty); %} instruct membar_release_lock() %{ @@ -7358,12 +7799,22 @@ instruct membar_release_lock() %{ ins_pipe(empty); %} -instruct membar_volatile() %{ +instruct membar_volatile(eFlagsReg cr) %{ match(MemBarVolatile); + effect(KILL cr); ins_cost(400); - format %{ "MEMBAR-volatile" %} - ins_encode( enc_membar_volatile ); + format %{ + $$template + if (os::is_MP()) { + $$emit$$"LOCK ADDL [ESP + #0], 0\t! membar_volatile" + } else { + $$emit$$"MEMBAR-volatile ! (empty encoding)" + } + %} + ins_encode %{ + __ membar(Assembler::StoreLoad); + %} ins_pipe(pipe_slow); %} @@ -7957,7 +8408,7 @@ instruct storeLConditional( memory mem, eADXRegL oldval, eBCXRegL newval, eFlags __ xchgl(as_Register(EBX_enc), as_Register(ECX_enc)); if( os::is_MP() ) __ lock(); - __ cmpxchg8(Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp)); + __ cmpxchg8($mem$$Address); __ xchgl(as_Register(EBX_enc), as_Register(ECX_enc)); %} ins_pipe( pipe_cmpxchg ); @@ -11467,6 +11918,7 @@ instruct convI2X_reg(regX dst, eRegI src) %{ instruct convI2L_reg( eRegL dst, eRegI src, eFlagsReg cr) %{ match(Set dst (ConvI2L src)); effect(KILL cr); + ins_cost(375); format %{ "MOV $dst.lo,$src\n\t" "MOV $dst.hi,$src\n\t" "SAR $dst.hi,31" %} @@ -11478,6 +11930,7 @@ instruct convI2L_reg( eRegL dst, eRegI src, eFlagsReg cr) %{ instruct convI2L_reg_zex(eRegL dst, eRegI src, immL_32bits mask, eFlagsReg flags ) %{ match(Set dst (AndL (ConvI2L src) mask) ); effect( KILL flags ); + ins_cost(250); format %{ "MOV $dst.lo,$src\n\t" "XOR $dst.hi,$dst.hi" %} opcode(0x33); // XOR @@ -11489,6 +11942,7 @@ instruct convI2L_reg_zex(eRegL dst, eRegI src, immL_32bits mask, eFlagsReg flags instruct zerox_long(eRegL dst, eRegL src, immL_32bits mask, eFlagsReg flags ) %{ match(Set dst (AndL src mask) ); effect( KILL flags ); + ins_cost(250); format %{ "MOV $dst.lo,$src.lo\n\t" "XOR $dst.hi,$dst.hi\n\t" %} opcode(0x33); // XOR @@ -11902,11 +12356,8 @@ instruct Repl2F_immXF0(regXD dst, immXF0 zero) %{ ins_pipe( fpu_reg_reg ); %} - - // ======================================================================= // fast clearing of an array - instruct rep_stos(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlagsReg cr) %{ match(Set dummy (ClearArray cnt base)); effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr); @@ -11920,24 +12371,48 @@ instruct rep_stos(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlag ins_pipe( pipe_slow ); %} -instruct string_compare(eDIRegP str1, eSIRegP str2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result, eFlagsReg cr) %{ +instruct string_compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2, + eAXRegI tmp3, eBXRegI tmp4, eCXRegI result, eFlagsReg cr) %{ match(Set result (StrComp str1 str2)); - effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL cr); + effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr); //ins_cost(300); format %{ "String Compare $str1,$str2 -> $result // KILL EAX, EBX" %} - ins_encode( enc_String_Compare() ); + ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); + ins_pipe( pipe_slow ); +%} + +// fast string equals +instruct string_equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2, + eBXRegI tmp3, eCXRegI tmp4, eAXRegI result, eFlagsReg cr) %{ + match(Set result (StrEquals str1 str2)); + effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr); + + format %{ "String Equals $str1,$str2 -> $result // KILL EBX, ECX" %} + ins_encode( enc_String_Equals(tmp1, tmp2, str1, str2, tmp3, tmp4, result) ); + ins_pipe( pipe_slow ); +%} + +instruct string_indexof(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2, + eCXRegI tmp3, eDXRegI tmp4, eBXRegI result, eFlagsReg cr) %{ + predicate(UseSSE42Intrinsics); + match(Set result (StrIndexOf str1 str2)); + effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr); + + format %{ "String IndexOf $str1,$str2 -> $result // KILL EAX, ECX, EDX" %} + ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); ins_pipe( pipe_slow ); %} // fast array equals -instruct array_equals(eDIRegP ary1, eSIRegP ary2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result, eFlagsReg cr) %{ +instruct array_equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2, eBXRegI tmp3, + eDXRegI tmp4, eAXRegI result, eFlagsReg cr) %{ match(Set result (AryEq ary1 ary2)); - effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL cr); + effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); //ins_cost(300); - format %{ "Array Equals $ary1,$ary2 -> $result // KILL EAX, EBX" %} - ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result) ); + format %{ "Array Equals $ary1,$ary2 -> $result // KILL EBX, EDX" %} + ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) ); ins_pipe( pipe_slow ); %} @@ -12375,15 +12850,12 @@ instruct partialSubtypeCheck( eDIRegP result, eSIRegP sub, eAXRegP super, eCXReg effect( KILL rcx, KILL cr ); ins_cost(1100); // slightly larger than the next version - format %{ "CMPL EAX,ESI\n\t" - "JEQ,s hit\n\t" - "MOV EDI,[$sub+Klass::secondary_supers]\n\t" + format %{ "MOV EDI,[$sub+Klass::secondary_supers]\n\t" "MOV ECX,[EDI+arrayKlass::length]\t# length to scan\n\t" "ADD EDI,arrayKlass::base_offset\t# Skip to start of data; set NZ in case count is zero\n\t" "REPNE SCASD\t# Scan *EDI++ for a match with EAX while CX-- != 0\n\t" "JNE,s miss\t\t# Missed: EDI not-zero\n\t" "MOV [$sub+Klass::secondary_super_cache],$super\t# Hit: update cache\n\t" - "hit:\n\t" "XOR $result,$result\t\t Hit: EDI zero\n\t" "miss:\t" %} @@ -12397,9 +12869,7 @@ instruct partialSubtypeCheck_vs_Zero( eFlagsReg cr, eSIRegP sub, eAXRegP super, effect( KILL rcx, KILL result ); ins_cost(1000); - format %{ "CMPL EAX,ESI\n\t" - "JEQ,s miss\t# Actually a hit; we are done.\n\t" - "MOV EDI,[$sub+Klass::secondary_supers]\n\t" + format %{ "MOV EDI,[$sub+Klass::secondary_supers]\n\t" "MOV ECX,[EDI+arrayKlass::length]\t# length to scan\n\t" "ADD EDI,arrayKlass::base_offset\t# Skip to start of data; set NZ in case count is zero\n\t" "REPNE SCASD\t# Scan *EDI++ for a match with EAX while CX-- != 0\n\t" @@ -13220,7 +13690,7 @@ instruct safePoint_poll(eFlagsReg cr) %{ // These must follow all instruction definitions as they use the names // defined in the instructions definitions. // -// peepmatch ( root_instr_name [preceeding_instruction]* ); +// peepmatch ( root_instr_name [preceding_instruction]* ); // // peepconstraint %{ // (instruction_number.operand_name relational_op instruction_number.operand_name diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index ad4f03b23a3..892b0863128 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -1,5 +1,5 @@ // -// Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -326,7 +326,6 @@ reg_class ptr_no_rax_reg(RDX, RDX_H, R9, R9_H, R10, R10_H, R11, R11_H, - R12, R12_H, R13, R13_H, R14, R14_H); @@ -340,7 +339,6 @@ reg_class ptr_no_rbp_reg(RDX, RDX_H, R9, R9_H, R10, R10_H, R11, R11_H, - R12, R12_H, R13, R13_H, R14, R14_H); @@ -354,7 +352,6 @@ reg_class ptr_no_rax_rbx_reg(RDX, RDX_H, R9, R9_H, R10, R10_H, R11, R11_H, - R12, R12_H, R13, R13_H, R14, R14_H); @@ -444,9 +441,6 @@ reg_class long_rcx_reg(RCX, RCX_H); // Singleton class for RDX long register reg_class long_rdx_reg(RDX, RDX_H); -// Singleton class for R12 long register -reg_class long_r12_reg(R12, R12_H); - // Class for all int registers (except RSP) reg_class int_reg(RAX, RDX, @@ -1842,7 +1836,9 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { if (UseCompressedOops) { st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes() #%d]\t", oopDesc::klass_offset_in_bytes()); - st->print_cr("leaq rscratch1, [r12_heapbase, r, Address::times_8, 0]"); + if (Universe::narrow_oop_shift() != 0) { + st->print_cr("leaq rscratch1, [r12_heapbase, r, Address::times_8, 0]"); + } st->print_cr("cmpq rax, rscratch1\t # Inline cache check"); } else { st->print_cr("cmpq rax, [j_rarg0 + oopDesc::klass_offset_in_bytes() #%d]\t" @@ -1891,7 +1887,11 @@ void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const uint MachUEPNode::size(PhaseRegAlloc* ra_) const { if (UseCompressedOops) { - return OptoBreakpoint ? 19 : 20; + if (Universe::narrow_oop_shift() == 0) { + return OptoBreakpoint ? 15 : 16; + } else { + return OptoBreakpoint ? 19 : 20; + } } else { return OptoBreakpoint ? 11 : 12; } @@ -2575,45 +2575,13 @@ encode %{ Register Rrax = as_Register(RAX_enc); // super class Register Rrcx = as_Register(RCX_enc); // killed Register Rrsi = as_Register(RSI_enc); // sub class - Label hit, miss, cmiss; + Label miss; + const bool set_cond_codes = true; MacroAssembler _masm(&cbuf); - // Compare super with sub directly, since super is not in its own SSA. - // The compiler used to emit this test, but we fold it in here, - // to allow platform-specific tweaking on sparc. - __ cmpptr(Rrax, Rrsi); - __ jcc(Assembler::equal, hit); -#ifndef PRODUCT - __ lea(Rrcx, ExternalAddress((address)&SharedRuntime::_partial_subtype_ctr)); - __ incrementl(Address(Rrcx, 0)); -#endif //PRODUCT - __ movptr(Rrdi, Address(Rrsi, - sizeof(oopDesc) + - Klass::secondary_supers_offset_in_bytes())); - __ movl(Rrcx, Address(Rrdi, arrayOopDesc::length_offset_in_bytes())); - __ addptr(Rrdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - if (UseCompressedOops) { - __ encode_heap_oop(Rrax); - __ repne_scanl(); - __ jcc(Assembler::notEqual, cmiss); - __ decode_heap_oop(Rrax); - __ movptr(Address(Rrsi, - sizeof(oopDesc) + - Klass::secondary_super_cache_offset_in_bytes()), - Rrax); - __ jmp(hit); - __ bind(cmiss); - __ decode_heap_oop(Rrax); - __ jmp(miss); - } else { - __ repne_scan(); - __ jcc(Assembler::notEqual, miss); - __ movptr(Address(Rrsi, - sizeof(oopDesc) + - Klass::secondary_super_cache_offset_in_bytes()), - Rrax); - } - __ bind(hit); + __ check_klass_subtype_slow_path(Rrsi, Rrax, Rrcx, Rrdi, + NULL, &miss, + /*set_cond_codes:*/ true); if ($primary) { __ xorptr(Rrdi, Rrdi); } @@ -3462,14 +3430,12 @@ encode %{ enc_class movq_ld(regD dst, memory mem) %{ MacroAssembler _masm(&cbuf); - Address madr = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - __ movq(as_XMMRegister($dst$$reg), madr); + __ movq($dst$$XMMRegister, $mem$$Address); %} enc_class movq_st(memory mem, regD src) %{ MacroAssembler _masm(&cbuf); - Address madr = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - __ movq(madr, as_XMMRegister($src$$reg)); + __ movq($mem$$Address, $src$$XMMRegister); %} enc_class pshufd_8x8(regF dst, regF src) %{ @@ -3728,13 +3694,16 @@ encode %{ } %} - enc_class enc_String_Compare() - %{ + enc_class enc_String_Compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, + rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{ Label RCX_GOOD_LABEL, LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, CONT_LABEL, WHILE_HEAD_LABEL; MacroAssembler masm(&cbuf); + XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); + XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); + // Get the first character position in both strings // [8] char array, [12] offset, [16] count int value_offset = java_lang_String::value_offset_in_bytes(); @@ -3752,6 +3721,7 @@ encode %{ // Compute the minimum of the string lengths(rsi) and the // difference of the string lengths (stack) + // do the conditional move stuff masm.movl(rdi, Address(rdi, count_offset)); masm.movl(rsi, Address(rsi, count_offset)); masm.movl(rcx, rdi); @@ -3765,8 +3735,8 @@ encode %{ masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL); // Load first characters - masm.load_unsigned_word(rcx, Address(rbx, 0)); - masm.load_unsigned_word(rdi, Address(rax, 0)); + masm.load_unsigned_short(rcx, Address(rbx, 0)); + masm.load_unsigned_short(rdi, Address(rax, 0)); // Compare first characters masm.subl(rcx, rdi); @@ -3779,7 +3749,7 @@ encode %{ Label LSkip2; // Check if the strings start at same location masm.cmpptr(rbx, rax); - masm.jcc(Assembler::notEqual, LSkip2); + masm.jccb(Assembler::notEqual, LSkip2); // Check if the length difference is zero (from stack) masm.cmpl(Address(rsp, 0), 0x0); @@ -3789,103 +3759,382 @@ encode %{ masm.bind(LSkip2); } + // Advance to next character + masm.addptr(rax, 2); + masm.addptr(rbx, 2); + + if (UseSSE42Intrinsics) { + // With SSE4.2, use double quad vector compare + Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL; + // Setup to compare 16-byte vectors + masm.movl(rdi, rsi); + masm.andl(rsi, 0xfffffff8); // rsi holds the vector count + masm.andl(rdi, 0x00000007); // rdi holds the tail count + masm.testl(rsi, rsi); + masm.jccb(Assembler::zero, COMPARE_TAIL); + + masm.lea(rax, Address(rax, rsi, Address::times_2)); + masm.lea(rbx, Address(rbx, rsi, Address::times_2)); + masm.negptr(rsi); + + masm.bind(COMPARE_VECTORS); + masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2)); + masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2)); + masm.pxor(tmp1Reg, tmp2Reg); + masm.ptest(tmp1Reg, tmp1Reg); + masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL); + masm.addptr(rsi, 8); + masm.jcc(Assembler::notZero, COMPARE_VECTORS); + masm.jmpb(COMPARE_TAIL); + + // Mismatched characters in the vectors + masm.bind(VECTOR_NOT_EQUAL); + masm.lea(rax, Address(rax, rsi, Address::times_2)); + masm.lea(rbx, Address(rbx, rsi, Address::times_2)); + masm.movl(rdi, 8); + + // Compare tail (< 8 chars), or rescan last vectors to + // find 1st mismatched characters + masm.bind(COMPARE_TAIL); + masm.testl(rdi, rdi); + masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL); + masm.movl(rsi, rdi); + // Fallthru to tail compare + } + // Shift RAX and RBX to the end of the arrays, negate min - masm.lea(rax, Address(rax, rsi, Address::times_2, 2)); - masm.lea(rbx, Address(rbx, rsi, Address::times_2, 2)); + masm.lea(rax, Address(rax, rsi, Address::times_2, 0)); + masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0)); masm.negptr(rsi); // Compare the rest of the characters masm.bind(WHILE_HEAD_LABEL); - masm.load_unsigned_word(rcx, Address(rbx, rsi, Address::times_2, 0)); - masm.load_unsigned_word(rdi, Address(rax, rsi, Address::times_2, 0)); + masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0)); + masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0)); masm.subl(rcx, rdi); - masm.jcc(Assembler::notZero, POP_LABEL); + masm.jccb(Assembler::notZero, POP_LABEL); masm.increment(rsi); masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL); // Strings are equal up to min length. Return the length difference. masm.bind(LENGTH_DIFF_LABEL); masm.pop(rcx); - masm.jmp(DONE_LABEL); + masm.jmpb(DONE_LABEL); // Discard the stored length difference masm.bind(POP_LABEL); masm.addptr(rsp, 8); - + // That's it masm.bind(DONE_LABEL); %} - enc_class enc_Array_Equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI tmp1, rbx_RegI tmp2, rcx_RegI result) %{ - Label TRUE_LABEL, FALSE_LABEL, DONE_LABEL, COMPARE_LOOP_HDR, COMPARE_LOOP; + enc_class enc_String_IndexOf(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2, + rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result) %{ + // SSE4.2 version + Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR, + SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE; MacroAssembler masm(&cbuf); - Register ary1Reg = as_Register($ary1$$reg); - Register ary2Reg = as_Register($ary2$$reg); - Register tmp1Reg = as_Register($tmp1$$reg); - Register tmp2Reg = as_Register($tmp2$$reg); - Register resultReg = as_Register($result$$reg); + XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); + + // Get the first character position in both strings + // [8] char array, [12] offset, [16] count + int value_offset = java_lang_String::value_offset_in_bytes(); + int offset_offset = java_lang_String::offset_offset_in_bytes(); + int count_offset = java_lang_String::count_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + + // Get counts for string and substr + masm.movl(rdx, Address(rsi, count_offset)); + masm.movl(rax, Address(rdi, count_offset)); + // Check for substr count > string count + masm.cmpl(rax, rdx); + masm.jcc(Assembler::greater, RET_NEG_ONE); + + // Start the indexOf operation + // Get start addr of string + masm.load_heap_oop(rbx, Address(rsi, value_offset)); + masm.movl(rcx, Address(rsi, offset_offset)); + masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset)); + masm.push(rsi); + + // Get start addr of substr + masm.load_heap_oop(rbx, Address(rdi, value_offset)); + masm.movl(rcx, Address(rdi, offset_offset)); + masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset)); + masm.push(rdi); + masm.push(rax); + masm.jmpb(PREP_FOR_SCAN); + + // Substr count saved at sp + // Substr saved at sp+8 + // String saved at sp+16 + + // Prep to load substr for scan + masm.bind(LOAD_SUBSTR); + masm.movptr(rdi, Address(rsp, 8)); + masm.movl(rax, Address(rsp, 0)); + + // Load substr + masm.bind(PREP_FOR_SCAN); + masm.movdqu(tmp1Reg, Address(rdi, 0)); + masm.addq(rdx, 8); // prime the loop + masm.subptr(rsi, 16); + + // Scan string for substr in 16-byte vectors + masm.bind(SCAN_TO_SUBSTR); + masm.subq(rdx, 8); + masm.addptr(rsi, 16); + masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d); + masm.jcc(Assembler::above, SCAN_TO_SUBSTR); + masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND); + + // Fallthru: found a potential substr + + //Make sure string is still long enough + masm.subl(rdx, rcx); + masm.cmpl(rdx, rax); + masm.jccb(Assembler::negative, RET_NOT_FOUND); + // Compute start addr of substr + masm.lea(rsi, Address(rsi, rcx, Address::times_2)); + masm.movptr(rbx, rsi); + + // Compare potential substr + masm.addq(rdx, 8); // prime the loop + masm.addq(rax, 8); + masm.subptr(rsi, 16); + masm.subptr(rdi, 16); + + // Scan 16-byte vectors of string and substr + masm.bind(SCAN_SUBSTR); + masm.subq(rax, 8); + masm.subq(rdx, 8); + masm.addptr(rsi, 16); + masm.addptr(rdi, 16); + masm.movdqu(tmp1Reg, Address(rdi, 0)); + masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d); + masm.jcc(Assembler::noOverflow, LOAD_SUBSTR); // OF == 0 + masm.jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0 + + // Compute substr offset + masm.movptr(rsi, Address(rsp, 16)); + masm.subptr(rbx, rsi); + masm.shrl(rbx, 1); + masm.jmpb(CLEANUP); + + masm.bind(RET_NEG_ONE); + masm.movl(rbx, -1); + masm.jmpb(DONE); + + masm.bind(RET_NOT_FOUND); + masm.movl(rbx, -1); + + masm.bind(CLEANUP); + masm.addptr(rsp, 24); + + masm.bind(DONE); + %} + + enc_class enc_String_Equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, + rbx_RegI tmp3, rcx_RegI tmp2, rax_RegI result) %{ + Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR; + MacroAssembler masm(&cbuf); + + XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); + XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); + + int value_offset = java_lang_String::value_offset_in_bytes(); + int offset_offset = java_lang_String::offset_offset_in_bytes(); + int count_offset = java_lang_String::count_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + + // does source == target string? + masm.cmpptr(rdi, rsi); + masm.jcc(Assembler::equal, RET_TRUE); + + // get and compare counts + masm.movl(rcx, Address(rdi, count_offset)); + masm.movl(rax, Address(rsi, count_offset)); + masm.cmpl(rcx, rax); + masm.jcc(Assembler::notEqual, RET_FALSE); + masm.testl(rax, rax); + masm.jcc(Assembler::zero, RET_TRUE); + + // get source string offset and value + masm.load_heap_oop(rbx, Address(rsi, value_offset)); + masm.movl(rax, Address(rsi, offset_offset)); + masm.lea(rsi, Address(rbx, rax, Address::times_2, base_offset)); + + // get compare string offset and value + masm.load_heap_oop(rbx, Address(rdi, value_offset)); + masm.movl(rax, Address(rdi, offset_offset)); + masm.lea(rdi, Address(rbx, rax, Address::times_2, base_offset)); + + // Set byte count + masm.shll(rcx, 1); + masm.movl(rax, rcx); + + if (UseSSE42Intrinsics) { + // With SSE4.2, use double quad vector compare + Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; + // Compare 16-byte vectors + masm.andl(rcx, 0xfffffff0); // vector count (in bytes) + masm.andl(rax, 0x0000000e); // tail count (in bytes) + masm.testl(rcx, rcx); + masm.jccb(Assembler::zero, COMPARE_TAIL); + masm.lea(rdi, Address(rdi, rcx, Address::times_1)); + masm.lea(rsi, Address(rsi, rcx, Address::times_1)); + masm.negptr(rcx); + + masm.bind(COMPARE_WIDE_VECTORS); + masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1)); + masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1)); + masm.pxor(tmp1Reg, tmp2Reg); + masm.ptest(tmp1Reg, tmp1Reg); + masm.jccb(Assembler::notZero, RET_FALSE); + masm.addptr(rcx, 16); + masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); + masm.bind(COMPARE_TAIL); + masm.movl(rcx, rax); + // Fallthru to tail compare + } + + // Compare 4-byte vectors + masm.andl(rcx, 0xfffffffc); // vector count (in bytes) + masm.andl(rax, 0x00000002); // tail char (in bytes) + masm.testl(rcx, rcx); + masm.jccb(Assembler::zero, COMPARE_CHAR); + masm.lea(rdi, Address(rdi, rcx, Address::times_1)); + masm.lea(rsi, Address(rsi, rcx, Address::times_1)); + masm.negptr(rcx); + + masm.bind(COMPARE_VECTORS); + masm.movl(rbx, Address(rdi, rcx, Address::times_1)); + masm.cmpl(rbx, Address(rsi, rcx, Address::times_1)); + masm.jccb(Assembler::notEqual, RET_FALSE); + masm.addptr(rcx, 4); + masm.jcc(Assembler::notZero, COMPARE_VECTORS); + + // Compare trailing char (final 2 bytes), if any + masm.bind(COMPARE_CHAR); + masm.testl(rax, rax); + masm.jccb(Assembler::zero, RET_TRUE); + masm.load_unsigned_short(rbx, Address(rdi, 0)); + masm.load_unsigned_short(rcx, Address(rsi, 0)); + masm.cmpl(rbx, rcx); + masm.jccb(Assembler::notEqual, RET_FALSE); + + masm.bind(RET_TRUE); + masm.movl(rax, 1); // return true + masm.jmpb(DONE); + + masm.bind(RET_FALSE); + masm.xorl(rax, rax); // return false + + masm.bind(DONE); + %} + + enc_class enc_Array_Equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2, + rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{ + Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR; + MacroAssembler masm(&cbuf); + + XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); + XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); + Register ary1Reg = as_Register($ary1$$reg); + Register ary2Reg = as_Register($ary2$$reg); + Register tmp3Reg = as_Register($tmp3$$reg); + Register tmp4Reg = as_Register($tmp4$$reg); + Register resultReg = as_Register($result$$reg); int length_offset = arrayOopDesc::length_offset_in_bytes(); int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); // Check the input args - masm.cmpq(ary1Reg, ary2Reg); + masm.cmpq(ary1Reg, ary2Reg); masm.jcc(Assembler::equal, TRUE_LABEL); - masm.testq(ary1Reg, ary1Reg); + masm.testq(ary1Reg, ary1Reg); masm.jcc(Assembler::zero, FALSE_LABEL); - masm.testq(ary2Reg, ary2Reg); + masm.testq(ary2Reg, ary2Reg); masm.jcc(Assembler::zero, FALSE_LABEL); // Check the lengths - masm.movl(tmp2Reg, Address(ary1Reg, length_offset)); + masm.movl(tmp4Reg, Address(ary1Reg, length_offset)); masm.movl(resultReg, Address(ary2Reg, length_offset)); - masm.cmpl(tmp2Reg, resultReg); + masm.cmpl(tmp4Reg, resultReg); masm.jcc(Assembler::notEqual, FALSE_LABEL); masm.testl(resultReg, resultReg); masm.jcc(Assembler::zero, TRUE_LABEL); - // Get the number of 4 byte vectors to compare - masm.shrl(resultReg, 1); + //load array address + masm.lea(ary1Reg, Address(ary1Reg, base_offset)); + masm.lea(ary2Reg, Address(ary2Reg, base_offset)); - // Check for odd-length arrays - masm.andl(tmp2Reg, 1); - masm.testl(tmp2Reg, tmp2Reg); - masm.jcc(Assembler::zero, COMPARE_LOOP_HDR); + //set byte count + masm.shll(tmp4Reg, 1); + masm.movl(resultReg,tmp4Reg); - // Compare 2-byte "tail" at end of arrays - masm.load_unsigned_word(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset)); - masm.load_unsigned_word(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset)); - masm.cmpl(tmp1Reg, tmp2Reg); - masm.jcc(Assembler::notEqual, FALSE_LABEL); + if (UseSSE42Intrinsics){ + // With SSE4.2, use double quad vector compare + Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; + // Compare 16-byte vectors + masm.andl(tmp4Reg, 0xfffffff0); // vector count (in bytes) + masm.andl(resultReg, 0x0000000e); // tail count (in bytes) + masm.testl(tmp4Reg, tmp4Reg); + masm.jccb(Assembler::zero, COMPARE_TAIL); + masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); + masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); + masm.negptr(tmp4Reg); + + masm.bind(COMPARE_WIDE_VECTORS); + masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); + masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); + masm.pxor(tmp1Reg, tmp2Reg); + masm.ptest(tmp1Reg, tmp1Reg); + + masm.jccb(Assembler::notZero, FALSE_LABEL); + masm.addptr(tmp4Reg, 16); + masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); + masm.bind(COMPARE_TAIL); + masm.movl(tmp4Reg, resultReg); + // Fallthru to tail compare + } + + // Compare 4-byte vectors + masm.andl(tmp4Reg, 0xfffffffc); // vector count (in bytes) + masm.andl(resultReg, 0x00000002); // tail char (in bytes) + masm.testl(tmp4Reg, tmp4Reg); //if tmp2 == 0, only compare char + masm.jccb(Assembler::zero, COMPARE_CHAR); + masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); + masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); + masm.negptr(tmp4Reg); + + masm.bind(COMPARE_VECTORS); + masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); + masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); + masm.jccb(Assembler::notEqual, FALSE_LABEL); + masm.addptr(tmp4Reg, 4); + masm.jcc(Assembler::notZero, COMPARE_VECTORS); + + // Compare trailing char (final 2 bytes), if any + masm.bind(COMPARE_CHAR); masm.testl(resultReg, resultReg); - masm.jcc(Assembler::zero, TRUE_LABEL); - - // Setup compare loop - masm.bind(COMPARE_LOOP_HDR); - // Shift tmp1Reg and tmp2Reg to the last 4-byte boundary of the arrays - masm.leaq(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset)); - masm.leaq(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset)); - masm.negq(resultReg); - - // 4-byte-wide compare loop - masm.bind(COMPARE_LOOP); - masm.movl(ary1Reg, Address(tmp1Reg, resultReg, Address::times_4, 0)); - masm.movl(ary2Reg, Address(tmp2Reg, resultReg, Address::times_4, 0)); - masm.cmpl(ary1Reg, ary2Reg); - masm.jcc(Assembler::notEqual, FALSE_LABEL); - masm.incrementq(resultReg); - masm.jcc(Assembler::notZero, COMPARE_LOOP); + masm.jccb(Assembler::zero, TRUE_LABEL); + masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0)); + masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0)); + masm.cmpl(tmp3Reg, tmp4Reg); + masm.jccb(Assembler::notEqual, FALSE_LABEL); masm.bind(TRUE_LABEL); masm.movl(resultReg, 1); // return true - masm.jmp(DONE_LABEL); + masm.jmpb(DONE); masm.bind(FALSE_LABEL); masm.xorl(resultReg, resultReg); // return false // That's it - masm.bind(DONE_LABEL); + masm.bind(DONE); %} enc_class enc_rethrow() @@ -4196,33 +4445,6 @@ encode %{ // done: %} - enc_class enc_membar_acquire - %{ - // [jk] not needed currently, if you enable this and it really - // emits code don't forget to the remove the "size(0)" line in - // membar_acquire() - // MacroAssembler masm(&cbuf); - // masm.membar(Assembler::Membar_mask_bits(Assembler::LoadStore | - // Assembler::LoadLoad)); - %} - - enc_class enc_membar_release - %{ - // [jk] not needed currently, if you enable this and it really - // emits code don't forget to the remove the "size(0)" line in - // membar_release() - // MacroAssembler masm(&cbuf); - // masm.membar(Assembler::Membar_mask_bits(Assembler::LoadStore | - // Assembler::StoreStore)); - %} - - enc_class enc_membar_volatile - %{ - MacroAssembler masm(&cbuf); - masm.membar(Assembler::Membar_mask_bits(Assembler::StoreLoad | - Assembler::StoreStore)); - %} - // Safepoint Poll. This polls the safepoint page, and causes an // exception if it is not readable. Unfortunately, it kills // RFLAGS in the process. @@ -4908,15 +5130,6 @@ operand rRegP() interface(REG_INTER); %} - -operand r12RegL() %{ - constraint(ALLOC_IN_RC(long_r12_reg)); - match(RegL); - - format %{ %} - interface(REG_INTER); -%} - operand rRegN() %{ constraint(ALLOC_IN_RC(int_reg)); match(RegN); @@ -5157,7 +5370,7 @@ operand regF() %} // Double register operands -operand regD() +operand regD() %{ constraint(ALLOC_IN_RC(double_reg)); match(RegD); @@ -5291,21 +5504,6 @@ operand indIndexScaleOffset(any_RegP reg, immL32 off, rRegL lreg, immI2 scale) %} %} -// Indirect Narrow Oop Plus Offset Operand -operand indNarrowOopOffset(rRegN src, immL32 off) %{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeN src) off); - - op_cost(10); - format %{"[R12 + $src << 3 + $off] (compressed oop addressing)" %} - interface(MEMORY_INTER) %{ - base(0xc); // R12 - index($src); - scale(0x3); - disp($off); - %} -%} - // Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand operand indPosIndexScaleOffset(any_RegP reg, immL32 off, rRegI idx, immI2 scale) %{ @@ -5323,6 +5521,158 @@ operand indPosIndexScaleOffset(any_RegP reg, immL32 off, rRegI idx, immI2 scale) %} %} +// Indirect Narrow Oop Plus Offset Operand +// Note: x86 architecture doesn't support "scale * index + offset" without a base +// we can't free r12 even with Universe::narrow_oop_base() == NULL. +operand indCompressedOopOffset(rRegN reg, immL32 off) %{ + predicate(UseCompressedOops && (Universe::narrow_oop_shift() != 0)); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + + op_cost(10); + format %{"[R12 + $reg << 3 + $off] (compressed oop addressing)" %} + interface(MEMORY_INTER) %{ + base(0xc); // R12 + index($reg); + scale(0x3); + disp($off); + %} +%} + +// Indirect Memory Operand +operand indirectNarrow(rRegN reg) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(DecodeN reg); + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp(0x0); + %} +%} + +// Indirect Memory Plus Short Offset Operand +operand indOffset8Narrow(rRegN reg, immL8 off) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + + format %{ "[$reg + $off (8-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Long Offset Operand +operand indOffset32Narrow(rRegN reg, immL32 off) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + + format %{ "[$reg + $off (32-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Index Register Plus Offset Operand +operand indIndexOffsetNarrow(rRegN reg, rRegL lreg, immL32 off) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeN reg) lreg) off); + + op_cost(10); + format %{"[$reg + $off + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Index Register Plus Offset Operand +operand indIndexNarrow(rRegN reg, rRegL lreg) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) lreg); + + op_cost(10); + format %{"[$reg + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp(0x0); + %} +%} + +// Indirect Memory Times Scale Plus Index Register +operand indIndexScaleNarrow(rRegN reg, rRegL lreg, immI2 scale) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) (LShiftL lreg scale)); + + op_cost(10); + format %{"[$reg + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp(0x0); + %} +%} + +// Indirect Memory Times Scale Plus Index Register Plus Offset Operand +operand indIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegL lreg, immI2 scale) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeN reg) (LShiftL lreg scale)) off); + + op_cost(10); + format %{"[$reg + $off + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp($off); + %} +%} + +// Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand +operand indPosIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegI idx, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(Universe::narrow_oop_shift() == 0 && n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP (DecodeN reg) (LShiftL (ConvI2L idx) scale)) off); + + op_cost(10); + format %{"[$reg + $off + $idx << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale($scale); + disp($off); + %} +%} + + //----------Special Memory Operands-------------------------------------------- // Stack Slot Operand - This operand is used for loading and storing temporary // values on the stack where a match requires a value to @@ -5483,14 +5833,17 @@ operand cmpOpUCF2() %{ //----------OPERAND CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used as to simplify -// instruction definitions by not requiring the AD writer to specify seperate +// instruction definitions by not requiring the AD writer to specify separate // instructions for every form of operand when the instruction accepts // multiple operand types with the same basic encoding and format. The classic // case of this is memory operands. opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, indIndexScale, indIndexScaleOffset, indPosIndexScaleOffset, - indNarrowOopOffset); + indCompressedOopOffset, + indirectNarrow, indOffset8Narrow, indOffset32Narrow, + indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, + indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow); //----------PIPELINE----------------------------------------------------------- // Rules which define the behavior of the target architectures pipeline. @@ -6031,70 +6384,88 @@ instruct loadB(rRegI dst, memory mem) ins_cost(125); format %{ "movsbl $dst, $mem\t# byte" %} - opcode(0x0F, 0xBE); - ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem)); + + ins_encode %{ + __ movsbl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); %} -// Load Byte (8 bit signed) into long -// instruct loadB2L(rRegL dst, memory mem) -// %{ -// match(Set dst (ConvI2L (LoadB mem))); - -// ins_cost(125); -// format %{ "movsbq $dst, $mem\t# byte -> long" %} -// opcode(0x0F, 0xBE); -// ins_encode(REX_reg_mem_wide(dst, mem), OpcP, OpcS, reg_mem(dst, mem)); -// ins_pipe(ialu_reg_mem); -// %} - -// Load Byte (8 bit UNsigned) -instruct loadUB(rRegI dst, memory mem, immI_255 bytemask) +// Load Byte (8 bit signed) into Long Register +instruct loadB2L(rRegL dst, memory mem) %{ - match(Set dst (AndI (LoadB mem) bytemask)); + match(Set dst (ConvI2L (LoadB mem))); + + ins_cost(125); + format %{ "movsbq $dst, $mem\t# byte -> long" %} + + ins_encode %{ + __ movsbq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Byte (8 bit UNsigned) +instruct loadUB(rRegI dst, memory mem) +%{ + match(Set dst (LoadUB mem)); ins_cost(125); format %{ "movzbl $dst, $mem\t# ubyte" %} - opcode(0x0F, 0xB6); - ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem)); + + ins_encode %{ + __ movzbl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); %} -// Load Byte (8 bit UNsigned) into long -// instruct loadUB2L(rRegL dst, memory mem, immI_255 bytemask) -// %{ -// match(Set dst (ConvI2L (AndI (LoadB mem) bytemask))); +// Load Unsigned Byte (8 bit UNsigned) into Long Register +instruct loadUB2L(rRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadUB mem))); -// ins_cost(125); -// format %{ "movzbl $dst, $mem\t# ubyte -> long" %} -// opcode(0x0F, 0xB6); -// ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem)); -// ins_pipe(ialu_reg_mem); -// %} + ins_cost(125); + format %{ "movzbq $dst, $mem\t# ubyte -> long" %} + + ins_encode %{ + __ movzbq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} // Load Short (16 bit signed) instruct loadS(rRegI dst, memory mem) %{ match(Set dst (LoadS mem)); - ins_cost(125); // XXX + ins_cost(125); format %{ "movswl $dst, $mem\t# short" %} - opcode(0x0F, 0xBF); - ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem)); + + ins_encode %{ + __ movswl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); %} -// Load Short (16 bit signed) into long -// instruct loadS2L(rRegL dst, memory mem) -// %{ -// match(Set dst (ConvI2L (LoadS mem))); +// Load Short (16 bit signed) into Long Register +instruct loadS2L(rRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadS mem))); -// ins_cost(125); // XXX -// format %{ "movswq $dst, $mem\t# short -> long" %} -// opcode(0x0F, 0xBF); -// ins_encode(REX_reg_mem_wide(dst, mem), OpcP, OpcS, reg_mem(dst, mem)); -// ins_pipe(ialu_reg_mem); -// %} + ins_cost(125); + format %{ "movswq $dst, $mem\t# short -> long" %} + + ins_encode %{ + __ movswq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} // Load Unsigned Short/Char (16 bit UNsigned) instruct loadUS(rRegI dst, memory mem) @@ -6103,32 +6474,71 @@ instruct loadUS(rRegI dst, memory mem) ins_cost(125); format %{ "movzwl $dst, $mem\t# ushort/char" %} - opcode(0x0F, 0xB7); - ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem)); + + ins_encode %{ + __ movzwl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); %} -// Load Unsigned Short/Char (16 bit UNsigned) into long -// instruct loadUS2L(rRegL dst, memory mem) -// %{ -// match(Set dst (ConvI2L (LoadUS mem))); +// Load Unsigned Short/Char (16 bit UNsigned) into Long Register +instruct loadUS2L(rRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadUS mem))); -// ins_cost(125); -// format %{ "movzwl $dst, $mem\t# ushort/char -> long" %} -// opcode(0x0F, 0xB7); -// ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem)); -// ins_pipe(ialu_reg_mem); -// %} + ins_cost(125); + format %{ "movzwq $dst, $mem\t# ushort/char -> long" %} + + ins_encode %{ + __ movzwq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} // Load Integer instruct loadI(rRegI dst, memory mem) %{ match(Set dst (LoadI mem)); - ins_cost(125); // XXX + ins_cost(125); format %{ "movl $dst, $mem\t# int" %} - opcode(0x8B); - ins_encode(REX_reg_mem(dst, mem), OpcP, reg_mem(dst, mem)); + + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Integer into Long Register +instruct loadI2L(rRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadI mem))); + + ins_cost(125); + format %{ "movslq $dst, $mem\t# int -> long" %} + + ins_encode %{ + __ movslq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Integer into Long Register +instruct loadUI2L(rRegL dst, memory mem) +%{ + match(Set dst (LoadUI2L mem)); + + ins_cost(125); + format %{ "movl $dst, $mem\t# uint -> long" %} + + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); %} @@ -6137,10 +6547,13 @@ instruct loadL(rRegL dst, memory mem) %{ match(Set dst (LoadL mem)); - ins_cost(125); // XXX + ins_cost(125); format %{ "movq $dst, $mem\t# long" %} - opcode(0x8B); - ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + + ins_encode %{ + __ movq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); // XXX %} @@ -6176,9 +6589,7 @@ instruct loadN(rRegN dst, memory mem) ins_cost(125); // XXX format %{ "movl $dst, $mem\t# compressed ptr" %} ins_encode %{ - Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - Register dst = as_Register($dst$$reg); - __ movl(dst, addr); + __ movl($dst$$Register, $mem$$Address); %} ins_pipe(ialu_reg_mem); // XXX %} @@ -6204,9 +6615,7 @@ instruct loadNKlass(rRegN dst, memory mem) ins_cost(125); // XXX format %{ "movl $dst, $mem\t# compressed klass ptr" %} ins_encode %{ - Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - Register dst = as_Register($dst$$reg); - __ movl(dst, addr); + __ movl($dst$$Register, $mem$$Address); %} ins_pipe(ialu_reg_mem); // XXX %} @@ -6360,6 +6769,102 @@ instruct leaPIdxScaleOff(rRegP dst, indIndexScaleOffset mem) ins_pipe(ialu_reg_reg_fat); %} +instruct leaPPosIdxScaleOff(rRegP dst, indPosIndexScaleOffset mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxscaleoff" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +// Load Effective Address which uses Narrow (32-bits) oop +instruct leaPCompressedOopOffset(rRegP dst, indCompressedOopOffset mem) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_shift() != 0)); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr compressedoopoff32" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaP8Narrow(rRegP dst, indOffset8Narrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); // XXX + format %{ "leaq $dst, $mem\t# ptr off8narrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaP32Narrow(rRegP dst, indOffset32Narrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr off32narrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxOffNarrow(rRegP dst, indIndexOffsetNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxoffnarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxScaleNarrow(rRegP dst, indIndexScaleNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscalenarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxScaleOffNarrow(rRegP dst, indIndexScaleOffsetNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscaleoffnarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPPosIdxScaleOffNarrow(rRegP dst, indPosIndexScaleOffsetNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxscaleoffnarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + instruct loadConI(rRegI dst, immI src) %{ match(Set dst src); @@ -6470,8 +6975,7 @@ instruct loadConN0(rRegN dst, immN0 src, rFlagsReg cr) %{ effect(KILL cr); format %{ "xorq $dst, $src\t# compressed NULL ptr" %} ins_encode %{ - Register dst = $dst$$Register; - __ xorq(dst, dst); + __ xorq($dst$$Register, $dst$$Register); %} ins_pipe(ialu_reg); %} @@ -6483,11 +6987,10 @@ instruct loadConN(rRegN dst, immN src) %{ format %{ "movl $dst, $src\t# compressed ptr" %} ins_encode %{ address con = (address)$src$$constant; - Register dst = $dst$$Register; if (con == NULL) { ShouldNotReachHere(); } else { - __ set_narrow_oop(dst, (jobject)$src$$constant); + __ set_narrow_oop($dst$$Register, (jobject)$src$$constant); } %} ins_pipe(ialu_reg_fat); // XXX @@ -6736,12 +7239,25 @@ instruct storeP(memory mem, any_RegP src) ins_pipe(ialu_mem_reg); %} +instruct storeImmP0(memory mem, immP0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreP mem zero)); + + ins_cost(125); // XXX + format %{ "movq $mem, R12\t# ptr (R12_heapbase==0)" %} + ins_encode %{ + __ movq($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + // Store NULL Pointer, mark word, or other simple pointer constant. instruct storeImmP(memory mem, immP31 src) %{ match(Set mem (StoreP mem src)); - ins_cost(125); // XXX + ins_cost(150); // XXX format %{ "movq $mem, $src\t# ptr" %} opcode(0xC7); /* C7 /0 */ ins_encode(REX_mem_wide(mem), OpcP, RM_opc_mem(0x00, mem), Con32(src)); @@ -6756,14 +7272,55 @@ instruct storeN(memory mem, rRegN src) ins_cost(125); // XXX format %{ "movl $mem, $src\t# compressed ptr" %} ins_encode %{ - Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - Register src = as_Register($src$$reg); - __ movl(addr, src); + __ movl($mem$$Address, $src$$Register); %} ins_pipe(ialu_mem_reg); %} +instruct storeImmN0(memory mem, immN0 zero) +%{ + predicate(Universe::narrow_oop_base() == NULL); + match(Set mem (StoreN mem zero)); + + ins_cost(125); // XXX + format %{ "movl $mem, R12\t# compressed ptr (R12_heapbase==0)" %} + ins_encode %{ + __ movl($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeImmN(memory mem, immN src) +%{ + match(Set mem (StoreN mem src)); + + ins_cost(150); // XXX + format %{ "movl $mem, $src\t# compressed ptr" %} + ins_encode %{ + address con = (address)$src$$constant; + if (con == NULL) { + __ movl($mem$$Address, (int32_t)0); + } else { + __ set_narrow_oop($mem$$Address, (jobject)$src$$constant); + } + %} + ins_pipe(ialu_mem_imm); +%} + // Store Integer Immediate +instruct storeImmI0(memory mem, immI0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreI mem zero)); + + ins_cost(125); // XXX + format %{ "movl $mem, R12\t# int (R12_heapbase==0)" %} + ins_encode %{ + __ movl($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmI(memory mem, immI src) %{ match(Set mem (StoreI mem src)); @@ -6776,6 +7333,19 @@ instruct storeImmI(memory mem, immI src) %} // Store Long Immediate +instruct storeImmL0(memory mem, immL0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreL mem zero)); + + ins_cost(125); // XXX + format %{ "movq $mem, R12\t# long (R12_heapbase==0)" %} + ins_encode %{ + __ movq($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmL(memory mem, immL32 src) %{ match(Set mem (StoreL mem src)); @@ -6788,6 +7358,19 @@ instruct storeImmL(memory mem, immL32 src) %} // Store Short/Char Immediate +instruct storeImmC0(memory mem, immI0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreC mem zero)); + + ins_cost(125); // XXX + format %{ "movw $mem, R12\t# short/char (R12_heapbase==0)" %} + ins_encode %{ + __ movw($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmI16(memory mem, immI16 src) %{ predicate(UseStoreImmI16); @@ -6801,6 +7384,19 @@ instruct storeImmI16(memory mem, immI16 src) %} // Store Byte Immediate +instruct storeImmB0(memory mem, immI0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreB mem zero)); + + ins_cost(125); // XXX + format %{ "movb $mem, R12\t# short/char (R12_heapbase==0)" %} + ins_encode %{ + __ movb($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmB(memory mem, immI8 src) %{ match(Set mem (StoreB mem src)); @@ -6840,6 +7436,19 @@ instruct storeA2I(memory mem, regD src) %{ %} // Store CMS card-mark Immediate +instruct storeImmCM0_reg(memory mem, immI0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreCM mem zero)); + + ins_cost(125); // XXX + format %{ "movb $mem, R12\t# CMS card-mark byte 0 (R12_heapbase==0)" %} + ins_encode %{ + __ movb($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmCM0(memory mem, immI0 src) %{ match(Set mem (StoreCM mem src)); @@ -6873,6 +7482,19 @@ instruct storeF(memory mem, regF src) %} // Store immediate Float value (it is faster than store from XMM register) +instruct storeF0(memory mem, immF0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreF mem zero)); + + ins_cost(25); // XXX + format %{ "movl $mem, R12\t# float 0. (R12_heapbase==0)" %} + ins_encode %{ + __ movl($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeF_imm(memory mem, immF src) %{ match(Set mem (StoreF mem src)); @@ -6899,6 +7521,7 @@ instruct storeD(memory mem, regD src) // Store immediate double 0.0 (it is faster than store from XMM register) instruct storeD0_imm(memory mem, immD0 src) %{ + predicate(!UseCompressedOops || (Universe::narrow_oop_base() != NULL)); match(Set mem (StoreD mem src)); ins_cost(50); @@ -6908,6 +7531,19 @@ instruct storeD0_imm(memory mem, immD0 src) ins_pipe(ialu_mem_imm); %} +instruct storeD0(memory mem, immD0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreD mem zero)); + + ins_cost(25); // XXX + format %{ "movq $mem, R12\t# double 0. (R12_heapbase==0)" %} + ins_encode %{ + __ movq($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeSSI(stackSlotI dst, rRegI src) %{ match(Set dst src); @@ -7019,6 +7655,56 @@ instruct storeL_reversed(memory dst, rRegL src) %{ ins_pipe( ialu_mem_reg ); %} + +//---------- Population Count Instructions ------------------------------------- + +instruct popCountI(rRegI dst, rRegI src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI src)); + + format %{ "popcnt $dst, $src" %} + ins_encode %{ + __ popcntl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct popCountI_mem(rRegI dst, memory mem) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI (LoadI mem))); + + format %{ "popcnt $dst, $mem" %} + ins_encode %{ + __ popcntl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL(rRegI dst, rRegL src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL src)); + + format %{ "popcnt $dst, $src" %} + ins_encode %{ + __ popcntq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL_mem(rRegI dst, memory mem) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL (LoadL mem))); + + format %{ "popcnt $dst, $mem" %} + ins_encode %{ + __ popcntq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg); +%} + + //----------MemBar Instructions----------------------------------------------- // Memory barrier flavors @@ -7028,7 +7714,7 @@ instruct membar_acquire() ins_cost(0); size(0); - format %{ "MEMBAR-acquire" %} + format %{ "MEMBAR-acquire ! (empty encoding)" %} ins_encode(); ins_pipe(empty); %} @@ -7051,7 +7737,7 @@ instruct membar_release() ins_cost(0); size(0); - format %{ "MEMBAR-release" %} + format %{ "MEMBAR-release ! (empty encoding)" %} ins_encode(); ins_pipe(empty); %} @@ -7068,13 +7754,22 @@ instruct membar_release_lock() ins_pipe(empty); %} -instruct membar_volatile() -%{ +instruct membar_volatile(rFlagsReg cr) %{ match(MemBarVolatile); + effect(KILL cr); ins_cost(400); - format %{ "MEMBAR-volatile" %} - ins_encode(enc_membar_volatile); + format %{ + $$template + if (os::is_MP()) { + $$emit$$"lock addl [rsp + #0], 0\t! membar_volatile" + } else { + $$emit$$"MEMBAR-volatile ! (empty encoding)" + } + %} + ins_encode %{ + __ membar(Assembler::StoreLoad); + %} ins_pipe(pipe_slow); %} @@ -7134,9 +7829,7 @@ instruct encodeHeapOop_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{ effect(KILL cr); format %{ "encode_heap_oop_not_null $dst,$src" %} ins_encode %{ - Register s = $src$$Register; - Register d = $dst$$Register; - __ encode_heap_oop_not_null(d, s); + __ encode_heap_oop_not_null($dst$$Register, $src$$Register); %} ins_pipe(ialu_reg_long); %} @@ -7166,7 +7859,11 @@ instruct decodeHeapOop_not_null(rRegP dst, rRegN src) %{ ins_encode %{ Register s = $src$$Register; Register d = $dst$$Register; - __ decode_heap_oop_not_null(d, s); + if (s != d) { + __ decode_heap_oop_not_null(d, s); + } else { + __ decode_heap_oop_not_null(d); + } %} ins_pipe(ialu_reg_long); %} @@ -8363,7 +9060,7 @@ instruct divModL_rReg_divmod(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div, //----------- DivL-By-Constant-Expansions-------------------------------------- // DivI cases are handled by the compiler -// Magic constant, reciprical of 10 +// Magic constant, reciprocal of 10 instruct loadConL_0x6666666666666667(rRegL dst) %{ effect(DEF dst); @@ -10804,16 +11501,6 @@ instruct convI2L_reg_reg(rRegL dst, rRegI src) // ins_pipe(ialu_reg_reg); // %} -instruct convI2L_reg_mem(rRegL dst, memory src) -%{ - match(Set dst (ConvI2L (LoadI src))); - - format %{ "movslq $dst, $src\t# i2l" %} - opcode(0x63); // needs REX.W - ins_encode(REX_reg_mem_wide(dst, src), OpcP, reg_mem(dst,src)); - ins_pipe(ialu_reg_mem); -%} - // Zero-extend convert int to long instruct convI2L_reg_reg_zex(rRegL dst, rRegI src, immL_32bits mask) %{ @@ -11136,27 +11823,52 @@ instruct rep_stos(rcx_RegL cnt, rdi_RegP base, rax_RegI zero, Universe dummy, ins_pipe(pipe_slow); %} -instruct string_compare(rdi_RegP str1, rsi_RegP str2, rax_RegI tmp1, - rbx_RegI tmp2, rcx_RegI result, rFlagsReg cr) +instruct string_compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, + rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr) %{ match(Set result (StrComp str1 str2)); - effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL cr); + effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr); //ins_cost(300); format %{ "String Compare $str1, $str2 -> $result // XXX KILL RAX, RBX" %} - ins_encode( enc_String_Compare() ); + ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); + ins_pipe( pipe_slow ); +%} + +instruct string_indexof(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2, + rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result, rFlagsReg cr) +%{ + predicate(UseSSE42Intrinsics); + match(Set result (StrIndexOf str1 str2)); + effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr); + + format %{ "String IndexOf $str1,$str2 -> $result // KILL RAX, RCX, RDX" %} + ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); + ins_pipe( pipe_slow ); +%} + +// fast string equals +instruct string_equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, rbx_RegI tmp3, + rcx_RegI tmp4, rax_RegI result, rFlagsReg cr) +%{ + match(Set result (StrEquals str1 str2)); + effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr); + + format %{ "String Equals $str1,$str2 -> $result // KILL RBX, RCX" %} + ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); ins_pipe( pipe_slow ); %} // fast array equals -instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI tmp1, - rbx_RegI tmp2, rcx_RegI result, rFlagsReg cr) %{ +instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2, rax_RegI tmp3, + rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr) +%{ match(Set result (AryEq ary1 ary2)); - effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL cr); + effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); //ins_cost(300); - format %{ "Array Equals $ary1,$ary2 -> $result // KILL RAX, RBX" %} - ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result) ); + format %{ "Array Equals $ary1,$ary2 -> $result // KILL RAX, RBX" %} + ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) ); ins_pipe( pipe_slow ); %} @@ -11341,8 +12053,9 @@ instruct testP_reg(rFlagsReg cr, rRegP src, immP0 zero) // This will generate a signed flags result. This should be OK since // any compare to a zero should be eq/neq. -instruct testP_reg_mem(rFlagsReg cr, memory op, immP0 zero) +instruct testP_mem(rFlagsReg cr, memory op, immP0 zero) %{ + predicate(!UseCompressedOops || (Universe::narrow_oop_base() != NULL)); match(Set cr (CmpP (LoadP op) zero)); ins_cost(500); // XXX @@ -11353,13 +12066,24 @@ instruct testP_reg_mem(rFlagsReg cr, memory op, immP0 zero) ins_pipe(ialu_cr_reg_imm); %} +instruct testP_mem_reg0(rFlagsReg cr, memory mem, immP0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set cr (CmpP (LoadP mem) zero)); + + format %{ "cmpq R12, $mem\t# ptr (R12_heapbase==0)" %} + ins_encode %{ + __ cmpq(r12, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2) %{ match(Set cr (CmpN op1 op2)); format %{ "cmpl $op1, $op2\t# compressed ptr" %} - ins_encode %{ __ cmpl(as_Register($op1$$reg), as_Register($op2$$reg)); %} + ins_encode %{ __ cmpl($op1$$Register, $op2$$Register); %} ins_pipe(ialu_cr_reg_reg); %} @@ -11367,11 +12091,30 @@ instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem) %{ match(Set cr (CmpN src (LoadN mem))); - ins_cost(500); // XXX - format %{ "cmpl $src, mem\t# compressed ptr" %} + format %{ "cmpl $src, $mem\t# compressed ptr" %} ins_encode %{ - Address adr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - __ cmpl(as_Register($src$$reg), adr); + __ cmpl($src$$Register, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct compN_rReg_imm(rFlagsRegU cr, rRegN op1, immN op2) %{ + match(Set cr (CmpN op1 op2)); + + format %{ "cmpl $op1, $op2\t# compressed ptr" %} + ins_encode %{ + __ cmp_narrow_oop($op1$$Register, (jobject)$op2$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compN_mem_imm(rFlagsRegU cr, memory mem, immN src) +%{ + match(Set cr (CmpN src (LoadN mem))); + + format %{ "cmpl $mem, $src\t# compressed ptr" %} + ins_encode %{ + __ cmp_narrow_oop($mem$$Address, (jobject)$src$$constant); %} ins_pipe(ialu_cr_reg_mem); %} @@ -11384,15 +12127,27 @@ instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ ins_pipe(ialu_cr_reg_imm); %} -instruct testN_reg_mem(rFlagsReg cr, memory mem, immN0 zero) +instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) %{ + predicate(Universe::narrow_oop_base() != NULL); match(Set cr (CmpN (LoadN mem) zero)); ins_cost(500); // XXX format %{ "testl $mem, 0xffffffff\t# compressed ptr" %} ins_encode %{ - Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - __ cmpl(addr, (int)0xFFFFFFFF); + __ cmpl($mem$$Address, (int)0xFFFFFFFF); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero) +%{ + predicate(Universe::narrow_oop_base() == NULL); + match(Set cr (CmpN (LoadN mem) zero)); + + format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)" %} + ins_encode %{ + __ cmpl(r12, $mem$$Address); %} ins_pipe(ialu_cr_reg_mem); %} @@ -11424,7 +12179,6 @@ instruct compL_rReg_mem(rFlagsReg cr, rRegL op1, memory op2) %{ match(Set cr (CmpL op1 (LoadL op2))); - ins_cost(500); // XXX format %{ "cmpq $op1, $op2" %} opcode(0x3B); /* Opcode 3B /r */ ins_encode(REX_reg_mem_wide(op1, op2), OpcP, reg_mem(op1, op2)); @@ -11685,15 +12439,12 @@ instruct partialSubtypeCheck(rdi_RegP result, effect(KILL rcx, KILL cr); ins_cost(1100); // slightly larger than the next version - format %{ "cmpq rax, rsi\n\t" - "jeq,s hit\n\t" - "movq rdi, [$sub + (sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())]\n\t" + format %{ "movq rdi, [$sub + (sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())]\n\t" "movl rcx, [rdi + arrayOopDesc::length_offset_in_bytes()]\t# length to scan\n\t" "addq rdi, arrayOopDex::base_offset_in_bytes(T_OBJECT)\t# Skip to start of data; set NZ in case count is zero\n\t" "repne scasq\t# Scan *rdi++ for a match with rax while rcx--\n\t" "jne,s miss\t\t# Missed: rdi not-zero\n\t" "movq [$sub + (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes())], $super\t# Hit: update cache\n\t" - "hit:\n\t" "xorq $result, $result\t\t Hit: rdi zero\n\t" "miss:\t" %} @@ -11708,13 +12459,10 @@ instruct partialSubtypeCheck_vs_Zero(rFlagsReg cr, rdi_RegP result) %{ match(Set cr (CmpP (PartialSubtypeCheck sub super) zero)); - predicate(!UseCompressedOops); // decoding oop kills condition codes effect(KILL rcx, KILL result); ins_cost(1000); - format %{ "cmpq rax, rsi\n\t" - "jeq,s miss\t# Actually a hit; we are done.\n\t" - "movq rdi, [$sub + (sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())]\n\t" + format %{ "movq rdi, [$sub + (sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())]\n\t" "movl rcx, [rdi + arrayOopDesc::length_offset_in_bytes()]\t# length to scan\n\t" "addq rdi, arrayOopDex::base_offset_in_bytes(T_OBJECT)\t# Skip to start of data; set NZ in case count is zero\n\t" "repne scasq\t# Scan *rdi++ for a match with rax while cx-- != 0\n\t" @@ -12082,7 +12830,7 @@ instruct RethrowException() // These must follow all instruction definitions as they use the names // defined in the instructions definitions. // -// peepmatch ( root_instr_name [precerding_instruction]* ); +// peepmatch ( root_instr_name [preceding_instruction]* ); // // peepconstraint %{ // (instruction_number.operand_name relational_op instruction_number.operand_name diff --git a/hotspot/src/os/linux/launcher/java.c b/hotspot/src/os/linux/launcher/java.c index a13782ec437..e335776325d 100644 --- a/hotspot/src/os/linux/launcher/java.c +++ b/hotspot/src/os/linux/launcher/java.c @@ -419,7 +419,7 @@ main(int argc, char ** argv) goto leave; } mainClass = LoadClass(env, classname); - if(mainClass == NULL) { /* exception occured */ + if(mainClass == NULL) { /* exception occurred */ ReportExceptionDescription(env); message = "Could not find the main class. Program will exit."; goto leave; @@ -441,7 +441,7 @@ main(int argc, char ** argv) goto leave; } mainClass = LoadClass(env, classname); - if(mainClass == NULL) { /* exception occured */ + if(mainClass == NULL) { /* exception occurred */ ReportExceptionDescription(env); message = "Could not find the main class. Program will exit."; goto leave; diff --git a/hotspot/src/os/linux/launcher/java_md.h b/hotspot/src/os/linux/launcher/java_md.h index 89e4d0b7ac8..6016621754a 100644 --- a/hotspot/src/os/linux/launcher/java_md.h +++ b/hotspot/src/os/linux/launcher/java_md.h @@ -47,7 +47,7 @@ #ifdef JAVA_ARGS /* * ApplicationHome is prepended to each of these entries; the resulting - * strings are concatenated (seperated by PATH_SEPARATOR) and used as the + * strings are concatenated (separated by PATH_SEPARATOR) and used as the * value of -cp option to the launcher. */ #ifndef APP_CLASSPATH diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 846906951d4..b4705e4a7f2 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1518,21 +1518,51 @@ const char* os::dll_file_extension() { return ".so"; } const char* os::get_temp_directory() { return "/tmp/"; } -void os::dll_build_name( - char* buffer, size_t buflen, const char* pname, const char* fname) { - // copied from libhpi +static bool file_exists(const char* filename) { + struct stat statbuf; + if (filename == NULL || strlen(filename) == 0) { + return false; + } + return os::stat(filename, &statbuf) == 0; +} + +void os::dll_build_name(char* buffer, size_t buflen, + const char* pname, const char* fname) { + // Copied from libhpi const size_t pnamelen = pname ? strlen(pname) : 0; - /* Quietly truncate on buffer overflow. Should be an error. */ + // Quietly truncate on buffer overflow. Should be an error. if (pnamelen + strlen(fname) + 10 > (size_t) buflen) { *buffer = '\0'; return; } if (pnamelen == 0) { - sprintf(buffer, "lib%s.so", fname); + snprintf(buffer, buflen, "lib%s.so", fname); + } else if (strchr(pname, *os::path_separator()) != NULL) { + int n; + char** pelements = split_path(pname, &n); + for (int i = 0 ; i < n ; i++) { + // Really shouldn't be NULL, but check can't hurt + if (pelements[i] == NULL || strlen(pelements[i]) == 0) { + continue; // skip the empty path values + } + snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname); + if (file_exists(buffer)) { + break; + } + } + // release the storage + for (int i = 0 ; i < n ; i++) { + if (pelements[i] != NULL) { + FREE_C_HEAP_ARRAY(char, pelements[i]); + } + } + if (pelements != NULL) { + FREE_C_HEAP_ARRAY(char*, pelements); + } } else { - sprintf(buffer, "%s/lib%s.so", pname, fname); + snprintf(buffer, buflen, "%s/lib%s.so", pname, fname); } } @@ -2269,15 +2299,16 @@ void linux_wrap_code(char* base, size_t size) { // All it does is to check if there are enough free pages // left at the time of mmap(). This could be a potential // problem. -bool os::commit_memory(char* addr, size_t size) { - uintptr_t res = (uintptr_t) ::mmap(addr, size, - PROT_READ|PROT_WRITE|PROT_EXEC, +bool os::commit_memory(char* addr, size_t size, bool exec) { + int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; + uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); return res != (uintptr_t) MAP_FAILED; } -bool os::commit_memory(char* addr, size_t size, size_t alignment_hint) { - return commit_memory(addr, size); +bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, + bool exec) { + return commit_memory(addr, size, exec); } void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } @@ -2417,8 +2448,7 @@ os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory; unsigned long* os::Linux::_numa_all_nodes; bool os::uncommit_memory(char* addr, size_t size) { - return ::mmap(addr, size, - PROT_READ|PROT_WRITE|PROT_EXEC, + return ::mmap(addr, size, PROT_NONE, MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0) != MAP_FAILED; } @@ -2441,7 +2471,9 @@ static char* anon_mmap(char* requested_addr, size_t bytes, bool fixed) { flags |= MAP_FIXED; } - addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE|PROT_EXEC, + // Map uncommitted pages PROT_READ and PROT_WRITE, change access + // to PROT_EXEC if executable when we commit the page. + addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE, flags, -1, 0); if (addr != MAP_FAILED) { @@ -2582,7 +2614,9 @@ bool os::large_page_init() { #define SHM_HUGETLB 04000 #endif -char* os::reserve_memory_special(size_t bytes) { +char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { + // "exec" is passed in but not used. Creating the shared image for + // the code cache doesn't have an SHM_X executable permission to check. assert(UseLargePages, "only for large pages"); key_t key = IPC_PRIVATE; diff --git a/hotspot/src/os/linux/vm/perfMemory_linux.cpp b/hotspot/src/os/linux/vm/perfMemory_linux.cpp index c56798c0187..38165056267 100644 --- a/hotspot/src/os/linux/vm/perfMemory_linux.cpp +++ b/hotspot/src/os/linux/vm/perfMemory_linux.cpp @@ -192,7 +192,7 @@ static pid_t filename_to_pid(const char* filename) { // check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path -// is a symbolic link or if an error occured. +// is a symbolic link or if an error occurred. // static bool is_directory_secure(const char* path) { struct stat statbuf; diff --git a/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp b/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp index feedb287ada..5ad280c3b7b 100644 --- a/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp +++ b/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp @@ -249,6 +249,10 @@ int generateJvmOffsets(GEN_variant gen_variant) { printf("\n"); + GEN_OFFS(NarrowOopStruct, _base); + GEN_OFFS(NarrowOopStruct, _shift); + printf("\n"); + GEN_VALUE(SIZE_HeapBlockHeader, sizeof(HeapBlock::Header)); GEN_SIZE(oopDesc); GEN_SIZE(constantPoolOopDesc); diff --git a/hotspot/src/os/solaris/dtrace/jhelper.d b/hotspot/src/os/solaris/dtrace/jhelper.d index 6f2f6165c35..da5837238c8 100644 --- a/hotspot/src/os/solaris/dtrace/jhelper.d +++ b/hotspot/src/os/solaris/dtrace/jhelper.d @@ -46,7 +46,10 @@ extern pointer __JvmOffsets; extern pointer __1cJCodeCacheF_heap_; extern pointer __1cIUniverseP_methodKlassObj_; extern pointer __1cIUniverseO_collectedHeap_; -extern pointer __1cIUniverseK_heap_base_; +extern pointer __1cIUniverseL_narrow_oop_; +#ifdef _LP64 +extern pointer UseCompressedOops; +#endif extern pointer __1cHnmethodG__vtbl_; extern pointer __1cKBufferBlobG__vtbl_; @@ -56,6 +59,7 @@ extern pointer __1cKBufferBlobG__vtbl_; #define copyin_uint16(ADDR) *(uint16_t*) copyin((pointer) (ADDR), sizeof(uint16_t)) #define copyin_uint32(ADDR) *(uint32_t*) copyin((pointer) (ADDR), sizeof(uint32_t)) #define copyin_int32(ADDR) *(int32_t*) copyin((pointer) (ADDR), sizeof(int32_t)) +#define copyin_uint8(ADDR) *(uint8_t*) copyin((pointer) (ADDR), sizeof(uint8_t)) #define SAME(x) x #define copyin_offset(JVM_CONST) JVM_CONST = \ @@ -132,6 +136,9 @@ dtrace:helper:ustack: copyin_offset(SIZE_oopDesc); copyin_offset(SIZE_constantPoolOopDesc); + copyin_offset(OFFSET_NarrowOopStruct_base); + copyin_offset(OFFSET_NarrowOopStruct_shift); + /* * The PC to translate is in arg0. */ @@ -151,9 +158,19 @@ dtrace:helper:ustack: this->Universe_methodKlassOop = copyin_ptr(&``__1cIUniverseP_methodKlassObj_); this->CodeCache_heap_address = copyin_ptr(&``__1cJCodeCacheF_heap_); - this->Universe_heap_base = copyin_ptr(&``__1cIUniverseK_heap_base_); /* Reading volatile values */ +#ifdef _LP64 + this->Use_Compressed_Oops = copyin_uint8(&``UseCompressedOops); +#else + this->Use_Compressed_Oops = 0; +#endif + + this->Universe_narrow_oop_base = copyin_ptr(&``__1cIUniverseL_narrow_oop_ + + OFFSET_NarrowOopStruct_base); + this->Universe_narrow_oop_shift = copyin_int32(&``__1cIUniverseL_narrow_oop_ + + OFFSET_NarrowOopStruct_shift); + this->CodeCache_low = copyin_ptr(this->CodeCache_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); @@ -295,7 +312,7 @@ dtrace:helper:ustack: dtrace:helper:ustack: /!this->done && this->vtbl == this->BufferBlob_vtbl && -this->Universe_heap_base == NULL && +this->Use_Compressed_Oops == 0 && this->methodOopPtr > this->heap_start && this->methodOopPtr < this->heap_end/ { MARK_LINE; @@ -306,7 +323,7 @@ this->methodOopPtr > this->heap_start && this->methodOopPtr < this->heap_end/ dtrace:helper:ustack: /!this->done && this->vtbl == this->BufferBlob_vtbl && -this->Universe_heap_base != NULL && +this->Use_Compressed_Oops != 0 && this->methodOopPtr > this->heap_start && this->methodOopPtr < this->heap_end/ { MARK_LINE; @@ -314,8 +331,8 @@ this->methodOopPtr > this->heap_start && this->methodOopPtr < this->heap_end/ * Read compressed pointer and decode heap oop, same as oop.inline.hpp */ this->cklass = copyin_uint32(this->methodOopPtr + OFFSET_oopDesc_metadata); - this->klass = (uint64_t)((uintptr_t)this->Universe_heap_base + - ((uintptr_t)this->cklass << 3)); + this->klass = (uint64_t)((uintptr_t)this->Universe_narrow_oop_base + + ((uintptr_t)this->cklass << this->Universe_narrow_oop_shift)); this->methodOop = this->klass == this->Universe_methodKlassOop; this->done = !this->methodOop; } diff --git a/hotspot/src/os/solaris/dtrace/libjvm_db.c b/hotspot/src/os/solaris/dtrace/libjvm_db.c index ad0031e4b92..afa443092b4 100644 --- a/hotspot/src/os/solaris/dtrace/libjvm_db.c +++ b/hotspot/src/os/solaris/dtrace/libjvm_db.c @@ -146,13 +146,17 @@ struct jvm_agent { uint64_t BufferBlob_vtbl; uint64_t RuntimeStub_vtbl; + uint64_t Use_Compressed_Oops_address; uint64_t Universe_methodKlassObj_address; + uint64_t Universe_narrow_oop_base_address; + uint64_t Universe_narrow_oop_shift_address; uint64_t CodeCache_heap_address; - uint64_t Universe_heap_base_address; /* Volatiles */ + uint8_t Use_Compressed_Oops; uint64_t Universe_methodKlassObj; - uint64_t Universe_heap_base; + uint64_t Universe_narrow_oop_base; + uint32_t Universe_narrow_oop_shift; uint64_t CodeCache_low; uint64_t CodeCache_high; uint64_t CodeCache_segmap_low; @@ -279,8 +283,11 @@ static int parse_vmstructs(jvm_agent_t* J) { if (strcmp("_methodKlassObj", vmp->fieldName) == 0) { J->Universe_methodKlassObj_address = vmp->address; } - if (strcmp("_heap_base", vmp->fieldName) == 0) { - J->Universe_heap_base_address = vmp->address; + if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) { + J->Universe_narrow_oop_base_address = vmp->address; + } + if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) { + J->Universe_narrow_oop_shift_address = vmp->address; } } CHECK_FAIL(err); @@ -298,14 +305,39 @@ static int parse_vmstructs(jvm_agent_t* J) { return -1; } +static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) { + psaddr_t sym_addr; + int err; + + err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); + if (err != PS_OK) goto fail; + *valuep = sym_addr; + return PS_OK; + + fail: + return err; +} + static int read_volatiles(jvm_agent_t* J) { uint64_t ptr; int err; + err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address); + if (err == PS_OK) { + err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t)); + CHECK_FAIL(err); + } else { + J->Use_Compressed_Oops = 0; + } + err = read_pointer(J, J->Universe_methodKlassObj_address, &J->Universe_methodKlassObj); CHECK_FAIL(err); - err = read_pointer(J, J->Universe_heap_base_address, &J->Universe_heap_base); + + err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base); CHECK_FAIL(err); + err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t)); + CHECK_FAIL(err); + err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low, &J->CodeCache_low); CHECK_FAIL(err); @@ -374,19 +406,6 @@ static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { return -1; } -static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) { - psaddr_t sym_addr; - int err; - - err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); - if (err != PS_OK) goto fail; - *valuep = sym_addr; - return PS_OK; - - fail: - return err; -} - static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) { psaddr_t sym_addr; int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); @@ -458,14 +477,14 @@ void Jagent_destroy(jvm_agent_t *J) { static int is_methodOop(jvm_agent_t* J, uint64_t methodOopPtr) { uint64_t klass; int err; - // If heap_base is nonnull, this was a compressed oop. - if (J->Universe_heap_base != NULL) { + // If UseCompressedOops, this was a compressed oop. + if (J->Use_Compressed_Oops != 0) { uint32_t cklass; err = read_compressed_pointer(J, methodOopPtr + OFFSET_oopDesc_metadata, &cklass); // decode heap oop, same as oop.inline.hpp - klass = (uint64_t)((uintptr_t)J->Universe_heap_base + - ((uintptr_t)cklass << 3)); + klass = (uint64_t)((uintptr_t)J->Universe_narrow_oop_base + + ((uintptr_t)cklass << J->Universe_narrow_oop_shift)); } else { err = read_pointer(J, methodOopPtr + OFFSET_oopDesc_metadata, &klass); } diff --git a/hotspot/src/os/solaris/launcher/java.c b/hotspot/src/os/solaris/launcher/java.c index e4fc014de6d..866be7c65b7 100644 --- a/hotspot/src/os/solaris/launcher/java.c +++ b/hotspot/src/os/solaris/launcher/java.c @@ -419,7 +419,7 @@ main(int argc, char ** argv) goto leave; } mainClass = LoadClass(env, classname); - if(mainClass == NULL) { /* exception occured */ + if(mainClass == NULL) { /* exception occurred */ ReportExceptionDescription(env); message = "Could not find the main class. Program will exit."; goto leave; @@ -441,7 +441,7 @@ main(int argc, char ** argv) goto leave; } mainClass = LoadClass(env, classname); - if(mainClass == NULL) { /* exception occured */ + if(mainClass == NULL) { /* exception occurred */ ReportExceptionDescription(env); message = "Could not find the main class. Program will exit."; goto leave; diff --git a/hotspot/src/os/solaris/launcher/java_md.h b/hotspot/src/os/solaris/launcher/java_md.h index c65b42e2a3f..5122de9fc25 100644 --- a/hotspot/src/os/solaris/launcher/java_md.h +++ b/hotspot/src/os/solaris/launcher/java_md.h @@ -47,7 +47,7 @@ #ifdef JAVA_ARGS /* * ApplicationHome is prepended to each of these entries; the resulting - * strings are concatenated (seperated by PATH_SEPARATOR) and used as the + * strings are concatenated (separated by PATH_SEPARATOR) and used as the * value of -cp option to the launcher. */ #ifndef APP_CLASSPATH diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index c5c83883f48..ce201c3faca 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1827,21 +1827,51 @@ const char* os::dll_file_extension() { return ".so"; } const char* os::get_temp_directory() { return "/tmp/"; } -void os::dll_build_name( - char* buffer, size_t buflen, const char* pname, const char* fname) { - // copied from libhpi +static bool file_exists(const char* filename) { + struct stat statbuf; + if (filename == NULL || strlen(filename) == 0) { + return false; + } + return os::stat(filename, &statbuf) == 0; +} + +void os::dll_build_name(char* buffer, size_t buflen, + const char* pname, const char* fname) { + // Copied from libhpi const size_t pnamelen = pname ? strlen(pname) : 0; - /* Quietly truncate on buffer overflow. Should be an error. */ + // Quietly truncate on buffer overflow. Should be an error. if (pnamelen + strlen(fname) + 10 > (size_t) buflen) { *buffer = '\0'; return; } if (pnamelen == 0) { - sprintf(buffer, "lib%s.so", fname); + snprintf(buffer, buflen, "lib%s.so", fname); + } else if (strchr(pname, *os::path_separator()) != NULL) { + int n; + char** pelements = split_path(pname, &n); + for (int i = 0 ; i < n ; i++) { + // really shouldn't be NULL but what the heck, check can't hurt + if (pelements[i] == NULL || strlen(pelements[i]) == 0) { + continue; // skip the empty path values + } + snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname); + if (file_exists(buffer)) { + break; + } + } + // release the storage + for (int i = 0 ; i < n ; i++) { + if (pelements[i] != NULL) { + FREE_C_HEAP_ARRAY(char, pelements[i]); + } + } + if (pelements != NULL) { + FREE_C_HEAP_ARRAY(char*, pelements); + } } else { - sprintf(buffer, "%s/lib%s.so", pname, fname); + snprintf(buffer, buflen, "%s/lib%s.so", pname, fname); } } @@ -2623,15 +2653,16 @@ int os::vm_allocation_granularity() { return page_size; } -bool os::commit_memory(char* addr, size_t bytes) { +bool os::commit_memory(char* addr, size_t bytes, bool exec) { + int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; size_t size = bytes; return - NULL != Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, - PROT_READ | PROT_WRITE | PROT_EXEC); + NULL != Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot); } -bool os::commit_memory(char* addr, size_t bytes, size_t alignment_hint) { - if (commit_memory(addr, bytes)) { +bool os::commit_memory(char* addr, size_t bytes, size_t alignment_hint, + bool exec) { + if (commit_memory(addr, bytes, exec)) { if (UseMPSS && alignment_hint > (size_t)vm_page_size()) { // If the large page size has been set and the VM // is using large pages, use the large page size @@ -3220,7 +3251,9 @@ bool os::Solaris::set_mpss_range(caddr_t start, size_t bytes, size_t align) { return true; } -char* os::reserve_memory_special(size_t bytes) { +char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { + // "exec" is passed in but not used. Creating the shared image for + // the code cache doesn't have an SHM_X executable permission to check. assert(UseLargePages && UseISM, "only for ISM large pages"); size_t size = bytes; @@ -4451,6 +4484,9 @@ int_fnP_thread_t_i os::Solaris::_thr_setmutator; int_fnP_thread_t os::Solaris::_thr_suspend_mutator; int_fnP_thread_t os::Solaris::_thr_continue_mutator; +// (Static) wrapper for getisax(2) call. +os::Solaris::getisax_func_t os::Solaris::_getisax = 0; + // (Static) wrappers for the liblgrp API os::Solaris::lgrp_home_func_t os::Solaris::_lgrp_home; os::Solaris::lgrp_init_func_t os::Solaris::_lgrp_init; @@ -4465,16 +4501,19 @@ os::Solaris::lgrp_cookie_t os::Solaris::_lgrp_cookie = 0; // (Static) wrapper for meminfo() call. os::Solaris::meminfo_func_t os::Solaris::_meminfo = 0; -static address resolve_symbol(const char *name) { - address addr; - - addr = (address) dlsym(RTLD_DEFAULT, name); +static address resolve_symbol_lazy(const char* name) { + address addr = (address) dlsym(RTLD_DEFAULT, name); if(addr == NULL) { // RTLD_DEFAULT was not defined on some early versions of 2.5.1 addr = (address) dlsym(RTLD_NEXT, name); - if(addr == NULL) { - fatal(dlerror()); - } + } + return addr; +} + +static address resolve_symbol(const char* name) { + address addr = resolve_symbol_lazy(name); + if(addr == NULL) { + fatal(dlerror()); } return addr; } @@ -4673,15 +4712,26 @@ bool os::Solaris::liblgrp_init() { } void os::Solaris::misc_sym_init() { - address func = (address)dlsym(RTLD_DEFAULT, "meminfo"); - if(func == NULL) { - func = (address) dlsym(RTLD_NEXT, "meminfo"); + address func; + + // getisax + func = resolve_symbol_lazy("getisax"); + if (func != NULL) { + os::Solaris::_getisax = CAST_TO_FN_PTR(getisax_func_t, func); } + + // meminfo + func = resolve_symbol_lazy("meminfo"); if (func != NULL) { os::Solaris::set_meminfo(CAST_TO_FN_PTR(meminfo_func_t, func)); } } +uint_t os::Solaris::getisax(uint32_t* array, uint_t n) { + assert(_getisax != NULL, "_getisax not set"); + return _getisax(array, n); +} + // Symbol doesn't exist in Solaris 8 pset.h #ifndef PS_MYID #define PS_MYID -3 @@ -4716,6 +4766,10 @@ void os::init(void) { Solaris::initialize_system_info(); + // Initialize misc. symbols as soon as possible, so we can use them + // if we need them. + Solaris::misc_sym_init(); + int fd = open("/dev/zero", O_RDWR); if (fd < 0) { fatal1("os::init: cannot open /dev/zero (%s)", strerror(errno)); @@ -4857,7 +4911,6 @@ jint os::init_2(void) { } } - Solaris::misc_sym_init(); Solaris::signal_sets_init(); Solaris::init_signal_mem(); Solaris::install_signal_handlers(); diff --git a/hotspot/src/os/solaris/vm/os_solaris.hpp b/hotspot/src/os/solaris/vm/os_solaris.hpp index 8e322456d89..e4cbdbb5cd6 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,6 +72,8 @@ class Solaris { LGRP_VIEW_OS /* what's available to operating system */ } lgrp_view_t; + typedef uint_t (*getisax_func_t)(uint32_t* array, uint_t n); + typedef lgrp_id_t (*lgrp_home_func_t)(idtype_t idtype, id_t id); typedef lgrp_cookie_t (*lgrp_init_func_t)(lgrp_view_t view); typedef int (*lgrp_fini_func_t)(lgrp_cookie_t cookie); @@ -87,6 +89,8 @@ class Solaris { const uint_t info_req[], int info_count, uint64_t outdata[], uint_t validity[]); + static getisax_func_t _getisax; + static lgrp_home_func_t _lgrp_home; static lgrp_init_func_t _lgrp_init; static lgrp_fini_func_t _lgrp_fini; @@ -283,6 +287,9 @@ class Solaris { } static lgrp_cookie_t lgrp_cookie() { return _lgrp_cookie; } + static bool supports_getisax() { return _getisax != NULL; } + static uint_t getisax(uint32_t* array, uint_t n); + static void set_meminfo(meminfo_func_t func) { _meminfo = func; } static int meminfo (const uint64_t inaddr[], int addr_count, const uint_t info_req[], int info_count, diff --git a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp index 4626d7299b4..459ef573a90 100644 --- a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp +++ b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp @@ -194,7 +194,7 @@ static pid_t filename_to_pid(const char* filename) { // check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path -// is a symbolic link or if an error occured. +// is a symbolic link or if an error occurred. // static bool is_directory_secure(const char* path) { struct stat statbuf; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index dce602e8ecb..0ae4c3e8131 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1004,26 +1004,61 @@ const char * os::get_temp_directory() } } -void os::dll_build_name(char *holder, size_t holderlen, - const char* pname, const char* fname) -{ - // copied from libhpi - const size_t pnamelen = pname ? strlen(pname) : 0; - const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0; +static bool file_exists(const char* filename) { + if (filename == NULL || strlen(filename) == 0) { + return false; + } + return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES; +} - /* Quietly truncates on buffer overflow. Should be an error. */ - if (pnamelen + strlen(fname) + 10 > holderlen) { - *holder = '\0'; - return; - } +void os::dll_build_name(char *buffer, size_t buflen, + const char* pname, const char* fname) { + // Copied from libhpi + const size_t pnamelen = pname ? strlen(pname) : 0; + const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0; - if (pnamelen == 0) { - sprintf(holder, "%s.dll", fname); - } else if (c == ':' || c == '\\') { - sprintf(holder, "%s%s.dll", pname, fname); - } else { - sprintf(holder, "%s\\%s.dll", pname, fname); + // Quietly truncates on buffer overflow. Should be an error. + if (pnamelen + strlen(fname) + 10 > buflen) { + *buffer = '\0'; + return; + } + + if (pnamelen == 0) { + jio_snprintf(buffer, buflen, "%s.dll", fname); + } else if (c == ':' || c == '\\') { + jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname); + } else if (strchr(pname, *os::path_separator()) != NULL) { + int n; + char** pelements = split_path(pname, &n); + for (int i = 0 ; i < n ; i++) { + char* path = pelements[i]; + // Really shouldn't be NULL, but check can't hurt + size_t plen = (path == NULL) ? 0 : strlen(path); + if (plen == 0) { + continue; // skip the empty path values + } + const char lastchar = path[plen - 1]; + if (lastchar == ':' || lastchar == '\\') { + jio_snprintf(buffer, buflen, "%s%s.dll", path, fname); + } else { + jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname); + } + if (file_exists(buffer)) { + break; + } } + // release the storage + for (int i = 0 ; i < n ; i++) { + if (pelements[i] != NULL) { + FREE_C_HEAP_ARRAY(char, pelements[i]); + } + } + if (pelements != NULL) { + FREE_C_HEAP_ARRAY(char*, pelements); + } + } else { + jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname); + } } // Needs to be in os specific directory because windows requires another @@ -2189,7 +2224,8 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (addr > thread->stack_yellow_zone_base() && addr < thread->stack_base() ) { addr = (address)((uintptr_t)addr & (~((uintptr_t)os::vm_page_size() - (uintptr_t)1))); - os::commit_memory( (char *)addr, thread->stack_base() - addr ); + os::commit_memory((char *)addr, thread->stack_base() - addr, + false ); return EXCEPTION_CONTINUE_EXECUTION; } else @@ -2565,8 +2601,7 @@ char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { assert((size_t)addr % os::vm_allocation_granularity() == 0, "reserve alignment"); assert(bytes % os::vm_allocation_granularity() == 0, "reserve block size"); - char* res = (char*)VirtualAlloc(addr, bytes, MEM_RESERVE, - PAGE_EXECUTE_READWRITE); + char* res = (char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE); assert(res == NULL || addr == NULL || addr == res, "Unexpected address from reserve."); return res; @@ -2595,7 +2630,7 @@ bool os::can_execute_large_page_memory() { return true; } -char* os::reserve_memory_special(size_t bytes) { +char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { if (UseLargePagesIndividualAllocation) { if (TracePageSizes && Verbose) { @@ -2615,10 +2650,10 @@ char* os::reserve_memory_special(size_t bytes) { "use -XX:-UseLargePagesIndividualAllocation to turn off"); return NULL; } - p_buf = (char *) VirtualAlloc(NULL, + p_buf = (char *) VirtualAlloc(addr, size_of_reserve, // size of Reserve MEM_RESERVE, - PAGE_EXECUTE_READWRITE); + PAGE_READWRITE); // If reservation failed, return NULL if (p_buf == NULL) return NULL; @@ -2659,7 +2694,13 @@ char* os::reserve_memory_special(size_t bytes) { p_new = (char *) VirtualAlloc(next_alloc_addr, bytes_to_rq, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, - PAGE_EXECUTE_READWRITE); + PAGE_READWRITE); + if (p_new != NULL && exec) { + DWORD oldprot; + // Windows doc says to use VirtualProtect to get execute permissions + VirtualProtect(next_alloc_addr, bytes_to_rq, + PAGE_EXECUTE_READWRITE, &oldprot); + } } if (p_new == NULL) { @@ -2688,10 +2729,12 @@ char* os::reserve_memory_special(size_t bytes) { } else { // normal policy just allocate it all at once DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; - char * res = (char *)VirtualAlloc(NULL, - bytes, - flag, - PAGE_EXECUTE_READWRITE); + char * res = (char *)VirtualAlloc(NULL, bytes, flag, PAGE_READWRITE); + if (res != NULL && exec) { + DWORD oldprot; + // Windows doc says to use VirtualProtect to get execute permissions + VirtualProtect(res, bytes, PAGE_EXECUTE_READWRITE, &oldprot); + } return res; } } @@ -2703,7 +2746,7 @@ bool os::release_memory_special(char* base, size_t bytes) { void os::print_statistics() { } -bool os::commit_memory(char* addr, size_t bytes) { +bool os::commit_memory(char* addr, size_t bytes, bool exec) { if (bytes == 0) { // Don't bother the OS with noops. return true; @@ -2712,11 +2755,19 @@ bool os::commit_memory(char* addr, size_t bytes) { assert(bytes % os::vm_page_size() == 0, "commit in page-sized chunks"); // Don't attempt to print anything if the OS call fails. We're // probably low on resources, so the print itself may cause crashes. - return VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE) != NULL; + bool result = VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) != 0; + if (result != NULL && exec) { + DWORD oldprot; + // Windows doc says to use VirtualProtect to get execute permissions + return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot) != 0; + } else { + return result; + } } -bool os::commit_memory(char* addr, size_t size, size_t alignment_hint) { - return commit_memory(addr, size); +bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, + bool exec) { + return commit_memory(addr, size, exec); } bool os::uncommit_memory(char* addr, size_t bytes) { @@ -2750,7 +2801,7 @@ bool os::protect_memory(char* addr, size_t bytes, ProtType prot, // Strange enough, but on Win32 one can change protection only for committed // memory, not a big deal anyway, as bytes less or equal than 64K - if (!is_committed && !commit_memory(addr, bytes)) { + if (!is_committed && !commit_memory(addr, bytes, prot == MEM_PROT_RWX)) { fatal("cannot commit protection page"); } // One cannot use os::guard_memory() here, as on Win32 guard page @@ -3248,10 +3299,10 @@ jint os::init_2(void) { #endif if (!UseMembar) { - address mem_serialize_page = (address)VirtualAlloc(NULL, os::vm_page_size(), MEM_RESERVE, PAGE_EXECUTE_READWRITE); + address mem_serialize_page = (address)VirtualAlloc(NULL, os::vm_page_size(), MEM_RESERVE, PAGE_READWRITE); guarantee( mem_serialize_page != NULL, "Reserve Failed for memory serialize page"); - return_page = (address)VirtualAlloc(mem_serialize_page, os::vm_page_size(), MEM_COMMIT, PAGE_EXECUTE_READWRITE); + return_page = (address)VirtualAlloc(mem_serialize_page, os::vm_page_size(), MEM_COMMIT, PAGE_READWRITE); guarantee( return_page != NULL, "Commit Failed for memory serialize page"); os::set_memory_serialize_page( mem_serialize_page ); diff --git a/hotspot/src/os/windows/vm/perfMemory_windows.cpp b/hotspot/src/os/windows/vm/perfMemory_windows.cpp index 42a45ee6527..95063df2eb0 100644 --- a/hotspot/src/os/windows/vm/perfMemory_windows.cpp +++ b/hotspot/src/os/windows/vm/perfMemory_windows.cpp @@ -195,7 +195,7 @@ static int filename_to_pid(const char* filename) { // check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path -// is a symbolic link or if an error occured. +// is a symbolic link or if an error occurred. // static bool is_directory_secure(const char* path) { @@ -994,7 +994,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, return false; } - // if running on windows 2000 or later, set the automatic inheritence + // if running on windows 2000 or later, set the automatic inheritance // control flags. SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl; _SetSecurityDescriptorControl = (SetSecurityDescriptorControlFnPtr) @@ -1002,7 +1002,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, "SetSecurityDescriptorControl"); if (_SetSecurityDescriptorControl != NULL) { - // We do not want to further propogate inherited DACLs, so making them + // We do not want to further propagate inherited DACLs, so making them // protected prevents that. if (!_SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { diff --git a/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp b/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp index ccc884e8329..68be1d43523 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp @@ -30,5 +30,7 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 12288); define_pd_global(intx, CompilerThreadStackSize, 0); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 4*G); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff --git a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.hpp b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.hpp index 4c74a6af6ab..865cd1ce0f1 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.hpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.hpp @@ -29,13 +29,11 @@ static jint (*atomic_cmpxchg_func) (jint, volatile jint*, jint); static jlong (*atomic_cmpxchg_long_func)(jlong, volatile jlong*, jlong); static jint (*atomic_add_func) (jint, volatile jint*); - static void (*fence_func) (); static jint atomic_xchg_bootstrap (jint, volatile jint*); static jint atomic_cmpxchg_bootstrap (jint, volatile jint*, jint); static jlong atomic_cmpxchg_long_bootstrap(jlong, volatile jlong*, jlong); static jint atomic_add_bootstrap (jint, volatile jint*); - static void fence_bootstrap (); static void setup_fpu() {} diff --git a/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp b/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp index 317993ce58f..24d2bab7c19 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp +++ b/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp @@ -43,5 +43,7 @@ define_pd_global(intx, SurvivorRatio, 8); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 2*G); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff --git a/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp b/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp index 2b5f3ec0ac5..9777b0a131d 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp +++ b/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp @@ -44,11 +44,12 @@ inline void OrderAccess::release() { inline void OrderAccess::fence() { if (os::is_MP()) { + // always use locked addl since mfence is sometimes expensive #ifdef AMD64 - __asm__ __volatile__ ("mfence":::"memory"); + __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory"); #else __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory"); -#endif // AMD64 +#endif } } diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index 90e1921f8a0..df685ff5148 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp index c0bf513235e..71f16d94158 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp @@ -30,5 +30,9 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 12288); define_pd_global(intx, CompilerThreadStackSize, 0); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 4*G); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); + + diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp index c80d89157e4..5e27aefb977 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp @@ -60,22 +60,10 @@ inline void OrderAccess::release() { dummy = 0; } -#if defined(COMPILER2) || defined(_LP64) - inline void OrderAccess::fence() { _OrderAccess_fence(); } -#else // defined(COMPILER2) || defined(_LP64) - -inline void OrderAccess::fence() { - if (os::is_MP()) { - (*os::fence_func)(); - } -} - -#endif // defined(COMPILER2) || defined(_LP64) - #endif // _GNU_SOURCE inline jbyte OrderAccess::load_acquire(volatile jbyte* p) { return *p; } diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp index 012c170a980..44b67e9d035 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp @@ -532,7 +532,7 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_ if (oldAct.sa_sigaction != signalHandler) { void* sighand = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction) : CAST_FROM_FN_PTR(void*, oldAct.sa_handler); - warning("Unexpected Signal %d occured under user-defined signal handler " INTPTR_FORMAT, sig, (intptr_t)sighand); + warning("Unexpected Signal %d occurred under user-defined signal handler " INTPTR_FORMAT, sig, (intptr_t)sighand); } } @@ -619,7 +619,6 @@ typedef jint xchg_func_t (jint, volatile jint*); typedef jint cmpxchg_func_t (jint, volatile jint*, jint); typedef jlong cmpxchg_long_func_t(jlong, volatile jlong*, jlong); typedef jint add_func_t (jint, volatile jint*); -typedef void fence_func_t (); jint os::atomic_xchg_bootstrap(jint exchange_value, volatile jint* dest) { // try to use the stub: @@ -681,25 +680,10 @@ jint os::atomic_add_bootstrap(jint add_value, volatile jint* dest) { return (*dest) += add_value; } -void os::fence_bootstrap() { - // try to use the stub: - fence_func_t* func = CAST_TO_FN_PTR(fence_func_t*, StubRoutines::fence_entry()); - - if (func != NULL) { - os::fence_func = func; - (*func)(); - return; - } - assert(Threads::number_of_threads() == 0, "for bootstrap only"); - - // don't have to do anything for a single thread -} - xchg_func_t* os::atomic_xchg_func = os::atomic_xchg_bootstrap; cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap; cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_bootstrap; add_func_t* os::atomic_add_func = os::atomic_add_bootstrap; -fence_func_t* os::fence_func = os::fence_bootstrap; #endif // !_LP64 && !COMPILER2 diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.hpp index f522b038507..62fee83dd25 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.hpp @@ -29,13 +29,11 @@ static jint (*atomic_cmpxchg_func) (jint, volatile jint*, jint); static jlong (*atomic_cmpxchg_long_func)(jlong, volatile jlong*, jlong); static jint (*atomic_add_func) (jint, volatile jint*); - static void (*fence_func) (); static jint atomic_xchg_bootstrap (jint, volatile jint*); static jint atomic_cmpxchg_bootstrap (jint, volatile jint*, jint); static jlong atomic_cmpxchg_long_bootstrap(jlong, volatile jlong*, jlong); static jint atomic_add_bootstrap (jint, volatile jint*); - static void fence_bootstrap (); static void setup_fpu() {} diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp index 5f2ec21027e..ec537c7fe54 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,58 +25,107 @@ # include "incls/_precompiled.incl" # include "incls/_vm_version_solaris_sparc.cpp.incl" +# include +# include # include -int VM_Version::platform_features(int features) { - // We determine what sort of hardware we have via sysinfo(SI_ISALIST, ...). - // This isn't the best of all possible ways because there's not enough - // detail in the isa list it returns, but it's a bit less arcane than - // generating assembly code and an illegal instruction handler. We used - // to generate a getpsr trap, but that's even more arcane. - // - // Another possibility would be to use sysinfo(SI_PLATFORM, ...), but - // that would require more knowledge here than is wise. +// We need to keep these here as long as we have to build on Solaris +// versions before 10. +#ifndef SI_ARCHITECTURE_32 +#define SI_ARCHITECTURE_32 516 /* basic 32-bit SI_ARCHITECTURE */ +#endif - // isalist spec via 'man isalist' as of 01-Aug-2001 +#ifndef SI_ARCHITECTURE_64 +#define SI_ARCHITECTURE_64 517 /* basic 64-bit SI_ARCHITECTURE */ +#endif +static void do_sysinfo(int si, const char* string, int* features, int mask) { char tmp; - size_t bufsize = sysinfo(SI_ISALIST, &tmp, 1); - char* buf = (char*)malloc(bufsize); + size_t bufsize = sysinfo(si, &tmp, 1); - if (buf != NULL) { - if (sysinfo(SI_ISALIST, buf, bufsize) == bufsize) { - // Figure out what kind of sparc we have - char *sparc_string = strstr(buf, "sparc"); - if (sparc_string != NULL) { features |= v8_instructions_m; - if (sparc_string[5] == 'v') { - if (sparc_string[6] == '8') { - if (sparc_string[7] == '-') features |= hardware_int_muldiv_m; - else if (sparc_string[7] == 'p') features |= generic_v9_m; - else features |= generic_v8_m; - } else if (sparc_string[6] == '9') features |= generic_v9_m; + // All SI defines used below must be supported. + guarantee(bufsize != -1, "must be supported"); + + char* buf = (char*) malloc(bufsize); + + if (buf == NULL) + return; + + if (sysinfo(si, buf, bufsize) == bufsize) { + // Compare the string. + if (strcmp(buf, string) == 0) { + *features |= mask; + } + } + + free(buf); +} + +int VM_Version::platform_features(int features) { + // getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are + // supported on Solaris 10 and later. + if (os::Solaris::supports_getisax()) { +#ifndef PRODUCT + if (PrintMiscellaneous && Verbose) + tty->print_cr("getisax(2) supported."); +#endif + + // Check 32-bit architecture. + do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); + + // Check 64-bit architecture. + do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m); + + // Extract valid instruction set extensions. + uint_t av; + uint_t avn = os::Solaris::getisax(&av, 1); + assert(avn == 1, "should only return one av"); + + if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; + if (av & AV_SPARC_DIV32) features |= hardware_div32_m; + if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; + if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m; + if (av & AV_SPARC_POPC) features |= hardware_popc_m; + if (av & AV_SPARC_VIS) features |= vis1_instructions_m; + if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; + } else { + // getisax(2) failed, use the old legacy code. +#ifndef PRODUCT + if (PrintMiscellaneous && Verbose) + tty->print_cr("getisax(2) not supported."); +#endif + + char tmp; + size_t bufsize = sysinfo(SI_ISALIST, &tmp, 1); + char* buf = (char*) malloc(bufsize); + + if (buf != NULL) { + if (sysinfo(SI_ISALIST, buf, bufsize) == bufsize) { + // Figure out what kind of sparc we have + char *sparc_string = strstr(buf, "sparc"); + if (sparc_string != NULL) { features |= v8_instructions_m; + if (sparc_string[5] == 'v') { + if (sparc_string[6] == '8') { + if (sparc_string[7] == '-') { features |= hardware_mul32_m; + features |= hardware_div32_m; + } else if (sparc_string[7] == 'p') features |= generic_v9_m; + else features |= generic_v8_m; + } else if (sparc_string[6] == '9') features |= generic_v9_m; + } + } + + // Check for visualization instructions + char *vis = strstr(buf, "vis"); + if (vis != NULL) { features |= vis1_instructions_m; + if (vis[3] == '2') features |= vis2_instructions_m; } } - - // Check for visualization instructions - char *vis = strstr(buf, "vis"); - if (vis != NULL) { features |= vis1_instructions_m; - if (vis[3] == '2') features |= vis2_instructions_m; - } + free(buf); } - free(buf); } - bufsize = sysinfo(SI_MACHINE, &tmp, 1); - buf = (char*)malloc(bufsize); - - if (buf != NULL) { - if (sysinfo(SI_MACHINE, buf, bufsize) == bufsize) { - if (strstr(buf, "sun4v") != NULL) { - features |= sun4v_m; - } - } - free(buf); - } + // Determine the machine type. + do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m); return features; } diff --git a/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp b/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp index aef1d7314d3..754195f10ff 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp @@ -46,5 +46,7 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 10*K); define_pd_global(intx, CompilerThreadStackSize, 0); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 256*M); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff --git a/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp b/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp index ed8486f746f..bf4d97d21b4 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp @@ -61,11 +61,8 @@ extern "C" { #endif // AMD64 } inline void _OrderAccess_fence() { -#ifdef AMD64 - __asm__ __volatile__ ("mfence":::"memory"); -#else + // Always use locked addl since mfence is sometimes expensive __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory"); -#endif // AMD64 } } diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index c37370b572b..59ed458b23f 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -299,13 +299,17 @@ static void check_for_sse_support() { } +#endif // AMD64 + bool os::supports_sse() { +#ifdef AMD64 + return true; +#else if (sse_status == SSE_UNKNOWN) check_for_sse_support(); return sse_status == SSE_SUPPORTED; -} - #endif // AMD64 +} bool os::is_allocatable(size_t bytes) { #ifdef AMD64 @@ -690,7 +694,7 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_ if (oldAct.sa_sigaction != signalHandler) { void* sighand = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction) : CAST_FROM_FN_PTR(void*, oldAct.sa_handler); - warning("Unexpected Signal %d occured under user-defined signal handler %#lx", sig, (long)sighand); + warning("Unexpected Signal %d occurred under user-defined signal handler %#lx", sig, (long)sighand); } } @@ -790,7 +794,6 @@ typedef jint xchg_func_t (jint, volatile jint*); typedef jint cmpxchg_func_t (jint, volatile jint*, jint); typedef jlong cmpxchg_long_func_t(jlong, volatile jlong*, jlong); typedef jint add_func_t (jint, volatile jint*); -typedef void fence_func_t (); jint os::atomic_xchg_bootstrap(jint exchange_value, volatile jint* dest) { // try to use the stub: @@ -852,25 +855,10 @@ jint os::atomic_add_bootstrap(jint add_value, volatile jint* dest) { return (*dest) += add_value; } -void os::fence_bootstrap() { - // try to use the stub: - fence_func_t* func = CAST_TO_FN_PTR(fence_func_t*, StubRoutines::fence_entry()); - - if (func != NULL) { - os::fence_func = func; - (*func)(); - return; - } - assert(Threads::number_of_threads() == 0, "for bootstrap only"); - - // don't have to do anything for a single thread -} - xchg_func_t* os::atomic_xchg_func = os::atomic_xchg_bootstrap; cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap; cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_bootstrap; add_func_t* os::atomic_add_func = os::atomic_add_bootstrap; -fence_func_t* os::fence_func = os::fence_bootstrap; extern "C" _solaris_raw_setup_fpu(address ptr); void os::setup_fpu() { diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.hpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.hpp index c7f1de37c6b..3a02d11965d 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,18 +32,17 @@ static jint (*atomic_cmpxchg_func) (jint, volatile jint*, jint); static jlong (*atomic_cmpxchg_long_func)(jlong, volatile jlong*, jlong); static jint (*atomic_add_func) (jint, volatile jint*); - static void (*fence_func) (); static jint atomic_xchg_bootstrap (jint, volatile jint*); static jint atomic_cmpxchg_bootstrap (jint, volatile jint*, jint); static jlong atomic_cmpxchg_long_bootstrap(jlong, volatile jlong*, jlong); static jint atomic_add_bootstrap (jint, volatile jint*); - static void fence_bootstrap (); static void setup_fpu(); - static bool supports_sse(); #endif // AMD64 + static bool supports_sse(); + static bool is_allocatable(size_t bytes); // Used to register dynamic code cache area with the OS diff --git a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il index 9e1d6ce8ed3..5ac1d25a766 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il +++ b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il @@ -1,5 +1,5 @@ // -// Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_64.il b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_64.il index 169bebc9984..6b4c23a342f 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_64.il +++ b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_64.il @@ -1,5 +1,5 @@ // -// Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp b/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp index 7c578df700c..97226fa37dd 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp @@ -45,5 +45,7 @@ define_pd_global(intx, CompilerThreadStackSize, 0); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 2*G); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff --git a/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp b/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp index b0a98bb0bab..1e53ed1aaa1 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp @@ -46,7 +46,7 @@ inline void OrderAccess::release() { inline void OrderAccess::fence() { #ifdef AMD64 - (*os::fence_func)(); + StubRoutines_fence(); #else if (os::is_MP()) { __asm { diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp index 27b6af946d6..e322f5fd1e8 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp @@ -196,7 +196,6 @@ typedef jint cmpxchg_func_t (jint, volatile jint*, jint); typedef jlong cmpxchg_long_func_t (jlong, volatile jlong*, jlong); typedef jint add_func_t (jint, volatile jint*); typedef intptr_t add_ptr_func_t (intptr_t, volatile intptr_t*); -typedef void fence_func_t (); #ifdef AMD64 @@ -292,27 +291,11 @@ intptr_t os::atomic_add_ptr_bootstrap(intptr_t add_value, volatile intptr_t* des return (*dest) += add_value; } -void os::fence_bootstrap() { - // try to use the stub: - fence_func_t* func = CAST_TO_FN_PTR(fence_func_t*, StubRoutines::fence_entry()); - - if (func != NULL) { - os::fence_func = func; - (*func)(); - return; - } - assert(Threads::number_of_threads() == 0, "for bootstrap only"); - - // don't have to do anything for a single thread -} - - xchg_func_t* os::atomic_xchg_func = os::atomic_xchg_bootstrap; xchg_ptr_func_t* os::atomic_xchg_ptr_func = os::atomic_xchg_ptr_bootstrap; cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap; add_func_t* os::atomic_add_func = os::atomic_add_bootstrap; add_ptr_func_t* os::atomic_add_ptr_func = os::atomic_add_ptr_bootstrap; -fence_func_t* os::fence_func = os::fence_bootstrap; #endif // AMD64 diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp index d7578101677..1e0c6b334b5 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp @@ -35,9 +35,6 @@ static jint (*atomic_add_func) (jint, volatile jint*); static intptr_t (*atomic_add_ptr_func) (intptr_t, volatile intptr_t*); - static void (*fence_func) (); - - static jint atomic_xchg_bootstrap (jint, volatile jint*); static intptr_t atomic_xchg_ptr_bootstrap (intptr_t, volatile intptr_t*); @@ -53,8 +50,6 @@ #ifdef AMD64 static jint atomic_add_bootstrap (jint, volatile jint*); static intptr_t atomic_add_ptr_bootstrap (intptr_t, volatile intptr_t*); - - static void fence_bootstrap (); #endif // AMD64 static void setup_fpu(); diff --git a/hotspot/src/os_cpu/windows_x86/vm/unwind_windows_x86.hpp b/hotspot/src/os_cpu/windows_x86/vm/unwind_windows_x86.hpp index 1e8ed078d54..5f8958567e0 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/unwind_windows_x86.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/unwind_windows_x86.hpp @@ -68,6 +68,9 @@ typedef struct _DISPATCHER_CONTEXT { PVOID HandlerData; } DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT; +#if MSC_VER < 1500 + +/* Not needed for VS2008 compiler, comes from winnt.h. */ typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE) ( IN PEXCEPTION_RECORD ExceptionRecord, IN ULONG64 EstablisherFrame, @@ -75,4 +78,6 @@ typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE) ( IN OUT PDISPATCHER_CONTEXT DispatcherContext ); +#endif + #endif // AMD64 diff --git a/hotspot/src/share/tools/LogCompilation/Makefile b/hotspot/src/share/tools/LogCompilation/Makefile new file mode 100644 index 00000000000..2a2e2a5d71a --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/Makefile @@ -0,0 +1,75 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# +# +PKGLIST = \ +com.sun.hotspot.tools.compiler +#END PKGLIST + +FILELIST = com/sun/hotspot/tools/compiler/*.java + +ifneq "x$(ALT_BOOTDIR)" "x" + BOOTDIR := $(ALT_BOOTDIR) +endif + +ifeq "x$(BOOTDIR)" "x" + JDK_HOME := $(shell dirname $(shell which java))/.. +else + JDK_HOME := $(BOOTDIR) +endif + +isUnix := $(shell test -r c:/; echo $$?) + +ifeq "$(isUnix)" "1" + CPS := : +else + CPS := ";" +endif + +SRC_DIR = src +BUILD_DIR = build +OUTPUT_DIR = $(BUILD_DIR)/classes + +# gnumake 3.78.1 does not accept the *s, +# so use the shell to expand them +ALLFILES := $(patsubst %,$(SRC_DIR)/%,$(FILELIST)) +ALLFILES := $(shell /bin/ls $(ALLFILES)) + +JAVAC = $(JDK_HOME)/bin/javac +JAR = $(JDK_HOME)/bin/jar + +# Tagging it on because there's no reason not to run it +all: logc.jar + +logc.jar: filelist manifest.mf + @mkdir -p $(OUTPUT_DIR) + $(JAVAC) -source 1.5 -deprecation -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) @filelist + $(JAR) cvfm logc.jar manifest.mf -C $(OUTPUT_DIR) com + +.PHONY: filelist +filelist: $(ALLFILES) + @rm -f $@ + @echo $(ALLFILES) > $@ + +clean:: + rm -rf filelist logc.jar + rm -rf $(BUILD_DIR) diff --git a/hotspot/src/share/tools/LogCompilation/README b/hotspot/src/share/tools/LogCompilation/README new file mode 100644 index 00000000000..ed3cbbc8121 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/README @@ -0,0 +1,18 @@ +This is a very rough tool for parsing -XX:+LogCompilation output. +It's main purpose is to recreate output similar to +-XX:+PrintCompilation -XX:+PrintInlining output from a debug JVM. It +requires a 1.5 JDK to build and simply typing make should build it. + +It produces a jar file, logc.jar, that can be run on the +hotspot.log from LogCompilation output like this: + + java -jar logc.jar hotspot.log + +This will produce something like the normal PrintCompilation output. +Adding the -i option with also report inlining like PrintInlining. + +More information about the LogCompilation output can be found at + +http://wikis.sun.com/display/HotSpotInternals/LogCompilation+overview +http://wikis.sun.com/display/HotSpotInternals/PrintCompilation +http://wikis.sun.com/display/HotSpotInternals/LogCompilation+tool diff --git a/hotspot/src/share/tools/LogCompilation/manifest.mf b/hotspot/src/share/tools/LogCompilation/manifest.mf new file mode 100644 index 00000000000..62a36155dd0 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/manifest.mf @@ -0,0 +1 @@ +Main-Class: com.sun.hotspot.tools.compiler.LogCompilation diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/BasicLogEvent.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/BasicLogEvent.java new file mode 100644 index 00000000000..8d9d630a474 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/BasicLogEvent.java @@ -0,0 +1,75 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.PrintStream; + +/** + * + * @author never + */ +public abstract class BasicLogEvent implements LogEvent { + + protected final String id; + protected final double start; + protected double end; + protected Compilation compilation; + + BasicLogEvent(double start, String id) { + this.start = start; + this.end = start; + this.id = id; + } + + public double getStart() { + return start; + } + + public double getEnd() { + return end; + } + + public void setEnd(double end) { + this.end = end; + } + + public double getElapsedTime() { + return ((int) ((getEnd() - getStart()) * 1000)) / 1000.0; + } + + public String getId() { + return id; + } + + public Compilation getCompilation() { + return compilation; + } + + public void setCompilation(Compilation compilation) { + this.compilation = compilation; + } + + abstract public void print(PrintStream stream); +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java new file mode 100644 index 00000000000..bf96b1fbc91 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java @@ -0,0 +1,183 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +public class CallSite { + + private int bci; + private Method method; + private int count; + private String receiver; + private int receiver_count; + private String reason; + private List calls; + + CallSite() { + } + + CallSite(int bci, Method m) { + this.bci = bci; + this.method = m; + } + + void add(CallSite site) { + if (getCalls() == null) { + setCalls(new ArrayList()); + } + getCalls().add(site); + } + + CallSite last() { + return last(-1); + } + + CallSite last(int fromEnd) { + return getCalls().get(getCalls().size() + fromEnd); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + if (getReason() == null) { + sb.append(" @ " + getBci() + " " + getMethod()); + } else { + sb.append("- @ " + getBci() + " " + getMethod() + " " + getReason()); + } + sb.append("\n"); + if (getCalls() != null) { + for (CallSite site : getCalls()) { + sb.append(site); + sb.append("\n"); + } + } + return sb.toString(); + } + + public void print(PrintStream stream) { + print(stream, 0); + } + + void emit(PrintStream stream, int indent) { + for (int i = 0; i < indent; i++) { + stream.print(' '); + } + } + private static boolean compat = true; + + public void print(PrintStream stream, int indent) { + emit(stream, indent); + String m = getMethod().getHolder().replace('/', '.') + "::" + getMethod().getName(); + if (getReason() == null) { + stream.println(" @ " + getBci() + " " + m + " (" + getMethod().getBytes() + " bytes)"); + + } else { + if (isCompat()) { + stream.println(" @ " + getBci() + " " + m + " " + getReason()); + } else { + stream.println("- @ " + getBci() + " " + m + + " (" + getMethod().getBytes() + " bytes) " + getReason()); + } + } + if (getReceiver() != null) { + emit(stream, indent + 3); + // stream.println("type profile " + method.holder + " -> " + receiver + " (" + + // receiver_count + "/" + count + "," + (receiver_count * 100 / count) + "%)"); + stream.println("type profile " + getMethod().getHolder() + " -> " + getReceiver() + " (" + + (getReceiverCount() * 100 / getCount()) + "%)"); + } + if (getCalls() != null) { + for (CallSite site : getCalls()) { + site.print(stream, indent + 2); + } + } + } + + public int getBci() { + return bci; + } + + public void setBci(int bci) { + this.bci = bci; + } + + public Method getMethod() { + return method; + } + + public void setMethod(Method method) { + this.method = method; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public String getReceiver() { + return receiver; + } + + public void setReceiver(String receiver) { + this.receiver = receiver; + } + + public int getReceiverCount() { + return receiver_count; + } + + public void setReceiver_count(int receiver_count) { + this.receiver_count = receiver_count; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public List getCalls() { + return calls; + } + + public void setCalls(List calls) { + this.calls = calls; + } + + public static boolean isCompat() { + return compat; + } + + public static void setCompat(boolean aCompat) { + compat = aCompat; + } +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Compilation.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Compilation.java new file mode 100644 index 00000000000..3695ebd01e0 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Compilation.java @@ -0,0 +1,236 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.PrintStream; +import java.util.ArrayList; + +public class Compilation implements LogEvent { + + private int id; + private boolean osr; + private Method method; + private CallSite call = new CallSite(); + private int osrBci; + private String icount; + private String bcount; + private String special; + private double start; + private double end; + private int attempts; + private NMethod nmethod; + private ArrayList phases = new ArrayList(4); + private String failureReason; + + Compilation(int id) { + this.id = id; + } + + Phase getPhase(String s) { + for (Phase p : getPhases()) { + if (p.getName().equals(s)) { + return p; + } + } + return null; + } + + double getRegallocTime() { + return getPhase("regalloc").getElapsedTime(); + } + + public double getStart() { + return start; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getId()); + sb.append(" "); + sb.append(getMethod()); + sb.append(" "); + sb.append(getIcount()); + sb.append("+"); + sb.append(getBcount()); + sb.append("\n"); + for (CallSite site : getCall().getCalls()) { + sb.append(site); + sb.append("\n"); + } + return sb.toString(); + } + + public void printShort(PrintStream stream) { + if (getMethod() == null) { + stream.println(getSpecial()); + } else { + int bc = isOsr() ? getOsr_bci() : -1; + stream.print(getId() + getMethod().decodeFlags(bc) + getMethod().format(bc)); + } + } + + public void print(PrintStream stream) { + print(stream, 0, false); + } + + public void print(PrintStream stream, boolean printInlining) { + print(stream, 0, printInlining); + } + + public void print(PrintStream stream, int indent, boolean printInlining) { + if (getMethod() == null) { + stream.println(getSpecial()); + } else { + int bc = isOsr() ? getOsr_bci() : -1; + stream.print(getId() + getMethod().decodeFlags(bc) + getMethod().format(bc)); + stream.println(); + if (getFailureReason() != null) { + stream.println("COMPILE FAILED " + getFailureReason()); + } + if (printInlining && call.getCalls() != null) { + for (CallSite site : call.getCalls()) { + site.print(stream, indent + 2); + } + } + } + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public boolean isOsr() { + return osr; + } + + public void setOsr(boolean osr) { + this.osr = osr; + } + + public int getOsr_bci() { + return osrBci; + } + + public void setOsr_bci(int osrBci) { + this.osrBci = osrBci; + } + + public String getIcount() { + return icount; + } + + public void setICount(String icount) { + this.icount = icount; + } + + public String getBcount() { + return bcount; + } + + public void setBCount(String bcount) { + this.bcount = bcount; + } + + public String getSpecial() { + return special; + } + + public void setSpecial(String special) { + this.special = special; + } + + public void setStart(double start) { + this.start = start; + } + + public double getEnd() { + return end; + } + + public void setEnd(double end) { + this.end = end; + } + + public int getAttempts() { + return attempts; + } + + public void setAttempts(int attempts) { + this.attempts = attempts; + } + + public NMethod getNMethod() { + return nmethod; + } + + public void setNMethod(NMethod NMethod) { + this.nmethod = NMethod; + } + + public ArrayList getPhases() { + return phases; + } + + public void setPhases(ArrayList phases) { + this.setPhases(phases); + } + + public String getFailureReason() { + return failureReason; + } + + public void setFailureReason(String failureReason) { + this.failureReason = failureReason; + } + + public Method getMethod() { + return method; + } + + public void setMethod(Method method) { + this.method = method; + } + + public CallSite getCall() { + return call; + } + + public void setCall(CallSite call) { + this.call = call; + } + + public double getElapsedTime() { + return end - start; + } + + public Compilation getCompilation() { + return this; + } +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Constants.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Constants.java new file mode 100644 index 00000000000..e06dd05db54 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Constants.java @@ -0,0 +1,46 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +interface Constants { + static final int JVM_ACC_PUBLIC = 0x0001; /* visible to everyone */ + static final int JVM_ACC_PRIVATE = 0x0002; /* visible only to the defining class */ + static final int JVM_ACC_PROTECTED = 0x0004; /* visible to subclasses */ + static final int JVM_ACC_STATIC = 0x0008; /* instance variable is static */ + static final int JVM_ACC_FINAL = 0x0010; /* no further subclassing, overriding */ + static final int JVM_ACC_SYNCHRONIZED = 0x0020; /* wrap method call in monitor lock */ + static final int JVM_ACC_SUPER = 0x0020; /* funky handling of invokespecial */ + static final int JVM_ACC_VOLATILE = 0x0040; /* can not cache in registers */ + static final int JVM_ACC_BRIDGE = 0x0040; /* bridge method generated by compiler */ + static final int JVM_ACC_TRANSIENT = 0x0080; /* not persistent */ + static final int JVM_ACC_VARARGS = 0x0080; /* method declared with variable number of args */ + static final int JVM_ACC_NATIVE = 0x0100; /* implemented in C */ + static final int JVM_ACC_INTERFACE = 0x0200; /* class is an interface */ + static final int JVM_ACC_ABSTRACT = 0x0400; /* no definition provided */ + static final int JVM_ACC_STRICT = 0x0800; /* strict floating point */ + static final int JVM_ACC_SYNTHETIC = 0x1000; /* compiler-generated class, method or field */ + static final int JVM_ACC_ANNOTATION = 0x2000; /* annotation type */ + static final int JVM_ACC_ENUM = 0x4000; /* field is declared as element of enum */ +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCleanupReader.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCleanupReader.java new file mode 100644 index 00000000000..eb3140c171b --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCleanupReader.java @@ -0,0 +1,212 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.*; +import java.util.regex.*; + +/** + * This class is a filter class to deal with malformed XML that used + * to be produced by the JVM when generating LogCompilation. In 1.6 + * and later releases it shouldn't be required. + * @author never + */ + +class LogCleanupReader extends Reader { + private Reader reader; + + private char[] buffer = new char[4096]; + + private int bufferCount; + + private int bufferOffset; + + private char[] line = new char[1024]; + + private int index; + + private int length; + + private char[] one = new char[1]; + + LogCleanupReader(Reader r) { + reader = r; + } + + static final private Matcher pattern = Pattern.compile(".+ compile_id='[0-9]+'.*( compile_id='[0-9]+)").matcher(""); + static final private Matcher pattern2 = Pattern.compile("' (C[12]) compile_id=").matcher(""); + static final private Matcher pattern3 = Pattern.compile("'(destroy_vm)/").matcher(""); + + private void fill() throws IOException { + rawFill(); + if (length != -1) { + boolean changed = false; + String s = new String(line, 0, length); + String orig = s; + + pattern2.reset(s); + if (pattern2.find()) { + s = s.substring(0, pattern2.start(1)) + s.substring(pattern2.end(1) + 1); + changed = true; + } + + pattern.reset(s); + if (pattern.lookingAt()) { + s = s.substring(0, pattern.start(1)) + s.substring(pattern.end(1) + 1); + changed = true; + } + + pattern3.reset(s); + if (pattern3.find()) { + s = s.substring(0, pattern3.start(1)) + s.substring(pattern3.end(1)); + changed = true; + } + + if (changed) { + s.getChars(0, s.length(), line, 0); + length = s.length(); + } + } + } + + private void rawFill() throws IOException { + if (bufferCount == -1) { + length = -1; + return; + } + + int i = 0; + boolean fillNonEOL = true; + outer: + while (true) { + if (fillNonEOL) { + int p; + for (p = bufferOffset; p < bufferCount; p++) { + char c = buffer[p]; + if (c == '\r' || c == '\n') { + bufferOffset = p; + fillNonEOL = false; + continue outer; + } + if (i >= line.length) { + // copy and enlarge the line array + char[] newLine = new char[line.length * 2]; + System.arraycopy(line, 0, newLine, 0, line.length); + line = newLine; + } + line[i++] = c; + } + bufferOffset = p; + } else { + int p; + for (p = bufferOffset; p < bufferCount; p++) { + char c = buffer[p]; + if (c != '\r' && c != '\n') { + bufferOffset = p; + length = i; + index = 0; + return; + } + line[i++] = c; + } + bufferOffset = p; + } + if (bufferCount == -1) { + if (i == 0) { + length = -1; + } else { + length = i; + } + index = 0; + return; + } + if (bufferOffset != bufferCount) { + System.out.println(bufferOffset); + System.out.println(bufferCount); + throw new InternalError("how did we get here"); + } + // load more data and try again. + bufferCount = reader.read(buffer, 0, buffer.length); + bufferOffset = 0; + } + } + + public int read() throws java.io.IOException { + read(one, 0, 1); + return one[0]; + } + + public int read(char[] buffer) throws java.io.IOException { + return read(buffer, 0, buffer.length); + } + + public int read(char[] b, int off, int len) throws java.io.IOException { + if (length == -1) { + return -1; + } + + if (index == length) { + fill(); + if (length == -1) { + return -1; + } + } + int n = Math.min(length - index, Math.min(b.length - off, len)); + // System.out.printf("%d %d %d %d %d\n", index, length, off, len, n); + System.arraycopy(line, index, b, off, n); + index += n; + return n; + } + + public long skip(long n) throws java.io.IOException { + long result = n; + while (n-- > 0) read(); + return result; + } + + public boolean ready() throws java.io.IOException { + return reader.ready() || (line != null && length > 0); + } + + public boolean markSupported() { + return false; + } + + public void mark(int unused) throws java.io.IOException { + throw new UnsupportedOperationException("mark not supported"); + } + + public void reset() throws java.io.IOException { + reader.reset(); + line = null; + index = 0; + } + + public void close() throws java.io.IOException { + reader.close(); + line = null; + index = 0; + } +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java new file mode 100644 index 00000000000..5edbad656ee --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java @@ -0,0 +1,177 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * The main command line driver of a parser for LogCompilation output. + * @author never + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.PrintStream; +import java.util.*; +import org.xml.sax.*; +import org.xml.sax.helpers.*; + +public class LogCompilation extends DefaultHandler implements ErrorHandler, Constants { + + public static void usage(int exitcode) { + System.out.println("Usage: LogCompilation [ -v ] [ -c ] [ -s ] [ -e | -N ] file1 ..."); + System.out.println(" -c: clean up malformed 1.5 xml"); + System.out.println(" -i: print inlining decisions"); + System.out.println(" -S: print compilation statistics"); + System.out.println(" -s: sort events by start time"); + System.out.println(" -e: sort events by elapsed time"); + System.out.println(" -N: sort events by name and start"); + System.exit(exitcode); + } + + public static void main(String[] args) throws Exception { + Comparator defaultSort = LogParser.sortByStart; + boolean statistics = false; + boolean printInlining = false; + boolean cleanup = false; + int index = 0; + + while (args.length > index) { + if (args[index].equals("-e")) { + defaultSort = LogParser.sortByElapsed; + index++; + } else if (args[index].equals("-n")) { + defaultSort = LogParser.sortByNameAndStart; + index++; + } else if (args[index].equals("-s")) { + defaultSort = LogParser.sortByStart; + index++; + } else if (args[index].equals("-c")) { + cleanup = true; + index++; + } else if (args[index].equals("-S")) { + statistics = true; + index++; + } else if (args[index].equals("-h")) { + usage(0); + } else if (args[index].equals("-i")) { + printInlining = true; + index++; + } else { + break; + } + } + + if (index >= args.length) { + usage(1); + } + + while (index < args.length) { + ArrayList events = LogParser.parse(args[index], cleanup); + + if (statistics) { + printStatistics(events, System.out); + } else { + Collections.sort(events, defaultSort); + for (LogEvent c : events) { + if (printInlining && c instanceof Compilation) { + Compilation comp = (Compilation)c; + comp.print(System.out, true); + } else { + c.print(System.out); + } + } + } + index++; + } + } + + public static void printStatistics(ArrayList events, PrintStream out) { + long cacheSize = 0; + long maxCacheSize = 0; + int nmethodsCreated = 0; + int nmethodsLive = 0; + int[] attempts = new int[32]; + double regallocTime = 0; + int maxattempts = 0; + + LinkedHashMap phaseTime = new LinkedHashMap(7); + LinkedHashMap phaseNodes = new LinkedHashMap(7); + double elapsed = 0; + + for (LogEvent e : events) { + if (e instanceof Compilation) { + Compilation c = (Compilation) e; + c.printShort(out); + out.printf(" %6.4f\n", c.getElapsedTime()); + attempts[c.getAttempts()]++; + maxattempts = Math.max(maxattempts,c.getAttempts()); + elapsed += c.getElapsedTime(); + for (Phase phase : c.getPhases()) { + out.printf("\t%s %6.4f\n", phase.getName(), phase.getElapsedTime()); + Double v = phaseTime.get(phase.getName()); + if (v == null) { + v = Double.valueOf(0.0); + } + phaseTime.put(phase.getName(), Double.valueOf(v.doubleValue() + phase.getElapsedTime())); + + Integer v2 = phaseNodes.get(phase.getName()); + if (v2 == null) { + v2 = Integer.valueOf(0); + } + phaseNodes.put(phase.getName(), Integer.valueOf(v2.intValue() + phase.getNodes())); + } + } else if (e instanceof MakeNotEntrantEvent) { + MakeNotEntrantEvent mne = (MakeNotEntrantEvent) e; + NMethod nm = mne.getNMethod(); + if (mne.isZombie()) { + if (nm == null) { + System.err.println(mne.getId()); + } + cacheSize -= nm.getSize(); + nmethodsLive--; + } + } else if (e instanceof NMethod) { + nmethodsLive++; + nmethodsCreated++; + NMethod nm = (NMethod) e; + cacheSize += nm.getSize(); + maxCacheSize = Math.max(cacheSize, maxCacheSize); + } + } + out.printf("NMethods: %d created %d live %d bytes (%d peak) in the code cache\n", + nmethodsCreated, nmethodsLive, cacheSize, maxCacheSize); + out.println("Phase times:"); + for (String name : phaseTime.keySet()) { + Double v = phaseTime.get(name); + Integer v2 = phaseNodes.get(name); + out.printf("%20s %6.4f %d\n", name, v.doubleValue(), v2.intValue()); + } + out.printf("%20s %6.4f\n", "total", elapsed); + + if (maxattempts > 0) { + out.println("Distribution of regalloc passes:"); + for (int i = 0; i <= maxattempts; i++) { + out.printf("%2d %8d\n", i, attempts[i]); + } + } + } +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogEvent.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogEvent.java new file mode 100644 index 00000000000..69f6d385b0e --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogEvent.java @@ -0,0 +1,38 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.PrintStream; +import java.util.*; + +public interface LogEvent { + public double getStart(); + + public double getElapsedTime(); + + public Compilation getCompilation(); + + public void print(PrintStream stream); +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java new file mode 100644 index 00000000000..bfff7dfa916 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java @@ -0,0 +1,430 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * A SAX based parser of LogCompilation output from HotSpot. It takes a complete + * @author never + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.FileReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Stack; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +public class LogParser extends DefaultHandler implements ErrorHandler, Constants { + + static final HashMap typeMap; + static { + typeMap = new HashMap(); + typeMap.put("[I", "int[]"); + typeMap.put("[C", "char[]"); + typeMap.put("[Z", "boolean[]"); + typeMap.put("[L", "Object[]"); + typeMap.put("[B", "byte[]"); + } + + static Comparator sortByStart = new Comparator() { + + public int compare(LogEvent a, LogEvent b) { + double difference = (a.getStart() - b.getStart()); + if (difference < 0) { + return -1; + } + if (difference > 0) { + return 1; + } + return 0; + } + + @Override + public boolean equals(Object other) { + return false; + } + + @Override + public int hashCode() { + return 7; + } + }; + static Comparator sortByNameAndStart = new Comparator() { + + public int compare(LogEvent a, LogEvent b) { + Compilation c1 = a.getCompilation(); + Compilation c2 = b.getCompilation(); + if (c1 != null && c2 != null) { + int result = c1.getMethod().toString().compareTo(c2.getMethod().toString()); + if (result != 0) { + return result; + } + } + double difference = (a.getStart() - b.getStart()); + if (difference < 0) { + return -1; + } + if (difference > 0) { + return 1; + } + return 0; + } + + public boolean equals(Object other) { + return false; + } + + @Override + public int hashCode() { + return 7; + } + }; + static Comparator sortByElapsed = new Comparator() { + + public int compare(LogEvent a, LogEvent b) { + double difference = (a.getElapsedTime() - b.getElapsedTime()); + if (difference < 0) { + return -1; + } + if (difference > 0) { + return 1; + } + return 0; + } + + @Override + public boolean equals(Object other) { + return false; + } + + @Override + public int hashCode() { + return 7; + } + }; + + private ArrayList events = new ArrayList(); + + private HashMap types = new HashMap(); + private HashMap methods = new HashMap(); + private LinkedHashMap nmethods = new LinkedHashMap(); + private HashMap compiles = new HashMap(); + private String failureReason; + private int bci; + private Stack scopes = new Stack(); + private Compilation compile; + private CallSite site; + private Stack phaseStack = new Stack(); + private UncommonTrapEvent currentTrap; + + long parseLong(String l) { + try { + return Long.decode(l).longValue(); + } catch (NumberFormatException nfe) { + int split = l.length() - 8; + String s1 = "0x" + l.substring(split); + String s2 = l.substring(0, split); + long v1 = Long.decode(s1).longValue() & 0xffffffffL; + long v2 = (Long.decode(s2).longValue() & 0xffffffffL) << 32; + if (!l.equals("0x" + Long.toHexString(v1 + v2))) { + System.out.println(l); + System.out.println(s1); + System.out.println(s2); + System.out.println(v1); + System.out.println(v2); + System.out.println(Long.toHexString(v1 + v2)); + throw new InternalError("bad conversion"); + } + return v1 + v2; + } + } + + public static ArrayList parse(String file, boolean cleanup) throws Exception { + return parse(new FileReader(file), cleanup); + } + + public static ArrayList parse(Reader reader, boolean cleanup) throws Exception { + // Create the XML input factory + SAXParserFactory factory = SAXParserFactory.newInstance(); + + // Create the XML LogEvent reader + SAXParser p = factory.newSAXParser(); + + if (cleanup) { + // some versions of the log have slightly malformed XML, so clean it + // up before passing it to SAX + reader = new LogCleanupReader(reader); + } + + LogParser log = new LogParser(); + p.parse(new InputSource(reader), log); + + // Associate compilations with their NMethods + for (NMethod nm : log.nmethods.values()) { + Compilation c = log.compiles.get(nm.getId()); + nm.setCompilation(c); + // Native wrappers for methods don't have a compilation + if (c != null) { + c.setNMethod(nm); + } + } + + // Initially we want the LogEvent log sorted by timestamp + Collections.sort(log.events, sortByStart); + + return log.events; + } + + String search(Attributes attr, String name) { + return search(attr, name, null); + } + + String search(Attributes attr, String name, String defaultValue) { + String result = attr.getValue(name); + if (result != null) { + return result; + } + if (defaultValue != null) { + return defaultValue; + } + for (int i = 0; i < attr.getLength(); i++) { + System.out.println(attr.getQName(i) + " " + attr.getValue(attr.getQName(i))); + } + throw new InternalError("can't find " + name); + } + int indent = 0; + String compile_id; + + String type(String id) { + String result = types.get(id); + if (result == null) { + throw new InternalError(id); + } + String remapped = typeMap.get(result); + if (remapped != null) { + return remapped; + } + return result; + } + + void type(String id, String name) { + assert type(id) == null; + types.put(id, name); + } + + Method method(String id) { + Method result = methods.get(id); + if (result == null) { + throw new InternalError(id); + } + return result; + } + + public String makeId(Attributes atts) { + String id = atts.getValue("compile_id"); + String kind = atts.getValue("kind"); + if (kind != null && kind.equals("osr")) { + id += "%"; + } + return id; + } + + @Override + public void startElement(String uri, + String localName, + String qname, + Attributes atts) { + if (qname.equals("phase")) { + Phase p = new Phase(search(atts, "name"), + Double.parseDouble(search(atts, "stamp")), + Integer.parseInt(search(atts, "nodes"))); + phaseStack.push(p); + } else if (qname.equals("phase_done")) { + Phase p = phaseStack.pop(); + p.setEndNodes(Integer.parseInt(search(atts, "nodes"))); + p.setEnd(Double.parseDouble(search(atts, "stamp"))); + compile.getPhases().add(p); + } else if (qname.equals("task")) { + compile = new Compilation(Integer.parseInt(search(atts, "compile_id", "-1"))); + compile.setStart(Double.parseDouble(search(atts, "stamp"))); + compile.setICount(search(atts, "count", "0")); + compile.setBCount(search(atts, "backedge_count", "0")); + + String method = atts.getValue("method"); + int space = method.indexOf(' '); + method = method.substring(0, space) + "::" + + method.substring(space + 1, method.indexOf(' ', space + 1) + 1); + String compiler = atts.getValue("compiler"); + if (compiler == null) { + compiler = ""; + } + String kind = atts.getValue("compile_kind"); + if (kind == null) { + kind = "normal"; + } + if (kind.equals("osr")) { + compile.setOsr(true); + compile.setOsr_bci(Integer.parseInt(search(atts, "osr_bci"))); + } else if (kind.equals("c2i")) { + compile.setSpecial("--- adapter " + method); + } else { + compile.setSpecial(compile.getId() + " " + method + " (0 bytes)"); + } + events.add(compile); + compiles.put(makeId(atts), compile); + } else if (qname.equals("type")) { + type(search(atts, "id"), search(atts, "name")); + } else if (qname.equals("bc")) { + bci = Integer.parseInt(search(atts, "bci")); + } else if (qname.equals("klass")) { + type(search(atts, "id"), search(atts, "name")); + } else if (qname.equals("method")) { + String id = search(atts, "id"); + Method m = new Method(); + m.setHolder(type(search(atts, "holder"))); + m.setName(search(atts, "name")); + m.setReturnType(type(search(atts, "return"))); + m.setArguments(search(atts, "arguments", "void")); + m.setBytes(search(atts, "bytes")); + m.setIICount(search(atts, "iicount")); + m.setFlags(search(atts, "flags")); + methods.put(id, m); + } else if (qname.equals("call")) { + site = new CallSite(bci, method(search(atts, "method"))); + site.setCount(Integer.parseInt(search(atts, "count"))); + String receiver = atts.getValue("receiver"); + if (receiver != null) { + site.setReceiver(type(receiver)); + site.setReceiver_count(Integer.parseInt(search(atts, "receiver_count"))); + } + scopes.peek().add(site); + } else if (qname.equals("regalloc")) { + compile.setAttempts(Integer.parseInt(search(atts, "attempts"))); + } else if (qname.equals("inline_fail")) { + scopes.peek().last().setReason(search(atts, "reason")); + } else if (qname.equals("failure")) { + failureReason = search(atts, "reason"); + } else if (qname.equals("task_done")) { + compile.setEnd(Double.parseDouble(search(atts, "stamp"))); + if (Integer.parseInt(search(atts, "success")) == 0) { + compile.setFailureReason(failureReason); + } + } else if (qname.equals("make_not_entrant")) { + String id = makeId(atts); + NMethod nm = nmethods.get(id); + if (nm == null) throw new InternalError(); + LogEvent e = new MakeNotEntrantEvent(Double.parseDouble(search(atts, "stamp")), id, + atts.getValue("zombie") != null, nm); + events.add(e); + } else if (qname.equals("uncommon_trap")) { + String id = atts.getValue("compile_id"); + if (id != null) { + id = makeId(atts); + currentTrap = new UncommonTrapEvent(Double.parseDouble(search(atts, "stamp")), + id, + atts.getValue("reason"), + atts.getValue("action"), + Integer.parseInt(search(atts, "count", "0"))); + events.add(currentTrap); + } else { + // uncommon trap inserted during parsing. + // ignore for now + } + } else if (qname.equals("jvms")) { + // + if (currentTrap != null) { + currentTrap.addJVMS(atts.getValue("method"), Integer.parseInt(atts.getValue("bci"))); + } else { + System.err.println("Missing uncommon_trap for jvms"); + } + } else if (qname.equals("nmethod")) { + String id = makeId(atts); + NMethod nm = new NMethod(Double.parseDouble(search(atts, "stamp")), + id, + parseLong(atts.getValue("address")), + parseLong(atts.getValue("size"))); + nmethods.put(id, nm); + events.add(nm); + } else if (qname.equals("parse")) { + Method m = method(search(atts, "method")); + if (scopes.size() == 0) { + compile.setMethod(m); + scopes.push(compile.getCall()); + } else { + if (site.getMethod() == m) { + scopes.push(site); + } else if (scopes.peek().getCalls().size() > 2 && m == scopes.peek().last(-2).getMethod()) { + scopes.push(scopes.peek().last(-2)); + } else { + System.out.println(site.getMethod()); + System.out.println(m); + throw new InternalError("call site and parse don't match"); + } + } + } + } + + @Override + public void endElement(String uri, + String localName, + String qname) { + if (qname.equals("parse")) { + indent -= 2; + scopes.pop(); + } else if (qname.equals("uncommon_trap")) { + currentTrap = null; + } else if (qname.equals("task")) { + types.clear(); + methods.clear(); + site = null; + } + } + + @Override + public void warning(org.xml.sax.SAXParseException e) { + System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber()); + e.printStackTrace(); + } + + @Override + public void error(org.xml.sax.SAXParseException e) { + System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber()); + e.printStackTrace(); + } + + @Override + public void fatalError(org.xml.sax.SAXParseException e) { + System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber()); + e.printStackTrace(); + } +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java new file mode 100644 index 00000000000..2b3fc56b359 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java @@ -0,0 +1,55 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.PrintStream; + +class MakeNotEntrantEvent extends BasicLogEvent { + private final boolean zombie; + + private NMethod nmethod; + + MakeNotEntrantEvent(double s, String i, boolean z, NMethod nm) { + super(s, i); + zombie = z; + nmethod = nm; + } + + public NMethod getNMethod() { + return nmethod; + } + + public void print(PrintStream stream) { + if (isZombie()) { + stream.printf("%s make_zombie\n", getId()); + } else { + stream.printf("%s make_not_entrant\n", getId()); + } + } + + public boolean isZombie() { + return zombie; + } +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Method.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Method.java new file mode 100644 index 00000000000..f2c9a9c710b --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Method.java @@ -0,0 +1,120 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.util.Arrays; + +public class Method implements Constants { + + private String holder; + private String name; + private String returnType; + private String arguments; + private String bytes; + private String iicount; + private String flags; + + String decodeFlags(int osr_bci) { + int f = Integer.parseInt(getFlags()); + char[] c = new char[4]; + Arrays.fill(c, ' '); + if (osr_bci >= 0) { + c[0] = '%'; + } + if ((f & JVM_ACC_SYNCHRONIZED) != 0) { + c[1] = 's'; + } + return new String(c); + } + + String format(int osr_bci) { + if (osr_bci >= 0) { + return getHolder().replace('/', '.') + "::" + getName() + " @ " + osr_bci + " (" + getBytes() + " bytes)"; + } else { + return getHolder().replace('/', '.') + "::" + getName() + " (" + getBytes() + " bytes)"; + } + } + + @Override + public String toString() { + return getHolder().replace('/', '.') + "::" + getName() + " (" + getBytes() + " bytes)"; + } + + public String getHolder() { + return holder; + } + + public void setHolder(String holder) { + this.holder = holder; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getReturnType() { + return returnType; + } + + public void setReturnType(String returnType) { + this.returnType = returnType; + } + + public String getArguments() { + return arguments; + } + + public void setArguments(String arguments) { + this.arguments = arguments; + } + + public String getBytes() { + return bytes; + } + + public void setBytes(String bytes) { + this.bytes = bytes; + } + + public String getIICount() { + return iicount; + } + + public void setIICount(String iicount) { + this.iicount = iicount; + } + + public String getFlags() { + return flags; + } + + public void setFlags(String flags) { + this.flags = flags; + } +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/NMethod.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/NMethod.java new file mode 100644 index 00000000000..8fb277d00d6 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/NMethod.java @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.PrintStream; + +public class NMethod extends BasicLogEvent { + + private long address; + private long size; + + NMethod(double s, String i, long a, long sz) { + super(s, i); + address = a; + size = sz; + } + + public void print(PrintStream out) { + // XXX Currently we do nothing + // throw new InternalError(); + } + + public long getAddress() { + return address; + } + + public void setAddress(long address) { + this.address = address; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Phase.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Phase.java new file mode 100644 index 00000000000..8c29149a217 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Phase.java @@ -0,0 +1,63 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.PrintStream; + +public class Phase extends BasicLogEvent { + + private final int startNodes; + private int endNodes; + + Phase(String n, double s, int nodes) { + super(s, n); + startNodes = nodes; + } + + int getNodes() { + return getStartNodes(); + } + + void setEndNodes(int n) { + endNodes = n; + } + + public String getName() { + return getId(); + } + + public int getStartNodes() { + return startNodes; + } + + public int getEndNodes() { + return endNodes; + } + + @Override + public void print(PrintStream stream) { + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java new file mode 100644 index 00000000000..894cbdc7724 --- /dev/null +++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java @@ -0,0 +1,84 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.hotspot.tools.compiler; + +import java.io.PrintStream; + +class UncommonTrapEvent extends BasicLogEvent { + + private final String reason; + private final String action; + private int count; + private String jvms = ""; + + UncommonTrapEvent(double s, String i, String r, String a, int c) { + super(s, i); + reason = r; + action = a; + count = c; + } + + + public void addJVMS(String method, int bci) { + setJvms(getJvms() + " @" + bci + " " + method + "\n"); + } + + public void updateCount(UncommonTrapEvent trap) { + setCount(Math.max(getCount(), trap.getCount())); + } + + public void print(PrintStream stream) { + stream.printf("%s uncommon trap %s %s\n", getId(), getReason(), getAction()); + stream.print(getJvms()); + } + + public String getReason() { + return reason; + } + + public String getAction() { + return action; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public String getJvms() { + return jvms; + } + + public void setJvms(String jvms) { + this.jvms = jvms; + } + + public void setCompilation(Compilation compilation) { + this.compilation = compilation; + } +} diff --git a/hotspot/src/share/tools/MakeDeps/BuildConfig.java b/hotspot/src/share/tools/MakeDeps/BuildConfig.java index 442972dab9c..accdab67550 100644 --- a/hotspot/src/share/tools/MakeDeps/BuildConfig.java +++ b/hotspot/src/share/tools/MakeDeps/BuildConfig.java @@ -247,6 +247,7 @@ class BuildConfig { sysDefines.add("HOTSPOT_BUILD_USER="+System.getProperty("user.name")); sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\""); sysDefines.add("_JNI_IMPLEMENTATION_"); + sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i486\\\""); sysDefines.addAll(defines); diff --git a/hotspot/src/share/tools/MakeDeps/Database.java b/hotspot/src/share/tools/MakeDeps/Database.java index 5cec93b7d03..3cdffebca49 100644 --- a/hotspot/src/share/tools/MakeDeps/Database.java +++ b/hotspot/src/share/tools/MakeDeps/Database.java @@ -365,7 +365,7 @@ public class Database { // HACK ALERT. The compilation of ad_ files is very slow. // We want to start compiling them as early as possible. The compilation - // order on unix is dependant on the order we emit files here. + // order on unix is dependent on the order we emit files here. // By sorting the output before emitting it, we expect // that ad_ will be compiled early. boolean shouldSortObjFiles = true; diff --git a/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC7.java b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC7.java index 82159a41835..109613b45d7 100644 --- a/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC7.java +++ b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC7.java @@ -27,6 +27,8 @@ import java.util.*; public class WinGammaPlatformVC7 extends WinGammaPlatform { + String projectVersion() {return "7.10";}; + public void writeProjectFile(String projectFileName, String projectName, Vector allConfigs) throws IOException { System.out.println(); @@ -40,7 +42,7 @@ public class WinGammaPlatformVC7 extends WinGammaPlatform { "VisualStudioProject", new String[] { "ProjectType", "Visual C++", - "Version", "7.10", + "Version", projectVersion(), "Name", projectName, "ProjectGUID", "{8822CB5C-1C41-41C2-8493-9F6E1994338B}", "SccProjectName", "", @@ -417,7 +419,9 @@ public class WinGammaPlatformVC7 extends WinGammaPlatform { new String[] { "Name", "VCPreLinkEventTool", "Description", BuildConfig.getFieldString(null, "PrelinkDescription"), - "CommandLine", cfg.expandFormat(BuildConfig.getFieldString(null, "PrelinkCommand").replace('\t', '\n')) + //Caution: String.replace(String,String) is available from JDK5 onwards only + "CommandLine", cfg.expandFormat(BuildConfig.getFieldString(null, "PrelinkCommand").replace + ("\t", " ")) } ); @@ -542,25 +546,41 @@ public class WinGammaPlatformVC7 extends WinGammaPlatform { } class CompilerInterfaceVC7 extends CompilerInterface { - Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) { - Vector rv = new Vector(); + void getBaseCompilerFlags_common(Vector defines, Vector includes, String outDir,Vector rv) { // advanced M$ IDE (2003) can only recognize name if it's first or // second attribute in the tag - go guess addAttr(rv, "Name", "VCCLCompilerTool"); addAttr(rv, "AdditionalIncludeDirectories", Util.join(",", includes)); - addAttr(rv, "PreprocessorDefinitions", Util.join(";", defines).replace("\"",""")); - addAttr(rv, "UsePrecompiledHeader", "3"); - addAttr(rv, "PrecompiledHeaderThrough", "incls"+Util.sep+"_precompiled.incl"); + addAttr(rv, "PreprocessorDefinitions", + Util.join(";", defines).replace("\"",""")); + addAttr(rv, "PrecompiledHeaderThrough", + "incls"+Util.sep+"_precompiled.incl"); addAttr(rv, "PrecompiledHeaderFile", outDir+Util.sep+"vm.pch"); addAttr(rv, "AssemblerListingLocation", outDir); addAttr(rv, "ObjectFile", outDir+Util.sep); addAttr(rv, "ProgramDataBaseFileName", outDir+Util.sep+"vm.pdb"); + // Set /nologo optin addAttr(rv, "SuppressStartupBanner", "TRUE"); + // Surpass the default /Tc or /Tp. 0 is compileAsDefault addAttr(rv, "CompileAs", "0"); + // Set /W3 option. 3 is warningLevel_3 addAttr(rv, "WarningLevel", "3"); + // Set /WX option, addAttr(rv, "WarnAsError", "TRUE"); + // Set /GS option addAttr(rv, "BufferSecurityCheck", "FALSE"); + // Set /Zi option. 3 is debugEnabled + addAttr(rv, "DebugInformationFormat", "3"); + } + Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) { + Vector rv = new Vector(); + + getBaseCompilerFlags_common(defines,includes, outDir, rv); + // Set /Yu option. 3 is pchUseUsingSpecific + // Note: Starting VC8 pchUseUsingSpecific is 2 !!! + addAttr(rv, "UsePrecompiledHeader", "3"); + // Set /EHsc- option addAttr(rv, "ExceptionHandling", "FALSE"); return rv; @@ -579,27 +599,39 @@ class CompilerInterfaceVC7 extends CompilerInterface { "/export:jio_vsnprintf "); addAttr(rv, "AdditionalDependencies", "Wsock32.lib winmm.lib"); addAttr(rv, "OutputFile", outDll); + // Set /INCREMENTAL option. 1 is linkIncrementalNo addAttr(rv, "LinkIncremental", "1"); addAttr(rv, "SuppressStartupBanner", "TRUE"); addAttr(rv, "ModuleDefinitionFile", outDir+Util.sep+"vm.def"); addAttr(rv, "ProgramDatabaseFile", outDir+Util.sep+"vm.pdb"); + // Set /SUBSYSTEM option. 2 is subSystemWindows addAttr(rv, "SubSystem", "2"); addAttr(rv, "BaseAddress", "0x8000000"); addAttr(rv, "ImportLibrary", outDir+Util.sep+"jvm.lib"); + // Set /MACHINE option. 1 is machineX86 addAttr(rv, "TargetMachine", "1"); return rv; } + void getDebugCompilerFlags_common(String opt,Vector rv) { + + // Set /On option + addAttr(rv, "Optimization", opt); + // Set /FR option. 1 is brAllInfo + addAttr(rv, "BrowseInformation", "1"); + addAttr(rv, "BrowseInformationFile", "$(IntDir)" + Util.sep); + // Set /MD option. 2 is rtMultiThreadedDLL + addAttr(rv, "RuntimeLibrary", "2"); + // Set /Oy- option + addAttr(rv, "OmitFramePointers", "FALSE"); + + } + Vector getDebugCompilerFlags(String opt) { Vector rv = new Vector(); - addAttr(rv, "Optimization", opt); - addAttr(rv, "OptimizeForProcessor", "1"); - addAttr(rv, "DebugInformationFormat", "3"); - addAttr(rv, "RuntimeLibrary", "2"); - addAttr(rv, "BrowseInformation", "1"); - addAttr(rv, "BrowseInformationFile", "$(IntDir)" + Util.sep); + getDebugCompilerFlags_common(opt,rv); return rv; } @@ -607,18 +639,29 @@ class CompilerInterfaceVC7 extends CompilerInterface { Vector getDebugLinkerFlags() { Vector rv = new Vector(); - addAttr(rv, "GenerateDebugInformation", "TRUE"); + addAttr(rv, "GenerateDebugInformation", "TRUE"); // == /DEBUG option return rv; } + void getProductCompilerFlags_common(Vector rv) { + // Set /O2 option. 2 is optimizeMaxSpeed + addAttr(rv, "Optimization", "2"); + // Set /Oy- option + addAttr(rv, "OmitFramePointers", "FALSE"); + } + Vector getProductCompilerFlags() { Vector rv = new Vector(); - addAttr(rv, "Optimization", "2"); + getProductCompilerFlags_common(rv); + // Set /Ob option. 1 is expandOnlyInline addAttr(rv, "InlineFunctionExpansion", "1"); + // Set /GF option. addAttr(rv, "StringPooling", "TRUE"); + // Set /MD option. 2 is rtMultiThreadedDLL addAttr(rv, "RuntimeLibrary", "2"); + // Set /Gy option addAttr(rv, "EnableFunctionLevelLinking", "TRUE"); return rv; @@ -627,7 +670,9 @@ class CompilerInterfaceVC7 extends CompilerInterface { Vector getProductLinkerFlags() { Vector rv = new Vector(); + // Set /OPT:REF option. 2 is optReferences addAttr(rv, "OptimizeReferences", "2"); + // Set /OPT:optFolding option. 2 is optFolding addAttr(rv, "EnableCOMDATFolding", "2"); return rv; diff --git a/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC8.java b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC8.java new file mode 100644 index 00000000000..a346b611560 --- /dev/null +++ b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC8.java @@ -0,0 +1,66 @@ +/* + * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +import java.io.*; +import java.util.*; + +public class WinGammaPlatformVC8 extends WinGammaPlatformVC7 { + + String projectVersion() {return "8.00";}; + +} + +class CompilerInterfaceVC8 extends CompilerInterfaceVC7 { + + Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) { + Vector rv = new Vector(); + + getBaseCompilerFlags_common(defines,includes, outDir, rv); + // Set /Yu option. 2 is pchUseUsingSpecific + addAttr(rv, "UsePrecompiledHeader", "2"); + // Set /EHsc- option. 0 is cppExceptionHandlingNo + addAttr(rv, "ExceptionHandling", "0"); + + return rv; + } + + + Vector getDebugCompilerFlags(String opt) { + Vector rv = new Vector(); + + getDebugCompilerFlags_common(opt,rv); + + return rv; + } + + Vector getProductCompilerFlags() { + Vector rv = new Vector(); + + getProductCompilerFlags_common(rv); + + return rv; + } + + +} diff --git a/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC9.java b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC9.java new file mode 100644 index 00000000000..4b64a555833 --- /dev/null +++ b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC9.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +import java.io.*; +import java.util.*; + +public class WinGammaPlatformVC9 extends WinGammaPlatformVC8 { + + String projectVersion() {return "9.00";}; + +} + +class CompilerInterfaceVC9 extends CompilerInterfaceVC8 { +} diff --git a/hotspot/src/share/vm/adlc/Doc/Syntax.doc b/hotspot/src/share/vm/adlc/Doc/Syntax.doc index ade893410c3..c2a24afc3a8 100644 --- a/hotspot/src/share/vm/adlc/Doc/Syntax.doc +++ b/hotspot/src/share/vm/adlc/Doc/Syntax.doc @@ -88,7 +88,7 @@ reg_class X_REG(AX, BX); // form a matcher register class of X_REG // these are used for constraints, etc. alloc_class class1(AX, BX); // form an allocation class of registers - // used by the register allocator for seperate + // used by the register allocator for separate // allocation of target register classes 3. Pipeline Syntax for Scheduling @@ -150,7 +150,7 @@ D. Delimiters b. %} (block terminator) c. EOF (file terminator) - 4. Each statement must start on a seperate line + 4. Each statement must start on a separate line 5. Identifiers cannot contain: (){}%;,"/\ diff --git a/hotspot/src/share/vm/adlc/adlc.hpp b/hotspot/src/share/vm/adlc/adlc.hpp index 14bc5d6b738..6b92dfd8476 100644 --- a/hotspot/src/share/vm/adlc/adlc.hpp +++ b/hotspot/src/share/vm/adlc/adlc.hpp @@ -44,7 +44,7 @@ using namespace std; #error "Something is wrong with the detection of MSC_VER in the makefiles" #endif -#if _MSC_VER >= 1400 && !defined(_WIN64) +#if _MSC_VER >= 1400 #define strdup _strdup #endif @@ -79,6 +79,7 @@ typedef unsigned int uintptr_t; // Macros // Debugging note: Put a breakpoint on "abort". +#undef assert #define assert(cond, msg) { if (!(cond)) { fprintf(stderr, "assert fails %s %d: %s\n", __FILE__, __LINE__, msg); abort(); }} #define max(a, b) (((a)>(b)) ? (a) : (b)) diff --git a/hotspot/src/share/vm/adlc/adlparse.cpp b/hotspot/src/share/vm/adlc/adlparse.cpp index 81a95e861ab..61ba5e2483c 100644 --- a/hotspot/src/share/vm/adlc/adlparse.cpp +++ b/hotspot/src/share/vm/adlc/adlparse.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -298,7 +298,7 @@ void ADLParser::matchrule_clone_and_swap(MatchRule* rule, const char* instr_iden rule->count_commutative_op(count); if (count > 0) { // Clone match rule and swap commutative operation's operands. - rule->swap_commutative_op(instr_ident, count, match_rules_cnt); + rule->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt); } } @@ -2586,7 +2586,7 @@ void ADLParser::peep_constraint_parse(Peephole &peep) { while( _curchar != ')' ) { // Get information on the left instruction and its operand // left-instructions's number - intptr_t left_inst = get_int(); + int left_inst = get_int(); // Left-instruction's operand skipws(); if( _curchar != '.' ) { @@ -2602,7 +2602,7 @@ void ADLParser::peep_constraint_parse(Peephole &peep) { skipws(); // Get information on the right instruction and its operand - intptr_t right_inst; // Right-instructions's number + int right_inst; // Right-instructions's number if( isdigit(_curchar) ) { right_inst = get_int(); // Right-instruction's operand @@ -3497,22 +3497,24 @@ FormatRule* ADLParser::template_parse(void) { // (1) // Check if there is a string to pass through to output - char *start = _ptr; // Record start of the next string - while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) { - // If at the start of a comment, skip past it - if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) { - skipws_no_preproc(); - } else { - // ELSE advance to the next character, or start of the next line - next_char_or_line(); + { + char *start = _ptr; // Record start of the next string + while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) { + // If at the start of a comment, skip past it + if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) { + skipws_no_preproc(); + } else { + // ELSE advance to the next character, or start of the next line + next_char_or_line(); + } + } + // If a string was found, terminate it and record in EncClass + if ( start != _ptr ) { + *_ptr = '\0'; // Terminate the string + // Add flag to _strings list indicating we should check _rep_vars + format->_strings.addName(NameList::_signal2); + format->_strings.addName(start); } - } - // If a string was found, terminate it and record in EncClass - if ( start != _ptr ) { - *_ptr = '\0'; // Terminate the string - // Add flag to _strings list indicating we should check _rep_vars - format->_strings.addName(NameList::_signal2); - format->_strings.addName(start); } // (2) @@ -3563,10 +3565,10 @@ FormatRule* ADLParser::template_parse(void) { // copy it and record in FormatRule if ( _curchar == '$' ) { next_char(); // Move past the '$' - char* rep_var = get_ident(); // Nil terminate the variable name - rep_var = strdup(rep_var);// Copy the string + char* next_rep_var = get_ident(); // Nil terminate the variable name + next_rep_var = strdup(next_rep_var);// Copy the string *_ptr = _curchar; // and replace Nil with original character - format->_rep_vars.addName(rep_var); + format->_rep_vars.addName(next_rep_var); // Add flag to _strings list indicating we should check _rep_vars format->_strings.addName(NameList::_signal); } @@ -3714,13 +3716,13 @@ ExpandRule* ADLParser::expand_parse(InstructForm *instr) { parse_err(SYNERR, "identifier expected at %c\n", _curchar); continue; } // Check that you have a valid operand - const Form *form = instr->_localNames[ident2]; - if (!form) { + const Form *form2 = instr->_localNames[ident2]; + if (!form2) { parse_err(SYNERR, "operand name expected at %s\n", ident2); continue; } - oper = form->is_operand(); - if (oper == NULL && !form->is_opclass()) { + oper = form2->is_operand(); + if (oper == NULL && !form2->is_opclass()) { parse_err(SYNERR, "operand name expected at %s\n", ident2); continue; } // Add operand to list @@ -4271,7 +4273,7 @@ int ADLParser::get_int(void) { int result; // Storage for integer result if( _curline == NULL ) // Return NULL at EOF. - return NULL; + return 0; skipws(); // Skip whitespace before identifier start = end = _ptr; // Start points at first character @@ -4553,7 +4555,7 @@ void ADLParser::parse_err(int flag, const char *fmt, ...) { //---------------------------ensure_start_of_line------------------------------ // A preprocessor directive has been encountered. Be sure it has fallen at -// the begining of a line, or else report an error. +// the beginning of a line, or else report an error. void ADLParser::ensure_start_of_line(void) { if (_curchar == '\n') { next_line(); return; } assert( _ptr >= _curline && _ptr < _curline+strlen(_curline), diff --git a/hotspot/src/share/vm/adlc/adlparse.hpp b/hotspot/src/share/vm/adlc/adlparse.hpp index 0840bfc758b..caedec483a4 100644 --- a/hotspot/src/share/vm/adlc/adlparse.hpp +++ b/hotspot/src/share/vm/adlc/adlparse.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/adlc/archDesc.cpp b/hotspot/src/share/vm/adlc/archDesc.cpp index a73ad76da23..408f0323cd1 100644 --- a/hotspot/src/share/vm/adlc/archDesc.cpp +++ b/hotspot/src/share/vm/adlc/archDesc.cpp @@ -1,5 +1,5 @@ // -// Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -436,10 +436,12 @@ void ArchDesc::build_chain_rule(OperandForm *oper) { if ((oper->_matrule) && (oper->_matrule->_lChild == NULL) && (oper->_matrule->_rChild == NULL)) { - const Form *form = _globalNames[oper->_matrule->_opType]; - if ((form) && form->is_operand() && - (form->ideal_only() == false)) { - add_chain_rule_entry(oper->_matrule->_opType, oper->cost(), oper->_ident); + { + const Form *form = _globalNames[oper->_matrule->_opType]; + if ((form) && form->is_operand() && + (form->ideal_only() == false)) { + add_chain_rule_entry(oper->_matrule->_opType, oper->cost(), oper->_ident); + } } // Check for additional chain rules if (oper->_matrule->_next) { @@ -1015,12 +1017,12 @@ void ArchDesc::initBaseOpTypes() { int idealIndex = 0; for (idealIndex = 1; idealIndex < _last_machine_leaf; ++idealIndex) { const char *idealName = NodeClassNames[idealIndex]; - _idealIndex.Insert((void*)idealName, (void*)idealIndex); + _idealIndex.Insert((void*) idealName, (void*) (intptr_t) idealIndex); } for ( idealIndex = _last_machine_leaf+1; idealIndex < _last_opcode; ++idealIndex) { const char *idealName = NodeClassNames[idealIndex]; - _idealIndex.Insert((void*)idealName, (void*)idealIndex); + _idealIndex.Insert((void*) idealName, (void*) (intptr_t) idealIndex); } } diff --git a/hotspot/src/share/vm/adlc/dfa.cpp b/hotspot/src/share/vm/adlc/dfa.cpp index 1075c9da774..20834184732 100644 --- a/hotspot/src/share/vm/adlc/dfa.cpp +++ b/hotspot/src/share/vm/adlc/dfa.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -870,7 +870,7 @@ void ExprDict::print_asserts(FILE *fp) { } // Print out the dictionary contents as key-value pairs -static void dumpekey(const void* key) { fprintf(stdout, "%s", key); } +static void dumpekey(const void* key) { fprintf(stdout, "%s", (char*) key); } static void dumpexpr(const void* expr) { fflush(stdout); ((Expr*)expr)->print(); } void ExprDict::dump() { @@ -1020,7 +1020,7 @@ void ProductionState::set_cost_bounds(const char *result, const Expr *cost, bool } // Print out the dictionary contents as key-value pairs -static void print_key (const void* key) { fprintf(stdout, "%s", key); } +static void print_key (const void* key) { fprintf(stdout, "%s", (char*) key); } static void print_production(const void* production) { fflush(stdout); ((Production*)production)->print(); } void ProductionState::print() { diff --git a/hotspot/src/share/vm/adlc/dict2.cpp b/hotspot/src/share/vm/adlc/dict2.cpp index f46693fd06c..e993e86ee45 100644 --- a/hotspot/src/share/vm/adlc/dict2.cpp +++ b/hotspot/src/share/vm/adlc/dict2.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2002 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -275,7 +275,7 @@ void Dict::print(PrintKeyOrValue print_key, PrintKeyOrValue print_value) { // Convert string to hash key. This algorithm implements a universal hash // function with the multipliers frozen (ok, so it's not universal). The // multipliers (and allowable characters) are all odd, so the resultant sum -// is odd - guarenteed not divisible by any power of two, so the hash tables +// is odd - guaranteed not divisible by any power of two, so the hash tables // can be any power of two with good results. Also, I choose multipliers // that have only 2 bits set (the low is always set to be odd) so // multiplication requires only shifts and adds. Characters are required to @@ -296,7 +296,7 @@ int hashstr(const void *t) { } //------------------------------hashptr-------------------------------------- -// Slimey cheap hash function; no guarenteed performance. Better than the +// Slimey cheap hash function; no guaranteed performance. Better than the // default for pointers, especially on MS-DOS machines. int hashptr(const void *key) { #ifdef __TURBOC__ @@ -306,7 +306,7 @@ int hashptr(const void *key) { #endif } -// Slimey cheap hash function; no guarenteed performance. +// Slimey cheap hash function; no guaranteed performance. int hashkey(const void *key) { return (int)((intptr_t)key); } diff --git a/hotspot/src/share/vm/adlc/dict2.hpp b/hotspot/src/share/vm/adlc/dict2.hpp index 41a1b19d167..14c75e5df49 100644 --- a/hotspot/src/share/vm/adlc/dict2.hpp +++ b/hotspot/src/share/vm/adlc/dict2.hpp @@ -89,10 +89,10 @@ class Dict { // Dictionary structure // Hashing functions int hashstr(const void *s); // Nice string hash -// Slimey cheap hash function; no guarenteed performance. Better than the +// Slimey cheap hash function; no guaranteed performance. Better than the // default for pointers, especially on MS-DOS machines. int hashptr(const void *key); -// Slimey cheap hash function; no guarenteed performance. +// Slimey cheap hash function; no guaranteed performance. int hashkey(const void *key); // Key comparators diff --git a/hotspot/src/share/vm/adlc/filebuff.cpp b/hotspot/src/share/vm/adlc/filebuff.cpp index 9cccb5d069e..d5dfd218651 100644 --- a/hotspot/src/share/vm/adlc/filebuff.cpp +++ b/hotspot/src/share/vm/adlc/filebuff.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ // FILEBUFF.CPP - Routines for handling a parser file buffer #include "adlc.hpp" +using namespace std; + //------------------------------FileBuff--------------------------------------- // Create a new parsing buffer FileBuff::FileBuff( BufferedFile *fptr, ArchDesc& archDesc) : _fp(fptr), _AD(archDesc) { @@ -48,10 +50,10 @@ FileBuff::FileBuff( BufferedFile *fptr, ArchDesc& archDesc) : _fp(fptr), _AD(arc file_error(SEMERR, 0, "Buffer allocation failed\n"); exit(1); // Exit on allocation failure } - *_bigbuf = '\n'; // Lead with a sentinal newline - _buf = _bigbuf+1; // Skip sentinal + *_bigbuf = '\n'; // Lead with a sentinel newline + _buf = _bigbuf+1; // Skip sentinel _bufmax = _buf; // Buffer is empty - _bufeol = _bigbuf; // _bufeol points at sentinal + _bufeol = _bigbuf; // _bufeol points at sentinel _filepos = -1; // filepos is in sync with _bufeol _bufoff = _offset = 0L; // Offset at file start @@ -60,8 +62,8 @@ FileBuff::FileBuff( BufferedFile *fptr, ArchDesc& archDesc) : _fp(fptr), _AD(arc file_error(SEMERR, 0, "File read error, no input read\n"); exit(1); // Exit on read error } - *_bufmax = '\n'; // End with a sentinal new-line - *(_bufmax+1) = '\0'; // Then end with a sentinal NULL + *_bufmax = '\n'; // End with a sentinel new-line + *(_bufmax+1) = '\0'; // Then end with a sentinel NULL } //------------------------------~FileBuff-------------------------------------- @@ -79,7 +81,7 @@ char *FileBuff::get_line(void) { _linenum++; retval = ++_bufeol; // return character following end of previous line - if (*retval == '\0') return NULL; // Check for EOF sentinal + if (*retval == '\0') return NULL; // Check for EOF sentinel // Search for newline character which must end each line for(_filepos++; *_bufeol != '\n'; _bufeol++) _filepos++; // keep filepos in sync with _bufeol @@ -217,7 +219,7 @@ static int printline( ostream& os, const char *fname, int line, off = expandtab(os,off,*s++,'-','-'); if( i == len ) os << '^'; // Mark end of region os << '\n'; // End of marked line - return 0L; // All done + return 0; // All done } //------------------------------print------------------------------------------ diff --git a/hotspot/src/share/vm/adlc/filebuff.hpp b/hotspot/src/share/vm/adlc/filebuff.hpp index 8f12f9262d9..6967d64a39c 100644 --- a/hotspot/src/share/vm/adlc/filebuff.hpp +++ b/hotspot/src/share/vm/adlc/filebuff.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include using namespace std; + // STRUCTURE FOR HANDLING INPUT AND OUTPUT FILES typedef struct { const char *_name; @@ -36,7 +37,7 @@ class ArchDesc; //------------------------------FileBuff-------------------------------------- // This class defines a nicely behaved buffer of text. Entire file of text -// is read into buffer at creation, with sentinals at start and end. +// is read into buffer at creation, with sentinels at start and end. class FileBuff { friend class FileBuffRegion; private: @@ -45,8 +46,8 @@ class FileBuff { long _bufoff; // Start of buffer file offset char *_buf; // The buffer itself. - char *_bigbuf; // The buffer plus sentinals; actual heap area - char *_bufmax; // A pointer to the buffer end sentinal + char *_bigbuf; // The buffer plus sentinels; actual heap area + char *_bufmax; // A pointer to the buffer end sentinel char *_bufeol; // A pointer to the last complete line end int _err; // Error flag for file seek/read operations @@ -72,7 +73,7 @@ class FileBuff { // This converts a pointer into the buffer to a file offset. It only works // when the pointer is valid (i.e. just obtained from getline()). - int getoff(const char *s) { return _bufoff+(int)(s-_buf); } + long getoff(const char* s) { return _bufoff + (s - _buf); } }; //------------------------------FileBuffRegion--------------------------------- @@ -95,8 +96,6 @@ class FileBuffRegion { FileBuffRegion *copy(); // Deep copy FileBuffRegion *merge(FileBuffRegion*); // Merge 2 regions; delete input -// void print(std::ostream&); -// friend std::ostream& operator<< (std::ostream&, FileBuffRegion&); void print(ostream&); friend ostream& operator<< (ostream&, FileBuffRegion&); }; diff --git a/hotspot/src/share/vm/adlc/forms.cpp b/hotspot/src/share/vm/adlc/forms.cpp index cfcfd0a36d8..fb9f24aa382 100644 --- a/hotspot/src/share/vm/adlc/forms.cpp +++ b/hotspot/src/share/vm/adlc/forms.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,6 +70,7 @@ const char *NameList::iter() { else return (_iter <_cur-1 ? _names[++_iter] : NULL); } const char *NameList::current() { return (_iter < _cur ? _names[_iter] : NULL); } +const char *NameList::peek(int skip) { return (_iter + skip < _cur ? _names[_iter + skip] : NULL); } // Return 'true' if current entry is signal bool NameList::current_is_signal() { @@ -248,11 +249,13 @@ Form::DataType Form::ideal_to_Reg_type(const char *name) const { // True if 'opType', an ideal name, loads or stores. Form::DataType Form::is_load_from_memory(const char *opType) const { if( strcmp(opType,"LoadB")==0 ) return Form::idealB; + if( strcmp(opType,"LoadUB")==0 ) return Form::idealB; if( strcmp(opType,"LoadUS")==0 ) return Form::idealC; if( strcmp(opType,"LoadD")==0 ) return Form::idealD; if( strcmp(opType,"LoadD_unaligned")==0 ) return Form::idealD; if( strcmp(opType,"LoadF")==0 ) return Form::idealF; if( strcmp(opType,"LoadI")==0 ) return Form::idealI; + if( strcmp(opType,"LoadUI2L")==0 ) return Form::idealI; if( strcmp(opType,"LoadKlass")==0 ) return Form::idealP; if( strcmp(opType,"LoadNKlass")==0 ) return Form::idealN; if( strcmp(opType,"LoadL")==0 ) return Form::idealL; @@ -370,7 +373,7 @@ bool FormDict::operator ==(const FormDict &d) const { } // Print out the dictionary contents as key-value pairs -static void dumpkey (const void* key) { fprintf(stdout, "%s", key); } +static void dumpkey (const void* key) { fprintf(stdout, "%s", (char*) key); } static void dumpform(const void* form) { fflush(stdout); ((Form*)form)->dump(); } void FormDict::dump() { diff --git a/hotspot/src/share/vm/adlc/forms.hpp b/hotspot/src/share/vm/adlc/forms.hpp index bf930b8e6da..b1615799508 100644 --- a/hotspot/src/share/vm/adlc/forms.hpp +++ b/hotspot/src/share/vm/adlc/forms.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,7 @@ protected: public: // Public Data Form *_next; // Next pointer for form lists - long _linenum; // Line number for debugging + int _linenum; // Line number for debugging // Dynamic type check for common forms. virtual OpClassForm *is_opclass() const; @@ -342,6 +342,7 @@ public: void reset(); // Reset iteration const char *iter(); // after reset(), first element : else next const char *current(); // return current element in iteration. + const char *peek(int skip = 1); // returns element + skip in iteration if there is one bool current_is_signal(); // Return 'true' if current entry is signal bool is_signal(const char *entry); // Return true if entry is a signal diff --git a/hotspot/src/share/vm/adlc/formsopt.cpp b/hotspot/src/share/vm/adlc/formsopt.cpp index df1f912e9a6..3b601897690 100644 --- a/hotspot/src/share/vm/adlc/formsopt.cpp +++ b/hotspot/src/share/vm/adlc/formsopt.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -273,13 +273,13 @@ int RegClass::regs_in_word( int wordnum, bool stack_also ) { for(_regDefs.reset(); (name = _regDefs.iter()) != NULL;) { int rnum = ((RegDef*)_regDef[name])->register_num(); if( (rnum >> 5) == wordnum ) - word |= (1L<<(rnum&31)); + word |= (1 << (rnum & 31)); } if( stack_also ) { // Now also collect stack bits for( int i = 0; i < 32; i++ ) if( wordnum*32+i >= RegisterForm::_reg_ctr ) - word |= (1L< _max_position ) _max_position = position; - _parent.addName((char *)parent); - _position.addName((char *)position); + _parent.addName((char*) (intptr_t) parent); + _position.addName((char*) (intptr_t) position); _instrs.addName(name); - _input.addName((char *)input); + _input.addName((char*) (intptr_t) input); } // Access info about instructions in the peep-match rule @@ -603,7 +603,7 @@ int PeepMatch::max_position() { return _max_position; } -const char *PeepMatch::instruction_name(intptr_t position) { +const char *PeepMatch::instruction_name(int position) { return _instrs.name(position); } @@ -615,11 +615,11 @@ void PeepMatch::reset() { _input.reset(); } -void PeepMatch::next_instruction( intptr_t &parent, intptr_t &position, const char * &name, intptr_t &input ){ - parent = (intptr_t)_parent.iter(); - position = (intptr_t)_position.iter(); +void PeepMatch::next_instruction(int &parent, int &position, const char* &name, int &input) { + parent = (int) (intptr_t) _parent.iter(); + position = (int) (intptr_t) _position.iter(); name = _instrs.iter(); - input = (intptr_t)_input.iter(); + input = (int) (intptr_t) _input.iter(); } // 'true' if current position in iteration is a placeholder, not matched. @@ -637,15 +637,15 @@ void PeepMatch::output(FILE *fp) { // Write info to output files } //------------------------------PeepConstraint--------------------------------- -PeepConstraint::PeepConstraint(intptr_t left_inst, char *left_op, char *relation, - intptr_t right_inst, char *right_op) +PeepConstraint::PeepConstraint(int left_inst, char* left_op, char* relation, + int right_inst, char* right_op) : _left_inst(left_inst), _left_op(left_op), _relation(relation), _right_inst(right_inst), _right_op(right_op), _next(NULL) {} PeepConstraint::~PeepConstraint() { } // Check if constraints use instruction at position -bool PeepConstraint::constrains_instruction(intptr_t position) { +bool PeepConstraint::constrains_instruction(int position) { // Check local instruction constraints if( _left_inst == position ) return true; if( _right_inst == position ) return true; @@ -692,7 +692,7 @@ void PeepReplace::add_instruction(char *root) { } void PeepReplace::add_operand( int inst_num, char *inst_operand ) { _instruction.add_signal(); - _operand_inst_num.addName((char*)inst_num); + _operand_inst_num.addName((char*) (intptr_t) inst_num); _operand_op_name.addName(inst_operand); } @@ -702,15 +702,15 @@ void PeepReplace::reset() { _operand_inst_num.reset(); _operand_op_name.reset(); } -void PeepReplace::next_instruction(const char * &inst){ +void PeepReplace::next_instruction(const char* &inst){ inst = _instruction.iter(); - intptr_t inst_num = (intptr_t)_operand_inst_num.iter(); - const char *inst_operand = _operand_op_name.iter(); + int inst_num = (int) (intptr_t) _operand_inst_num.iter(); + const char* inst_operand = _operand_op_name.iter(); } -void PeepReplace::next_operand( intptr_t &inst_num, const char * &inst_operand ) { - const char *inst = _instruction.iter(); - inst_num = (intptr_t)_operand_inst_num.iter(); - inst_operand = _operand_op_name.iter(); +void PeepReplace::next_operand(int &inst_num, const char* &inst_operand) { + const char* inst = _instruction.iter(); + inst_num = (int) (intptr_t) _operand_inst_num.iter(); + inst_operand = _operand_op_name.iter(); } diff --git a/hotspot/src/share/vm/adlc/formsopt.hpp b/hotspot/src/share/vm/adlc/formsopt.hpp index 627dc4de035..bb4ba107212 100644 --- a/hotspot/src/share/vm/adlc/formsopt.hpp +++ b/hotspot/src/share/vm/adlc/formsopt.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -457,10 +457,10 @@ public: // Access info about instructions in the peep-match rule int max_position(); - const char *instruction_name(intptr_t position); + const char *instruction_name(int position); // Iterate through all info on matched instructions void reset(); - void next_instruction( intptr_t &parent, intptr_t &position, const char * &name, intptr_t &input ); + void next_instruction(int &parent, int &position, const char* &name, int &input); // 'true' if current position in iteration is a placeholder, not matched. bool is_placeholder(); @@ -474,20 +474,20 @@ private: PeepConstraint *_next; // Additional constraints ANDed together public: - const intptr_t _left_inst; - const char *_left_op; - const char *_relation; - const intptr_t _right_inst; - const char *_right_op; + const int _left_inst; + const char* _left_op; + const char* _relation; + const int _right_inst; + const char* _right_op; public: // Public Methods - PeepConstraint(intptr_t left_inst, char *left_op, char *relation, - intptr_t right_inst, char *right_op); + PeepConstraint(int left_inst, char* left_op, char* relation, + int right_inst, char* right_op); ~PeepConstraint(); // Check if constraints use instruction at position - bool constrains_instruction(intptr_t position); + bool constrains_instruction(int position); // Add another constraint void append(PeepConstraint *next_peep_constraint); @@ -519,7 +519,7 @@ public: // Access contents of peepreplace void reset(); void next_instruction(const char * &root); - void next_operand( intptr_t &inst_num, const char * &inst_operand ); + void next_operand(int &inst_num, const char * &inst_operand ); // Utilities void dump(); diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index c265c1d04c7..1f80e2d0e16 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -574,9 +574,13 @@ bool InstructForm::needs_anti_dependence_check(FormDict &globals) const { // TEMPORARY // if( is_simple_chain_rule(globals) ) return false; - // String-compare uses many memorys edges, but writes none + // String.(compareTo/equals/indexOf) and Arrays.equals use many memorys edges, + // but writes none if( _matrule && _matrule->_rChild && - strcmp(_matrule->_rChild->_opType,"StrComp")==0 ) + ( strcmp(_matrule->_rChild->_opType,"StrComp" )==0 || + strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 || + strcmp(_matrule->_rChild->_opType,"StrIndexOf" )==0 || + strcmp(_matrule->_rChild->_opType,"AryEq" )==0 )) return true; // Check if instruction has a USE of a memory operand class, but no defs @@ -815,8 +819,10 @@ uint InstructForm::oper_input_base(FormDict &globals) { return AdlcVMDeps::Parms; // Skip the machine-state edges if( _matrule->_rChild && - strcmp(_matrule->_rChild->_opType,"StrComp")==0 ) { - // String compare takes 1 control and 4 memory edges. + ( strcmp(_matrule->_rChild->_opType,"StrComp" )==0 || + strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 || + strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 )) { + // String.(compareTo/equals/indexOf) take 1 control and 4 memory edges. return 5; } @@ -844,8 +850,12 @@ void InstructForm::build_components() { for (_parameters.reset(); (name = _parameters.iter()) != NULL;) { OperandForm *opForm = (OperandForm*)_localNames[name]; - const Form *form = _effects[name]; - Effect *e = form ? form->is_effect() : NULL; + Effect* e = NULL; + { + const Form* form = _effects[name]; + e = form ? form->is_effect() : NULL; + } + if (e != NULL) { has_temp |= e->is(Component::TEMP); @@ -858,19 +868,7 @@ void InstructForm::build_components() { OperandForm* kill = (OperandForm*)_localNames[kill_name]; globalAD->syntax_err(_linenum, "%s: %s %s must be at the end of the argument list\n", _ident, kill->_ident, kill_name); - } else if (e->isa(Component::KILL)) { - kill_name = name; - } - - // TEMPs are real uses and need to be among the first parameters - // listed, otherwise the numbering of operands and inputs gets - // screwy, so enforce this restriction during parse. - if (kill_name != NULL && - e->isa(Component::TEMP) && !e->isa(Component::DEF)) { - OperandForm* kill = (OperandForm*)_localNames[kill_name]; - globalAD->syntax_err(_linenum, "%s: %s %s must follow %s %s in the argument list\n", - _ident, kill->_ident, kill_name, opForm->_ident, name); - } else if (e->isa(Component::KILL)) { + } else if (e->isa(Component::KILL) && !e->isa(Component::USE)) { kill_name = name; } } @@ -1122,7 +1120,7 @@ bool InstructForm::cisc_spills_to(ArchDesc &AD, InstructForm *instr) { const char *op_name = NULL; const char *reg_type = NULL; FormDict &globals = AD.globalNames(); - cisc_spill_operand = _matrule->cisc_spill_match(globals, AD.get_registers(), instr->_matrule, op_name, reg_type); + cisc_spill_operand = _matrule->matchrule_cisc_spill_match(globals, AD.get_registers(), instr->_matrule, op_name, reg_type); if( (cisc_spill_operand != Not_cisc_spillable) && (op_name != NULL) && equivalent_predicates(this, instr) ) { cisc_spill_operand = operand_position(op_name, Component::USE); int def_oper = operand_position(op_name, Component::DEF); @@ -1217,13 +1215,17 @@ void InstructForm::rep_var_format(FILE *fp, const char *rep_var) { // Seach through operands to determine parameters unique positions. void InstructForm::set_unique_opnds() { uint* uniq_idx = NULL; - uint nopnds = num_opnds(); + int nopnds = num_opnds(); uint num_uniq = nopnds; - uint i; + int i; + _uniq_idx_length = 0; if ( nopnds > 0 ) { - // Allocate index array with reserve. - uniq_idx = (uint*) malloc(sizeof(uint)*(nopnds + 2)); - for( i = 0; i < nopnds+2; i++ ) { + // Allocate index array. Worst case we're mapping from each + // component back to an index and any DEF always goes at 0 so the + // length of the array has to be the number of components + 1. + _uniq_idx_length = _components.count() + 1; + uniq_idx = (uint*) malloc(sizeof(uint)*(_uniq_idx_length)); + for( i = 0; i < _uniq_idx_length; i++ ) { uniq_idx[i] = i; } } @@ -1238,8 +1240,8 @@ void InstructForm::set_unique_opnds() { _parameters.reset(); while( (name = _parameters.iter()) != NULL ) { count = 0; - uint position = 0; - uint uniq_position = 0; + int position = 0; + int uniq_position = 0; _components.reset(); Component *comp = NULL; if( sets_result() ) { @@ -1255,6 +1257,7 @@ void InstructForm::set_unique_opnds() { } if( strcmp(name, comp->_name)==0 ) { if( ++count > 1 ) { + assert(position < _uniq_idx_length, "out of bounds"); uniq_idx[position] = uniq_position; has_dupl_use = true; } else { @@ -1284,7 +1287,7 @@ void InstructForm::set_unique_opnds() { _num_uniq = num_uniq; } -// Generate index values needed for determing the operand position +// Generate index values needed for determining the operand position void InstructForm::index_temps(FILE *fp, FormDict &globals, const char *prefix, const char *receiver) { uint idx = 0; // position of operand in match rule int cur_num_opnds = num_opnds(); @@ -2200,8 +2203,8 @@ int OperandForm::operand_position(const char *name, int usedef) { // Return zero-based position in component list, only counting constants; // Return -1 if not in list. int OperandForm::constant_position(FormDict &globals, const Component *last) { - // Iterate through components and count constants preceeding 'constant' - uint position = 0; + // Iterate through components and count constants preceding 'constant' + int position = 0; Component *comp; _components.reset(); while( (comp = _components.iter()) != NULL && (comp != last) ) { @@ -2238,7 +2241,7 @@ int OperandForm::constant_position(FormDict &globals, const char *name) { // Return zero-based position in component list, only counting constants; // Return -1 if not in list. int OperandForm::register_position(FormDict &globals, const char *reg_name) { - // Iterate through components and count registers preceeding 'last' + // Iterate through components and count registers preceding 'last' uint position = 0; Component *comp; _components.reset(); @@ -2304,7 +2307,7 @@ void OperandForm::disp_is_oop(FILE *fp, FormDict &globals) { if ( op->is_base_constant(globals) == Form::idealP ) { // Find the constant's index: _c0, _c1, _c2, ... , _cN uint idx = op->constant_position( globals, rep_var); - fprintf(fp," virtual bool disp_is_oop() const {", _ident); + fprintf(fp," virtual bool disp_is_oop() const {"); fprintf(fp, " return _c%d->isa_oop_ptr();", idx); fprintf(fp, " }\n"); } @@ -3042,9 +3045,9 @@ bool MatchNode::find_type(const char *type, int &position) const { // Recursive call collecting info on top-level operands, not transitive. // Implementation does not modify state of internal structures. -void MatchNode::append_components(FormDict &locals, ComponentList &components, - bool deflag) const { - int usedef = deflag ? Component::DEF : Component::USE; +void MatchNode::append_components(FormDict& locals, ComponentList& components, + bool def_flag) const { + int usedef = def_flag ? Component::DEF : Component::USE; FormDict &globals = _AD.globalNames(); assert (_name != NULL, "MatchNode::build_components encountered empty node\n"); @@ -3062,10 +3065,10 @@ void MatchNode::append_components(FormDict &locals, ComponentList &components, return; } // Promote results of "Set" to DEF - bool def_flag = (!strcmp(_opType, "Set")) ? true : false; - if (_lChild) _lChild->append_components(locals, components, def_flag); - def_flag = false; // only applies to component immediately following 'Set' - if (_rChild) _rChild->append_components(locals, components, def_flag); + bool tmpdef_flag = (!strcmp(_opType, "Set")) ? true : false; + if (_lChild) _lChild->append_components(locals, components, tmpdef_flag); + tmpdef_flag = false; // only applies to component immediately following 'Set' + if (_rChild) _rChild->append_components(locals, components, tmpdef_flag); } // Find the n'th base-operand in the match node, @@ -3313,8 +3316,8 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { static const char *needs_ideal_memory_list[] = { "StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" , "StoreB","StoreC","Store" ,"StoreFP", - "LoadI" ,"LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" , - "LoadB" ,"LoadUS" ,"LoadS" ,"Load" , + "LoadI", "LoadUI2L", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" , + "LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" , "Store4I","Store2I","Store2L","Store2D","Store4F","Store2F","Store16B", "Store8B","Store4B","Store8C","Store4C","Store2C", "Load4I" ,"Load2I" ,"Load2L" ,"Load2D" ,"Load4F" ,"Load2F" ,"Load16B" , @@ -3411,9 +3414,9 @@ bool static root_ops_match(FormDict &globals, const char *op1, const char *op2) return (form1 == form2); } -//-------------------------cisc_spill_match------------------------------------ +//-------------------------cisc_spill_match_node------------------------------- // Recursively check two MatchRules for legal conversion via cisc-spilling -int MatchNode::cisc_spill_match(FormDict &globals, RegisterForm *registers, MatchNode *mRule2, const char * &operand, const char * ®_type) { +int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, MatchNode* mRule2, const char* &operand, const char* ®_type) { int cisc_spillable = Maybe_cisc_spillable; int left_spillable = Maybe_cisc_spillable; int right_spillable = Maybe_cisc_spillable; @@ -3434,10 +3437,16 @@ int MatchNode::cisc_spill_match(FormDict &globals, RegisterForm *registers, Mat const InstructForm *form2_inst = form2 ? form2->is_instruction() : NULL; const char *name_left = mRule2->_lChild ? mRule2->_lChild->_opType : NULL; const char *name_right = mRule2->_rChild ? mRule2->_rChild->_opType : NULL; + DataType data_type = Form::none; + if (form->is_operand()) { + // Make sure the loadX matches the type of the reg + data_type = form->ideal_to_Reg_type(form->is_operand()->ideal_type(globals)); + } // Detect reg vs (loadX memory) if( form->is_cisc_reg(globals) && form2_inst - && (is_load_from_memory(mRule2->_opType) != Form::none) // reg vs. (load memory) + && data_type != Form::none + && (is_load_from_memory(mRule2->_opType) == data_type) // reg vs. (load memory) && (name_left != NULL) // NOT (load) && (name_right == NULL) ) { // NOT (load memory foo) const Form *form2_left = name_left ? globals[name_left] : NULL; @@ -3487,13 +3496,13 @@ int MatchNode::cisc_spill_match(FormDict &globals, RegisterForm *registers, Mat return cisc_spillable; } -//---------------------------cisc_spill_match---------------------------------- +//---------------------------cisc_spill_match_rule------------------------------ // Recursively check two MatchRules for legal conversion via cisc-spilling // This method handles the root of Match tree, // general recursive checks done in MatchNode -int MatchRule::cisc_spill_match(FormDict &globals, RegisterForm *registers, - MatchRule *mRule2, const char * &operand, - const char * ®_type) { +int MatchRule::matchrule_cisc_spill_match(FormDict& globals, RegisterForm* registers, + MatchRule* mRule2, const char* &operand, + const char* ®_type) { int cisc_spillable = Maybe_cisc_spillable; int left_spillable = Maybe_cisc_spillable; int right_spillable = Maybe_cisc_spillable; @@ -3531,7 +3540,7 @@ int MatchRule::cisc_spill_match(FormDict &globals, RegisterForm *registers, //----------------------------- equivalent ------------------------------------ // Recursively check to see if two match rules are equivalent. // This rule handles the root. -bool MatchRule::equivalent(FormDict &globals, MatchRule *mRule2) { +bool MatchRule::equivalent(FormDict &globals, MatchNode *mRule2) { // Check that each sets a result if (sets_result() != mRule2->sets_result()) { return false; @@ -3647,7 +3656,7 @@ void MatchNode::swap_commutative_op(bool atroot, int id) { //-------------------------- swap_commutative_op ------------------------------ // Recursively swap specified commutative operation with subtree operands. -void MatchRule::swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt) { +void MatchRule::matchrule_swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt) { assert(match_rules_cnt < 100," too many match rule clones"); // Clone MatchRule* clone = new MatchRule(_AD, this); @@ -3660,8 +3669,8 @@ void MatchRule::swap_commutative_op(const char* instr_ident, int count, int& mat clone->_next = this->_next; this-> _next = clone; if( (--count) > 0 ) { - this-> swap_commutative_op(instr_ident, count, match_rules_cnt); - clone->swap_commutative_op(instr_ident, count, match_rules_cnt); + this-> matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt); + clone->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt); } } @@ -3693,7 +3702,7 @@ MatchRule::~MatchRule() { // Recursive call collecting info on top-level operands, not transitive. // Implementation does not modify state of internal structures. -void MatchRule::append_components(FormDict &locals, ComponentList &components) const { +void MatchRule::append_components(FormDict& locals, ComponentList& components, bool def_flag) const { assert (_name != NULL, "MatchNode::build_components encountered empty node\n"); MatchNode::append_components(locals, components, diff --git a/hotspot/src/share/vm/adlc/formssel.hpp b/hotspot/src/share/vm/adlc/formssel.hpp index a363f16ee41..2a7bfbb7934 100644 --- a/hotspot/src/share/vm/adlc/formssel.hpp +++ b/hotspot/src/share/vm/adlc/formssel.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,6 +101,7 @@ public: const char *_ins_pipe; // Instruction Scheduline description class uint *_uniq_idx; // Indexes of unique operands + int _uniq_idx_length; // Length of _uniq_idx array uint _num_uniq; // Number of unique operands ComponentList _components; // List of Components matches MachNode's // operand structure @@ -257,11 +258,13 @@ public: void set_unique_opnds(); uint num_unique_opnds() { return _num_uniq; } uint unique_opnds_idx(int idx) { - if( _uniq_idx != NULL && idx > 0 ) + if( _uniq_idx != NULL && idx > 0 ) { + assert(idx < _uniq_idx_length, "out of bounds"); return _uniq_idx[idx]; - else + } else { return idx; - } + } + } // Operands which are only KILLs aren't part of the input array and // require special handling in some cases. Their position in this @@ -274,7 +277,7 @@ public: // // Generate the format call for the replacement variable void rep_var_format(FILE *fp, const char *rep_var); - // Generate index values needed for determing the operand position + // Generate index values needed for determining the operand position void index_temps (FILE *fp, FormDict &globals, const char *prefix = "", const char *receiver = ""); // --------------------------- @@ -341,7 +344,7 @@ public: // --------------------------- Code Block // Add code - void add_code(const char *string_preceeding_replacement_var); + void add_code(const char *string_preceding_replacement_var); // Add a replacement variable or one of its subfields // Subfields are stored with a leading '$' void add_rep_var(char *replacement_var); @@ -917,8 +920,8 @@ public: // return 1 if found and position is incremented by operand offset in rule bool find_name(const char *str, int &position) const; bool find_type(const char *str, int &position) const; - void append_components(FormDict &locals, ComponentList &components, - bool def_flag) const; + virtual void append_components(FormDict& locals, ComponentList& components, + bool def_flag = false) const; bool base_operand(uint &position, FormDict &globals, const char * &result, const char * &name, const char * &opType) const; @@ -944,12 +947,12 @@ public: const char *reduce_left (FormDict &globals) const; // Recursive version of check in MatchRule - int cisc_spill_match(FormDict &globals, RegisterForm *registers, - MatchNode *mRule2, const char * &operand, - const char * ®_type); + int cisc_spill_match(FormDict& globals, RegisterForm* registers, + MatchNode* mRule2, const char* &operand, + const char* ®_type); int cisc_spill_merge(int left_result, int right_result); - bool equivalent(FormDict &globals, MatchNode *mNode2); + virtual bool equivalent(FormDict& globals, MatchNode* mNode2); void count_commutative_op(int& count); void swap_commutative_op(bool atroot, int count); @@ -976,7 +979,7 @@ public: MatchRule(ArchDesc &ad, MatchNode* mroot, int depth, char* construct, int numleaves); ~MatchRule(); - void append_components(FormDict &locals, ComponentList &components) const; + virtual void append_components(FormDict& locals, ComponentList& components, bool def_flag = false) const; // Recursive call on all operands' match rules in my match rule. bool base_operand(uint &position, FormDict &globals, const char * &result, const char * &name, @@ -1003,14 +1006,14 @@ public: Form::DataType is_ideal_store() const;// node matches ideal 'StoreXNode' // Check if 'mRule2' is a cisc-spill variant of this MatchRule - int cisc_spill_match(FormDict &globals, RegisterForm *registers, - MatchRule *mRule2, const char * &operand, - const char * ®_type); + int matchrule_cisc_spill_match(FormDict &globals, RegisterForm* registers, + MatchRule* mRule2, const char* &operand, + const char* ®_type); // Check if 'mRule2' is equivalent to this MatchRule - bool equivalent(FormDict &globals, MatchRule *mRule2); + virtual bool equivalent(FormDict& globals, MatchNode* mRule2); - void swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt); + void matchrule_swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt); void dump(); void output(FILE *fp); diff --git a/hotspot/src/share/vm/adlc/main.cpp b/hotspot/src/share/vm/adlc/main.cpp index c5b405d0208..7fb780935a3 100644 --- a/hotspot/src/share/vm/adlc/main.cpp +++ b/hotspot/src/share/vm/adlc/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -349,7 +349,7 @@ void ArchDesc::close_files(int delete_out) } else { if (_ADL_file._name) printf("%s --> ", _ADL_file._name); - printf("%s, %s, %s, %s, %s, %s, %s, %s, %s", + printf("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s", _CPP_file._name, _CPP_CLONE_file._name, _CPP_EXPAND_file._name, @@ -358,7 +358,8 @@ void ArchDesc::close_files(int delete_out) _CPP_MISC_file._name, _CPP_PEEPHOLE_file._name, _CPP_PIPELINE_file._name, - _HPP_file._name, _DFA_file._name); + _HPP_file._name, + _DFA_file._name); } printf("\n"); } @@ -431,7 +432,7 @@ int get_legal_text(FileBuff &fbuf, char **legal_text) legal_end = fbuf.get_line(); } *legal_text = legal_start; - return (legal_end - legal_start); + return (int) (legal_end - legal_start); } // VS2005 has its own definition, identical to this one. diff --git a/hotspot/src/share/vm/adlc/output_c.cpp b/hotspot/src/share/vm/adlc/output_c.cpp index dbc287b1d1a..0ae759cc3e2 100644 --- a/hotspot/src/share/vm/adlc/output_c.cpp +++ b/hotspot/src/share/vm/adlc/output_c.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,11 +225,11 @@ static int pipeline_reads_initializer(FILE *fp_cpp, NameList &pipeline_reads, Pi pipeclass->_parameters.reset(); while ( (paramname = pipeclass->_parameters.iter()) != NULL ) { - const PipeClassOperandForm *pipeopnd = + const PipeClassOperandForm *tmppipeopnd = (const PipeClassOperandForm *)pipeclass->_localUsage[paramname]; - if (pipeopnd) - templen += 10 + (int)strlen(pipeopnd->_stage); + if (tmppipeopnd) + templen += 10 + (int)strlen(tmppipeopnd->_stage); else templen += 19; @@ -253,10 +253,10 @@ static int pipeline_reads_initializer(FILE *fp_cpp, NameList &pipeline_reads, Pi pipeclass->_parameters.reset(); while ( (paramname = pipeclass->_parameters.iter()) != NULL ) { - const PipeClassOperandForm *pipeopnd = + const PipeClassOperandForm *tmppipeopnd = (const PipeClassOperandForm *)pipeclass->_localUsage[paramname]; templen += sprintf(&operand_stages[templen], " stage_%s%c\n", - pipeopnd ? pipeopnd->_stage : "undefined", + tmppipeopnd ? tmppipeopnd->_stage : "undefined", (++i < paramcount ? ',' : ' ') ); } @@ -1042,10 +1042,10 @@ static void defineOut_RegMask(FILE *fp, const char *node, const char *regMask) { // Scan the peepmatch and output a test for each instruction static void check_peepmatch_instruction_tree(FILE *fp, PeepMatch *pmatch, PeepConstraint *pconstraint) { - intptr_t parent = -1; - intptr_t inst_position = 0; - const char *inst_name = NULL; - intptr_t input = 0; + int parent = -1; + int inst_position = 0; + const char* inst_name = NULL; + int input = 0; fprintf(fp, " // Check instruction sub-tree\n"); pmatch->reset(); for( pmatch->next_instruction( parent, inst_position, inst_name, input ); @@ -1055,14 +1055,14 @@ static void check_peepmatch_instruction_tree(FILE *fp, PeepMatch *pmatch, PeepCo if( ! pmatch->is_placeholder() ) { // Define temporaries 'inst#', based on parent and parent's input index if( parent != -1 ) { // root was initialized - fprintf(fp, " inst%ld = inst%ld->in(%ld);\n", + fprintf(fp, " inst%d = inst%d->in(%d);\n", inst_position, parent, input); } // When not the root // Test we have the correct instruction by comparing the rule if( parent != -1 ) { - fprintf(fp, " matches = matches && ( inst%ld->rule() == %s_rule );", + fprintf(fp, " matches = matches && ( inst%d->rule() == %s_rule );", inst_position, inst_name); } } else { @@ -1073,20 +1073,20 @@ static void check_peepmatch_instruction_tree(FILE *fp, PeepMatch *pmatch, PeepCo } } -static void print_block_index(FILE *fp, intptr_t inst_position) { +static void print_block_index(FILE *fp, int inst_position) { assert( inst_position >= 0, "Instruction number less than zero"); fprintf(fp, "block_index"); if( inst_position != 0 ) { - fprintf(fp, " - %ld", inst_position); + fprintf(fp, " - %d", inst_position); } } // Scan the peepmatch and output a test for each instruction static void check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, PeepConstraint *pconstraint) { - intptr_t parent = -1; - intptr_t inst_position = 0; - const char *inst_name = NULL; - intptr_t input = 0; + int parent = -1; + int inst_position = 0; + const char* inst_name = NULL; + int input = 0; fprintf(fp, " // Check instruction sub-tree\n"); pmatch->reset(); for( pmatch->next_instruction( parent, inst_position, inst_name, input ); @@ -1101,14 +1101,14 @@ static void check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, Pe print_block_index(fp, inst_position); fprintf(fp, " > 0 ) {\n Node *n = block->_nodes.at("); print_block_index(fp, inst_position); - fprintf(fp, ");\n inst%ld = (n->is_Mach()) ? ", inst_position); + fprintf(fp, ");\n inst%d = (n->is_Mach()) ? ", inst_position); fprintf(fp, "n->as_Mach() : NULL;\n }\n"); } // When not the root // Test we have the correct instruction by comparing the rule. if( parent != -1 ) { - fprintf(fp, " matches = matches && (inst%ld != NULL) && (inst%ld->rule() == %s_rule);\n", + fprintf(fp, " matches = matches && (inst%d != NULL) && (inst%d->rule() == %s_rule);\n", inst_position, inst_position, inst_name); } } else { @@ -1121,10 +1121,10 @@ static void check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, Pe // Build mapping for register indices, num_edges to input static void build_instruction_index_mapping( FILE *fp, FormDict &globals, PeepMatch *pmatch ) { - intptr_t parent = -1; - intptr_t inst_position = 0; - const char *inst_name = NULL; - intptr_t input = 0; + int parent = -1; + int inst_position = 0; + const char* inst_name = NULL; + int input = 0; fprintf(fp, " // Build map to register info\n"); pmatch->reset(); for( pmatch->next_instruction( parent, inst_position, inst_name, input ); @@ -1136,9 +1136,9 @@ static void build_instruction_index_mapping( FILE *fp, FormDict &globals, PeepMa InstructForm *inst = globals[inst_name]->is_instruction(); if( inst != NULL ) { char inst_prefix[] = "instXXXX_"; - sprintf(inst_prefix, "inst%ld_", inst_position); + sprintf(inst_prefix, "inst%d_", inst_position); char receiver[] = "instXXXX->"; - sprintf(receiver, "inst%ld->", inst_position); + sprintf(receiver, "inst%d->", inst_position); inst->index_temps( fp, globals, inst_prefix, receiver ); } } @@ -1168,7 +1168,7 @@ static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch } // LEFT - intptr_t left_index = pconstraint->_left_inst; + int left_index = pconstraint->_left_inst; const char *left_op = pconstraint->_left_op; // Access info on the instructions whose operands are compared InstructForm *inst_left = globals[pmatch->instruction_name(left_index)]->is_instruction(); @@ -1191,7 +1191,7 @@ static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch // RIGHT int right_op_index = -1; - intptr_t right_index = pconstraint->_right_inst; + int right_index = pconstraint->_right_inst; const char *right_op = pconstraint->_right_op; if( right_index != -1 ) { // Match operand // Access info on the instructions whose operands are compared @@ -1351,7 +1351,7 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch assert( root_form != NULL, "Replacement instruction was not previously defined"); fprintf(fp, " %sNode *root = new (C) %sNode();\n", root_inst, root_inst); - intptr_t inst_num; + int inst_num; const char *op_name; int opnds_index = 0; // define result operand // Then install the use-operands for the new sub-tree @@ -1362,7 +1362,6 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch InstructForm *inst_form; inst_form = globals[pmatch->instruction_name(inst_num)]->is_instruction(); assert( inst_form, "Parser should guaranty this is an instruction"); - int op_base = inst_form->oper_input_base(globals); int inst_op_num = inst_form->operand_position(op_name, Component::USE); if( inst_op_num == NameList::Not_in_list ) inst_op_num = inst_form->operand_position(op_name, Component::USE_DEF); @@ -1379,32 +1378,32 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch // Add unmatched edges from root of match tree int op_base = root_form->oper_input_base(globals); for( int unmatched_edge = 1; unmatched_edge < op_base; ++unmatched_edge ) { - fprintf(fp, " root->add_req(inst%ld->in(%d)); // unmatched ideal edge\n", + fprintf(fp, " root->add_req(inst%d->in(%d)); // unmatched ideal edge\n", inst_num, unmatched_edge); } // If new instruction captures bottom type if( root_form->captures_bottom_type() ) { // Get bottom type from instruction whose result we are replacing - fprintf(fp, " root->_bottom_type = inst%ld->bottom_type();\n", inst_num); + fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num); } // Define result register and result operand - fprintf(fp, " ra_->add_reference(root, inst%ld);\n", inst_num); - fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%ld));\n", inst_num); - fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%ld), ra_->get_reg_first(inst%ld));\n", inst_num, inst_num); - fprintf(fp, " root->_opnds[0] = inst%ld->_opnds[0]->clone(C); // result\n", inst_num); + fprintf(fp, " ra_->add_reference(root, inst%d);\n", inst_num); + fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%d));\n", inst_num); + fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%d), ra_->get_reg_first(inst%d));\n", inst_num, inst_num); + fprintf(fp, " root->_opnds[0] = inst%d->_opnds[0]->clone(C); // result\n", inst_num); fprintf(fp, " // ----- Done with initial setup -----\n"); } else { if( (op_form == NULL) || (op_form->is_base_constant(globals) == Form::none) ) { // Do not have ideal edges for constants after matching - fprintf(fp, " for( unsigned x%d = inst%ld_idx%d; x%d < inst%ld_idx%d; x%d++ )\n", + fprintf(fp, " for( unsigned x%d = inst%d_idx%d; x%d < inst%d_idx%d; x%d++ )\n", inst_op_num, inst_num, inst_op_num, inst_op_num, inst_num, inst_op_num+1, inst_op_num ); - fprintf(fp, " root->add_req( inst%ld->in(x%d) );\n", + fprintf(fp, " root->add_req( inst%d->in(x%d) );\n", inst_num, inst_op_num ); } else { fprintf(fp, " // no ideal edge for constants after matching\n"); } - fprintf(fp, " root->_opnds[%d] = inst%ld->_opnds[%d]->clone(C);\n", + fprintf(fp, " root->_opnds[%d] = inst%d->_opnds[%d]->clone(C);\n", opnds_index, inst_num, inst_op_num ); } ++opnds_index; @@ -1443,7 +1442,7 @@ void ArchDesc::definePeephole(FILE *fp, InstructForm *node) { } for( int i = 0; i <= max_position; ++i ) { if( i == 0 ) { - fprintf(fp, " MachNode *inst0 = this;\n", i); + fprintf(fp, " MachNode *inst0 = this;\n"); } else { fprintf(fp, " MachNode *inst%d = NULL;\n", i); } @@ -1743,7 +1742,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { } // delete the rest of edges fprintf(fp," for(int i = idx%d - 1; i >= (int)idx%d; i--) {\n", cur_num_opnds, new_num_opnds); - fprintf(fp," del_req(i);\n", i); + fprintf(fp," del_req(i);\n"); fprintf(fp," }\n"); fprintf(fp," _num_opnds = %d;\n", new_num_opnds); } @@ -1817,7 +1816,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { fprintf(fp,"\n"); if( node->expands() ) { - fprintf(fp," return result;\n",cnt-1); + fprintf(fp," return result;\n"); } else { fprintf(fp," return this;\n"); } @@ -2140,8 +2139,59 @@ public: // A subfield variable, '$$' prefix emit_field( rep_var ); } else { - // A replacement variable, '$' prefix - emit_rep_var( rep_var ); + if (_strings_to_emit.peek() != NULL && + strcmp(_strings_to_emit.peek(), "$Address") == 0) { + fprintf(_fp, "Address::make_raw("); + + emit_rep_var( rep_var ); + fprintf(_fp,"->base(ra_,this,idx%d), ", _operand_idx); + + _reg_status = LITERAL_ACCESSED; + emit_rep_var( rep_var ); + fprintf(_fp,"->index(ra_,this,idx%d), ", _operand_idx); + + _reg_status = LITERAL_ACCESSED; + emit_rep_var( rep_var ); + fprintf(_fp,"->scale(), "); + + _reg_status = LITERAL_ACCESSED; + emit_rep_var( rep_var ); + Form::DataType stack_type = _operand ? _operand->is_user_name_for_sReg() : Form::none; + if( _operand && _operand_idx==0 && stack_type != Form::none ) { + fprintf(_fp,"->disp(ra_,this,0), "); + } else { + fprintf(_fp,"->disp(ra_,this,idx%d), ", _operand_idx); + } + + _reg_status = LITERAL_ACCESSED; + emit_rep_var( rep_var ); + fprintf(_fp,"->disp_is_oop())"); + + // skip trailing $Address + _strings_to_emit.iter(); + } else { + // A replacement variable, '$' prefix + const char* next = _strings_to_emit.peek(); + const char* next2 = _strings_to_emit.peek(2); + if (next != NULL && next2 != NULL && strcmp(next2, "$Register") == 0 && + (strcmp(next, "$base") == 0 || strcmp(next, "$index") == 0)) { + // handle $rev_var$$base$$Register and $rev_var$$index$$Register by + // producing as_Register(opnd_array(#)->base(ra_,this,idx1)). + fprintf(_fp, "as_Register("); + // emit the operand reference + emit_rep_var( rep_var ); + rep_var = _strings_to_emit.iter(); + assert(strcmp(rep_var, "$base") == 0 || strcmp(rep_var, "$index") == 0, "bad pattern"); + // handle base or index + emit_field(rep_var); + rep_var = _strings_to_emit.iter(); + assert(strcmp(rep_var, "$Register") == 0, "bad pattern"); + // close up the parens + fprintf(_fp, ")"); + } else { + emit_rep_var( rep_var ); + } + } } // end replacement and/or subfield } } diff --git a/hotspot/src/share/vm/adlc/output_h.cpp b/hotspot/src/share/vm/adlc/output_h.cpp index d2fd489abe9..4668d68f9fa 100644 --- a/hotspot/src/share/vm/adlc/output_h.cpp +++ b/hotspot/src/share/vm/adlc/output_h.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -574,7 +574,7 @@ void gen_inst_format(FILE *fp, FormDict &globals, InstructForm &inst, bool for_c // Generate the user-defined portion of the format if( inst._format ) { // If there are replacement variables, - // Generate index values needed for determing the operand position + // Generate index values needed for determining the operand position if( inst._format->_rep_vars.count() ) inst.index_temps(fp, globals); @@ -1832,7 +1832,7 @@ void ArchDesc::declareClasses(FILE *fp) { break; case Form::idealP: case Form::idealN: - fprintf(fp," return opnd_array(1)->type();\n",result); + fprintf(fp," return opnd_array(1)->type();\n"); break; case Form::idealD: fprintf(fp," return TypeD::make(opnd_array(1)->constantD());\n"); diff --git a/hotspot/src/share/vm/asm/assembler.cpp b/hotspot/src/share/vm/asm/assembler.cpp index e9d99621b6b..e41fc7e9d31 100644 --- a/hotspot/src/share/vm/asm/assembler.cpp +++ b/hotspot/src/share/vm/asm/assembler.cpp @@ -31,7 +31,7 @@ // The AbstractAssembler is generating code into a CodeBuffer. To make code generation faster, // the assembler keeps a copy of the code buffers boundaries & modifies them when // emitting bytes rather than using the code buffers accessor functions all the time. -// The code buffer is updated via set_code_end(...) after emiting a whole instruction. +// The code buffer is updated via set_code_end(...) after emitting a whole instruction. AbstractAssembler::AbstractAssembler(CodeBuffer* code) { if (code == NULL) return; @@ -239,6 +239,78 @@ void Label::patch_instructions(MacroAssembler* masm) { } } +struct DelayedConstant { + typedef void (*value_fn_t)(); + BasicType type; + intptr_t value; + value_fn_t value_fn; + // This limit of 20 is generous for initial uses. + // The limit needs to be large enough to store the field offsets + // into classes which do not have statically fixed layouts. + // (Initial use is for method handle object offsets.) + // Look for uses of "delayed_value" in the source code + // and make sure this number is generous enough to handle all of them. + enum { DC_LIMIT = 20 }; + static DelayedConstant delayed_constants[DC_LIMIT]; + static DelayedConstant* add(BasicType type, value_fn_t value_fn); + bool match(BasicType t, value_fn_t cfn) { + return type == t && value_fn == cfn; + } + static void update_all(); +}; + +DelayedConstant DelayedConstant::delayed_constants[DC_LIMIT]; +// Default C structure initialization rules have the following effect here: +// = { { (BasicType)0, (intptr_t)NULL }, ... }; + +DelayedConstant* DelayedConstant::add(BasicType type, + DelayedConstant::value_fn_t cfn) { + for (int i = 0; i < DC_LIMIT; i++) { + DelayedConstant* dcon = &delayed_constants[i]; + if (dcon->match(type, cfn)) + return dcon; + if (dcon->value_fn == NULL) { + // (cmpxchg not because this is multi-threaded but because I'm paranoid) + if (Atomic::cmpxchg_ptr(CAST_FROM_FN_PTR(void*, cfn), &dcon->value_fn, NULL) == NULL) { + dcon->type = type; + return dcon; + } + } + } + // If this assert is hit (in pre-integration testing!) then re-evaluate + // the comment on the definition of DC_LIMIT. + guarantee(false, "too many delayed constants"); + return NULL; +} + +void DelayedConstant::update_all() { + for (int i = 0; i < DC_LIMIT; i++) { + DelayedConstant* dcon = &delayed_constants[i]; + if (dcon->value_fn != NULL && dcon->value == 0) { + typedef int (*int_fn_t)(); + typedef address (*address_fn_t)(); + switch (dcon->type) { + case T_INT: dcon->value = (intptr_t) ((int_fn_t) dcon->value_fn)(); break; + case T_ADDRESS: dcon->value = (intptr_t) ((address_fn_t)dcon->value_fn)(); break; + } + } + } +} + +intptr_t* AbstractAssembler::delayed_value_addr(int(*value_fn)()) { + DelayedConstant* dcon = DelayedConstant::add(T_INT, (DelayedConstant::value_fn_t) value_fn); + return &dcon->value; +} +intptr_t* AbstractAssembler::delayed_value_addr(address(*value_fn)()) { + DelayedConstant* dcon = DelayedConstant::add(T_ADDRESS, (DelayedConstant::value_fn_t) value_fn); + return &dcon->value; +} +void AbstractAssembler::update_delayed_values() { + DelayedConstant::update_all(); +} + + + void AbstractAssembler::block_comment(const char* comment) { if (sect() == CodeBuffer::SECT_INSTS) { @@ -249,16 +321,19 @@ void AbstractAssembler::block_comment(const char* comment) { bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { // Exception handler checks the nmethod's implicit null checks table // only when this method returns false. - if (UseCompressedOops) { +#ifdef _LP64 + if (UseCompressedOops && Universe::narrow_oop_base() != NULL) { + assert (Universe::heap() != NULL, "java heap should be initialized"); // The first page after heap_base is unmapped and // the 'offset' is equal to [heap_base + offset] for // narrow oop implicit null checks. - uintptr_t heap_base = (uintptr_t)Universe::heap_base(); - if ((uintptr_t)offset >= heap_base) { + uintptr_t base = (uintptr_t)Universe::narrow_oop_base(); + if ((uintptr_t)offset >= base) { // Normalize offset for the next check. - offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1)); + offset = (intptr_t)(pointer_delta((void*)offset, (void*)base, 1)); } } +#endif return offset < 0 || os::vm_page_size() <= offset; } diff --git a/hotspot/src/share/vm/asm/assembler.hpp b/hotspot/src/share/vm/asm/assembler.hpp index 7af6e5dffa1..8027e4e1322 100644 --- a/hotspot/src/share/vm/asm/assembler.hpp +++ b/hotspot/src/share/vm/asm/assembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ * */ -// This file contains platform-independant assembler declarations. +// This file contains platform-independent assembler declarations. class CodeBuffer; class MacroAssembler; @@ -140,6 +140,28 @@ class Label VALUE_OBJ_CLASS_SPEC { } }; +// A union type for code which has to assemble both constant and +// non-constant operands, when the distinction cannot be made +// statically. +class RegisterOrConstant VALUE_OBJ_CLASS_SPEC { + private: + Register _r; + intptr_t _c; + + public: + RegisterOrConstant(): _r(noreg), _c(0) {} + RegisterOrConstant(Register r): _r(r), _c(0) {} + RegisterOrConstant(intptr_t c): _r(noreg), _c(c) {} + + Register as_register() const { assert(is_register(),""); return _r; } + intptr_t as_constant() const { assert(is_constant(),""); return _c; } + + Register register_or_noreg() const { return _r; } + intptr_t constant_or_zero() const { return _c; } + + bool is_register() const { return _r != noreg; } + bool is_constant() const { return _r == noreg; } +}; // The Abstract Assembler: Pure assembler doing NO optimizations on the // instruction level; i.e., what you write is what you get. @@ -280,6 +302,26 @@ class AbstractAssembler : public ResourceObj { inline address address_constant(Label& L); inline address address_table_constant(GrowableArray label); + // Bootstrapping aid to cope with delayed determination of constants. + // Returns a static address which will eventually contain the constant. + // The value zero (NULL) stands instead of a constant which is still uncomputed. + // Thus, the eventual value of the constant must not be zero. + // This is fine, since this is designed for embedding object field + // offsets in code which must be generated before the object class is loaded. + // Field offsets are never zero, since an object's header (mark word) + // is located at offset zero. + RegisterOrConstant delayed_value(int(*value_fn)(), Register tmp, int offset = 0) { + return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset); + } + RegisterOrConstant delayed_value(address(*value_fn)(), Register tmp, int offset = 0) { + return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset); + } + virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset) = 0; + // Last overloading is platform-dependent; look in assembler_.cpp. + static intptr_t* delayed_value_addr(int(*constant_fn)()); + static intptr_t* delayed_value_addr(address(*constant_fn)()); + static void update_delayed_values(); + // Bang stack to trigger StackOverflowError at a safe location // implementation delegates to machine-specific bang_stack_with_offset void generate_stack_overflow_check( int frame_size_in_bytes ); diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index 7ae4a13232a..3aa6036aff2 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 9b718a3d28f..12357678191 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/c1/c1_Optimizer.cpp b/hotspot/src/share/vm/c1/c1_Optimizer.cpp index 1b9f77aeef2..ca6c6f7f2ce 100644 --- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index dcd0f282ab9..986cfd28561 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp index 4f7e52559e6..934cca6d99d 100644 --- a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp +++ b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp @@ -284,6 +284,11 @@ ciMethodBlocks::ciMethodBlocks(Arena *arena, ciMethod *meth): _method(meth), // int ex_start = handler->start(); int ex_end = handler->limit(); + // ensure a block at the start of exception range and start of following code + (void) make_block_at(ex_start); + if (ex_end < _code_size) + (void) make_block_at(ex_end); + if (eb->is_handler()) { // Extend old handler exception range to cover additional range. int old_ex_start = eb->ex_start_bci(); @@ -295,10 +300,6 @@ ciMethodBlocks::ciMethodBlocks(Arena *arena, ciMethod *meth): _method(meth), eb->clear_exception_handler(); // Reset exception information } eb->set_exception_range(ex_start, ex_end); - // ensure a block at the start of exception range and start of following code - (void) make_block_at(ex_start); - if (ex_end < _code_size) - (void) make_block_at(ex_end); } } diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.cpp b/hotspot/src/share/vm/ci/ciTypeFlow.cpp index 08396235067..9bf831ef9f3 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp @@ -541,7 +541,7 @@ void ciTypeFlow::StateVector::do_aaload(ciBytecodeStream* str) { // is report a value that will meet correctly with any downstream // reference types on paths that will truly be executed. This null type // meets with any reference type to yield that same reference type. - // (The compiler will generate an unconditonal exception here.) + // (The compiler will generate an unconditional exception here.) push(null_type()); return; } @@ -2237,7 +2237,6 @@ ciTypeFlow::Block* ciTypeFlow::clone_loop_head(Loop* lp, StateVector* temp_vecto for (SuccIter iter(tail); !iter.done(); iter.next()) { if (iter.succ() == head) { iter.set_succ(clone); - break; } } flow_block(tail, temp_vector, temp_set); diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 4f8ec88f866..119b95adf46 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2747,9 +2747,10 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, super_klass(), methods(), access_flags, - class_loader(), - class_name(), - local_interfaces()); + class_loader, + class_name, + local_interfaces(), + CHECK_(nullHandle)); // Size of Java itable (in words) itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces); @@ -3229,7 +3230,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, // print out the superclass. const char * from = Klass::cast(this_klass())->external_name(); if (this_klass->java_super() != NULL) { - tty->print("RESOLVE %s %s\n", from, instanceKlass::cast(this_klass->java_super())->external_name()); + tty->print("RESOLVE %s %s (super)\n", from, instanceKlass::cast(this_klass->java_super())->external_name()); } // print out each of the interface classes referred to by this class. objArrayHandle local_interfaces(THREAD, this_klass->local_interfaces()); @@ -3239,7 +3240,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, klassOop k = klassOop(local_interfaces->obj_at(i)); instanceKlass* to_class = instanceKlass::cast(k); const char * to = to_class->external_name(); - tty->print("RESOLVE %s %s\n", from, to); + tty->print("RESOLVE %s %s (interface)\n", from, to); } } } diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 385e6a16e7f..cb6b41f3bb9 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,22 +239,20 @@ symbolHandle java_lang_String::as_symbol(Handle java_string, TRAPS) { typeArrayOop value = java_lang_String::value(obj); int offset = java_lang_String::offset(obj); int length = java_lang_String::length(obj); - - ResourceMark rm(THREAD); - symbolHandle result; - - if (length > 0) { - int utf8_length = UNICODE::utf8_length(value->char_at_addr(offset), length); - char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1); - UNICODE::convert_to_utf8(value->char_at_addr(offset), length, chars); - // Allocate the symbol - result = oopFactory::new_symbol_handle(chars, utf8_length, CHECK_(symbolHandle())); - } else { - result = oopFactory::new_symbol_handle("", 0, CHECK_(symbolHandle())); - } - return result; + jchar* base = value->char_at_addr(offset); + symbolOop sym = SymbolTable::lookup_unicode(base, length, THREAD); + return symbolHandle(THREAD, sym); } +symbolOop java_lang_String::as_symbol_or_null(oop java_string) { + typeArrayOop value = java_lang_String::value(java_string); + int offset = java_lang_String::offset(java_string); + int length = java_lang_String::length(java_string); + jchar* base = value->char_at_addr(offset); + return SymbolTable::probe_unicode(base, length); +} + + int java_lang_String::utf8_length(oop java_string) { typeArrayOop value = java_lang_String::value(java_string); int offset = java_lang_String::offset(java_string); @@ -385,6 +383,48 @@ klassOop java_lang_Class::as_klassOop(oop java_class) { } +void java_lang_Class::print_signature(oop java_class, outputStream* st) { + assert(java_lang_Class::is_instance(java_class), "must be a Class object"); + symbolOop name = NULL; + bool is_instance = false; + if (is_primitive(java_class)) { + name = vmSymbols::type_signature(primitive_type(java_class)); + } else { + klassOop k = as_klassOop(java_class); + is_instance = Klass::cast(k)->oop_is_instance(); + name = Klass::cast(k)->name(); + } + if (name == NULL) { + st->print(""); + return; + } + if (is_instance) st->print("L"); + st->write((char*) name->base(), (int) name->utf8_length()); + if (is_instance) st->print(";"); +} + +symbolOop java_lang_Class::as_signature(oop java_class, bool intern_if_not_found, TRAPS) { + assert(java_lang_Class::is_instance(java_class), "must be a Class object"); + symbolOop name = NULL; + if (is_primitive(java_class)) { + return vmSymbols::type_signature(primitive_type(java_class)); + } else { + klassOop k = as_klassOop(java_class); + if (!Klass::cast(k)->oop_is_instance()) { + return Klass::cast(k)->name(); + } else { + ResourceMark rm; + const char* sigstr = Klass::cast(k)->signature_name(); + int siglen = (int) strlen(sigstr); + if (!intern_if_not_found) + return SymbolTable::probe(sigstr, siglen); + else + return oopFactory::new_symbol(sigstr, siglen, THREAD); + } + } +} + + klassOop java_lang_Class::array_klass(oop java_class) { klassOop k = klassOop(java_class->obj_field(array_klass_offset)); assert(k == NULL || k->is_klass() && Klass::cast(k)->oop_is_javaArray(), "should be array klass"); @@ -412,6 +452,8 @@ void java_lang_Class::set_resolved_constructor(oop java_class, methodOop constru bool java_lang_Class::is_primitive(oop java_class) { + // should assert: + //assert(java_lang_Class::is_instance(java_class), "must be a Class object"); klassOop k = klassOop(java_class->obj_field(klass_offset)); return k == NULL; } @@ -431,6 +473,19 @@ BasicType java_lang_Class::primitive_type(oop java_class) { return type; } +BasicType java_lang_Class::as_BasicType(oop java_class, klassOop* reference_klass) { + assert(java_lang_Class::is_instance(java_class), "must be a Class object"); + if (is_primitive(java_class)) { + if (reference_klass != NULL) + (*reference_klass) = NULL; + return primitive_type(java_class); + } else { + if (reference_klass != NULL) + (*reference_klass) = as_klassOop(java_class); + return T_OBJECT; + } +} + oop java_lang_Class::primitive_mirror(BasicType t) { oop mirror = Universe::java_mirror(t); @@ -1988,6 +2043,21 @@ BasicType java_lang_boxing_object::set_value(oop box, jvalue* value) { } +void java_lang_boxing_object::print(BasicType type, jvalue* value, outputStream* st) { + switch (type) { + case T_BOOLEAN: st->print("%s", value->z ? "true" : "false"); break; + case T_CHAR: st->print("%d", value->c); break; + case T_BYTE: st->print("%d", value->b); break; + case T_SHORT: st->print("%d", value->s); break; + case T_INT: st->print("%d", value->i); break; + case T_LONG: st->print(INT64_FORMAT, value->j); break; + case T_FLOAT: st->print("%f", value->f); break; + case T_DOUBLE: st->print("%lf", value->d); break; + default: st->print("type %d?", type); break; + } +} + + // Support for java_lang_ref_Reference oop java_lang_ref_Reference::pending_list_lock() { instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass()); diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 612a0013562..3ae5b5337f8 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,6 +107,7 @@ class java_lang_String : AllStatic { // Conversion static symbolHandle as_symbol(Handle java_string, TRAPS); + static symbolOop as_symbol_or_null(oop java_string); // Testers static bool is_instance(oop obj) { @@ -149,6 +150,9 @@ class java_lang_Class : AllStatic { static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS); // Conversion static klassOop as_klassOop(oop java_class); + static BasicType as_BasicType(oop java_class, klassOop* reference_klass = NULL); + static symbolOop as_signature(oop java_class, bool intern_if_not_found, TRAPS); + static void print_signature(oop java_class, outputStream *st); // Testing static bool is_instance(oop obj) { return obj != NULL && obj->klass() == SystemDictionary::class_klass(); @@ -668,6 +672,8 @@ class java_lang_boxing_object: AllStatic { static BasicType basic_type(oop box); static bool is_instance(oop box) { return basic_type(box) != T_ILLEGAL; } static bool is_instance(oop box, BasicType type) { return basic_type(box) == type; } + static void print(oop box, outputStream* st) { jvalue value; print(get_value(box, &value), &value, st); } + static void print(BasicType type, jvalue* value, outputStream* st); static int value_offset_in_bytes(BasicType type) { return ( type == T_LONG || type == T_DOUBLE ) ? long_value_offset : diff --git a/hotspot/src/share/vm/classfile/loaderConstraints.hpp b/hotspot/src/share/vm/classfile/loaderConstraints.hpp index 9d1a6880a89..6928180d22a 100644 --- a/hotspot/src/share/vm/classfile/loaderConstraints.hpp +++ b/hotspot/src/share/vm/classfile/loaderConstraints.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,8 +60,10 @@ public: bool add_entry(symbolHandle name, klassOop klass1, Handle loader1, klassOop klass2, Handle loader2); - void check_signature_loaders(symbolHandle signature, Handle loader1, - Handle loader2, bool is_method, TRAPS); + // Note: The main entry point for this module is via SystemDictionary. + // SystemDictionary::check_signature_loaders(symbolHandle signature, + // Handle loader1, Handle loader2, + // bool is_method, TRAPS) klassOop find_constrained_klass(symbolHandle name, Handle loader); klassOop find_constrained_elem_klass(symbolHandle name, symbolHandle elem_name, diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index 0c2d6bbb3e9..076e29e3009 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,6 +109,40 @@ symbolOop SymbolTable::lookup_only(const char* name, int len, return the_table()->lookup(index, name, len, hash); } +// Suggestion: Push unicode-based lookup all the way into the hashing +// and probing logic, so there is no need for convert_to_utf8 until +// an actual new symbolOop is created. +symbolOop SymbolTable::lookup_unicode(const jchar* name, int utf16_length, TRAPS) { + int utf8_length = UNICODE::utf8_length((jchar*) name, utf16_length); + char stack_buf[128]; + if (utf8_length < (int) sizeof(stack_buf)) { + char* chars = stack_buf; + UNICODE::convert_to_utf8(name, utf16_length, chars); + return lookup(chars, utf8_length, THREAD); + } else { + ResourceMark rm(THREAD); + char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1);; + UNICODE::convert_to_utf8(name, utf16_length, chars); + return lookup(chars, utf8_length, THREAD); + } +} + +symbolOop SymbolTable::lookup_only_unicode(const jchar* name, int utf16_length, + unsigned int& hash) { + int utf8_length = UNICODE::utf8_length((jchar*) name, utf16_length); + char stack_buf[128]; + if (utf8_length < (int) sizeof(stack_buf)) { + char* chars = stack_buf; + UNICODE::convert_to_utf8(name, utf16_length, chars); + return lookup_only(chars, utf8_length, hash); + } else { + ResourceMark rm; + char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1);; + UNICODE::convert_to_utf8(name, utf16_length, chars); + return lookup_only(chars, utf8_length, hash); + } +} + void SymbolTable::add(constantPoolHandle cp, int names_count, const char** names, int* lengths, int* cp_indices, unsigned int* hashValues, TRAPS) { @@ -126,15 +160,6 @@ void SymbolTable::add(constantPoolHandle cp, int names_count, } } -// Needed for preloading classes in signatures when compiling. - -symbolOop SymbolTable::probe(const char* name, int len) { - unsigned int hashValue = hash_symbol(name, len); - int index = the_table()->hash_to_index(hashValue); - return the_table()->lookup(index, name, len, hashValue); -} - - symbolOop SymbolTable::basic_add(int index, u1 *name, int len, unsigned int hashValue, TRAPS) { assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), @@ -156,7 +181,7 @@ symbolOop SymbolTable::basic_add(int index, u1 *name, int len, symbolOop test = lookup(index, (char*)name, len, hashValue); if (test != NULL) { - // A race occured and another thread introduced the symbol, this one + // A race occurred and another thread introduced the symbol, this one // will be dropped and collected. return test; } @@ -193,7 +218,7 @@ bool SymbolTable::basic_add(constantPoolHandle cp, int names_count, int index = hash_to_index(hashValues[i]); symbolOop test = lookup(index, names[i], lengths[i], hashValues[i]); if (test != NULL) { - // A race occured and another thread introduced the symbol, this one + // A race occurred and another thread introduced the symbol, this one // will be dropped and collected. Use test instead. cp->symbol_at_put(cp_indices[i], test); } else { diff --git a/hotspot/src/share/vm/classfile/symbolTable.hpp b/hotspot/src/share/vm/classfile/symbolTable.hpp index 828512780bf..bb0f67d1cdd 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.hpp +++ b/hotspot/src/share/vm/classfile/symbolTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,6 +91,10 @@ public: // Only copy to C string to be added if lookup failed. static symbolOop lookup(symbolHandle sym, int begin, int end, TRAPS); + // jchar (utf16) version of lookups + static symbolOop lookup_unicode(const jchar* name, int len, TRAPS); + static symbolOop lookup_only_unicode(const jchar* name, int len, unsigned int& hash); + static void add(constantPoolHandle cp, int names_count, const char** names, int* lengths, int* cp_indices, unsigned int* hashValues, TRAPS); @@ -112,7 +116,14 @@ public: // Needed for preloading classes in signatures when compiling. // Returns the symbol is already present in symbol table, otherwise // NULL. NO ALLOCATION IS GUARANTEED! - static symbolOop probe(const char* name, int len); + static symbolOop probe(const char* name, int len) { + unsigned int ignore_hash; + return lookup_only(name, len, ignore_hash); + } + static symbolOop probe_unicode(const jchar* name, int len) { + unsigned int ignore_hash; + return lookup_only_unicode(name, len, ignore_hash); + } // Histogram static void print_histogram() PRODUCT_RETURN; diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 9ab749afb3e..b6af53d2d27 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1964,6 +1964,13 @@ BasicType SystemDictionary::box_klass_type(klassOop k) { return T_OBJECT; } +KlassHandle SystemDictionaryHandles::box_klass(BasicType t) { + if (t >= T_BOOLEAN && t <= T_VOID) + return KlassHandle(&SystemDictionary::_box_klasses[t], true); + else + return KlassHandle(); +} + // Constraints on class loaders. The details of the algorithm can be // found in the OOPSLA'98 paper "Dynamic Class Loading in the Java // Virtual Machine" by Sheng Liang and Gilad Bracha. The basic idea is @@ -2174,11 +2181,56 @@ symbolOop SystemDictionary::find_resolution_error(constantPoolHandle pool, int w } +// Signature constraints ensure that callers and callees agree about +// the meaning of type names in their signatures. This routine is the +// intake for constraints. It collects them from several places: +// +// * LinkResolver::resolve_method (if check_access is true) requires +// that the resolving class (the caller) and the defining class of +// the resolved method (the callee) agree on each type in the +// method's signature. +// +// * LinkResolver::resolve_interface_method performs exactly the same +// checks. +// +// * LinkResolver::resolve_field requires that the constant pool +// attempting to link to a field agree with the field's defining +// class about the type of the field signature. +// +// * klassVtable::initialize_vtable requires that, when a class +// overrides a vtable entry allocated by a superclass, that the +// overriding method (i.e., the callee) agree with the superclass +// on each type in the method's signature. +// +// * klassItable::initialize_itable requires that, when a class fills +// in its itables, for each non-abstract method installed in an +// itable, the method (i.e., the callee) agree with the interface +// on each type in the method's signature. +// +// All those methods have a boolean (check_access, checkconstraints) +// which turns off the checks. This is used from specialized contexts +// such as bootstrapping, dumping, and debugging. +// +// No direct constraint is placed between the class and its +// supertypes. Constraints are only placed along linked relations +// between callers and callees. When a method overrides or implements +// an abstract method in a supertype (superclass or interface), the +// constraints are placed as if the supertype were the caller to the +// overriding method. (This works well, since callers to the +// supertype have already established agreement between themselves and +// the supertype.) As a result of all this, a class can disagree with +// its supertype about the meaning of a type name, as long as that +// class neither calls a relevant method of the supertype, nor is +// called (perhaps via an override) from the supertype. +// +// +// SystemDictionary::check_signature_loaders(sig, l1, l2) +// // Make sure all class components (including arrays) in the given // signature will be resolved to the same class in both loaders. // Returns the name of the type that failed a loader constraint check, or // NULL if no constraint failed. The returned C string needs cleaning up -// with a ResourceMark in the caller +// with a ResourceMark in the caller. No exception except OOME is thrown. char* SystemDictionary::check_signature_loaders(symbolHandle signature, Handle loader1, Handle loader2, bool is_method, TRAPS) { diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index 38abf2d3c0a..6444709dd62 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -161,6 +161,7 @@ class ResolutionErrorTable; class SystemDictionary : AllStatic { friend class VMStructs; friend class CompactingPermGenGen; + friend class SystemDictionaryHandles; NOT_PRODUCT(friend class instanceKlassKlass;) public: @@ -595,3 +596,18 @@ private: static bool _has_loadClassInternal; static bool _has_checkPackageAccess; }; + +// Cf. vmSymbols vs. vmSymbolHandles +class SystemDictionaryHandles : AllStatic { +public: + #define WK_KLASS_HANDLE_DECLARE(name, ignore_symbol, option) \ + static KlassHandle name() { \ + SystemDictionary::name(); \ + klassOop* loc = &SystemDictionary::_well_known_klasses[SystemDictionary::WK_KLASS_ENUM_NAME(name)]; \ + return KlassHandle(loc, true); \ + } + WK_KLASSES_DO(WK_KLASS_HANDLE_DECLARE); + #undef WK_KLASS_HANDLE_DECLARE + + static KlassHandle box_klass(BasicType t); +}; diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 8379af9c414..fc0601aee3a 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,8 @@ template(java_lang_Object, "java/lang/Object") \ template(java_lang_Class, "java/lang/Class") \ template(java_lang_String, "java/lang/String") \ + template(java_lang_StringValue, "java/lang/StringValue") \ + template(java_lang_StringCache, "java/lang/StringValue$StringCache") \ template(java_lang_Thread, "java/lang/Thread") \ template(java_lang_ThreadGroup, "java/lang/ThreadGroup") \ template(java_lang_Cloneable, "java/lang/Cloneable") \ @@ -284,6 +286,9 @@ template(value_name, "value") \ template(frontCacheEnabled_name, "frontCacheEnabled") \ template(stringCacheEnabled_name, "stringCacheEnabled") \ + template(bitCount_name, "bitCount") \ + template(profile_name, "profile") \ + template(equals_name, "equals") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ @@ -304,6 +309,7 @@ template(double_long_signature, "(D)J") \ template(double_double_signature, "(D)D") \ template(int_float_signature, "(I)F") \ + template(long_int_signature, "(J)I") \ template(long_long_signature, "(J)J") \ template(long_double_signature, "(J)D") \ template(byte_signature, "B") \ @@ -376,7 +382,7 @@ template(unknown_class_name, "") \ \ /* used to identify class loaders handling parallel class loading */ \ - template(parallelCapable_name, "parallelLockMap;") \ + template(parallelCapable_name, "parallelLockMap") \ \ /* JVM monitoring and management support */ \ template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \ @@ -507,6 +513,10 @@ do_name( doubleToLongBits_name, "doubleToLongBits") \ do_intrinsic(_longBitsToDouble, java_lang_Double, longBitsToDouble_name, long_double_signature, F_S) \ do_name( longBitsToDouble_name, "longBitsToDouble") \ + \ + do_intrinsic(_bitCount_i, java_lang_Integer, bitCount_name, int_int_signature, F_S) \ + do_intrinsic(_bitCount_l, java_lang_Long, bitCount_name, long_int_signature, F_S) \ + \ do_intrinsic(_reverseBytes_i, java_lang_Integer, reverseBytes_name, int_int_signature, F_S) \ do_name( reverseBytes_name, "reverseBytes") \ do_intrinsic(_reverseBytes_l, java_lang_Long, reverseBytes_name, long_long_signature, F_S) \ @@ -570,7 +580,6 @@ do_signature(copyOfRange_signature, "([Ljava/lang/Object;IILjava/lang/Class;)[Ljava/lang/Object;") \ \ do_intrinsic(_equalsC, java_util_Arrays, equals_name, equalsC_signature, F_S) \ - do_name( equals_name, "equals") \ do_signature(equalsC_signature, "([C[C)Z") \ \ do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \ @@ -580,6 +589,7 @@ do_name( compareTo_name, "compareTo") \ do_intrinsic(_indexOf, java_lang_String, indexOf_name, string_int_signature, F_R) \ do_name( indexOf_name, "indexOf") \ + do_intrinsic(_equals, java_lang_String, equals_name, object_boolean_signature, F_R) \ \ do_class(java_nio_Buffer, "java/nio/Buffer") \ do_intrinsic(_checkIndex, java_nio_Buffer, checkIndex_name, int_int_signature, F_R) \ @@ -696,7 +706,6 @@ do_signature(putShort_raw_signature, "(JS)V") \ do_signature(getChar_raw_signature, "(J)C") \ do_signature(putChar_raw_signature, "(JC)V") \ - do_signature(getInt_raw_signature, "(J)I") \ do_signature(putInt_raw_signature, "(JI)V") \ do_alias(getLong_raw_signature, /*(J)J*/ long_long_signature) \ do_alias(putLong_raw_signature, /*(JJ)V*/ long_long_void_signature) \ @@ -713,7 +722,7 @@ do_intrinsic(_getByte_raw, sun_misc_Unsafe, getByte_name, getByte_raw_signature, F_RN) \ do_intrinsic(_getShort_raw, sun_misc_Unsafe, getShort_name, getShort_raw_signature, F_RN) \ do_intrinsic(_getChar_raw, sun_misc_Unsafe, getChar_name, getChar_raw_signature, F_RN) \ - do_intrinsic(_getInt_raw, sun_misc_Unsafe, getInt_name, getInt_raw_signature, F_RN) \ + do_intrinsic(_getInt_raw, sun_misc_Unsafe, getInt_name, long_int_signature, F_RN) \ do_intrinsic(_getLong_raw, sun_misc_Unsafe, getLong_name, getLong_raw_signature, F_RN) \ do_intrinsic(_getFloat_raw, sun_misc_Unsafe, getFloat_name, getFloat_raw_signature, F_RN) \ do_intrinsic(_getDouble_raw, sun_misc_Unsafe, getDouble_name, getDouble_raw_signature, F_RN) \ diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 6baa28690db..ff5985f1e2a 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -380,7 +380,7 @@ address nmethod::handler_for_exception_and_pc(Handle exception, address pc) { void nmethod::add_handler_for_exception_and_pc(Handle exception, address pc, address handler) { // There are potential race conditions during exception cache updates, so we // must own the ExceptionCache_lock before doing ANY modifications. Because - // we dont lock during reads, it is possible to have several threads attempt + // we don't lock during reads, it is possible to have several threads attempt // to update the cache with the same data. We need to check for already inserted // copies of the current data before adding it. diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index d2c4af89501..8305f7949d0 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -167,7 +167,7 @@ class nmethod : public CodeBlob { nmFlags flags; // various flags to keep track of nmethod state bool _markedForDeoptimization; // Used for stack deoptimization enum { alive = 0, - not_entrant = 1, // uncommon trap has happend but activations may still exist + not_entrant = 1, // uncommon trap has happened but activations may still exist zombie = 2, unloaded = 3 }; diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp index 3a07470e395..b21dab7ff7a 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp @@ -393,7 +393,7 @@ class CMSAdaptiveSizePolicy : public AdaptiveSizePolicy { // Restarts the concurrent phases timer. void concurrent_phases_resume(); - // Time begining and end of the marking phase for + // Time beginning and end of the marking phase for // a synchronous MS collection. A MS collection // that finishes in the foreground can have started // in the background. These methods capture the diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsGCAdaptivePolicyCounters.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsGCAdaptivePolicyCounters.hpp index 33321824520..f9054002078 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsGCAdaptivePolicyCounters.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsGCAdaptivePolicyCounters.hpp @@ -69,7 +69,7 @@ class CMSGCAdaptivePolicyCounters : public GCAdaptivePolicyCounters { // end of the sweep of the tenured generation. PerfVariable* _avg_cms_free_counter; // Average of the free space in the tenured generation at the - // start of the sweep of the tenured genertion. + // start of the sweep of the tenured generation. PerfVariable* _avg_cms_free_at_sweep_counter; // Average of the free space in the tenured generation at the // after any resizing of the tenured generation at the end diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index 6c6272a2f84..6b4bd36d934 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index e0c48a1b79a..9f16f8d2eb0 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index d716797bab4..40714825b7d 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3847,7 +3847,7 @@ bool CMSConcMarkingTask::get_work_from_overflow_stack(CMSMarkStack* ovflw_stk, MutexLockerEx ml(ovflw_stk->par_lock(), Mutex::_no_safepoint_check_flag); // Grab up to 1/4 the size of the work queue - size_t num = MIN2((size_t)work_q->max_elems()/4, + size_t num = MIN2((size_t)(work_q->max_elems() - work_q->size())/4, (size_t)ParGCDesiredObjsFromOverflowList); num = MIN2(num, ovflw_stk->length()); for (int i = (int) num; i > 0; i--) { @@ -4178,7 +4178,7 @@ bool CMSCollector::do_marking_mt(bool asynch) { // and is deferred for now; see CR# TBF. 07252005YSR. XXX assert(!CMSAbortSemantics || tsk.aborted(), "Inconsistency"); // If _restart_addr is non-NULL, a marking stack overflow - // occured; we need to do a fresh marking iteration from the + // occurred; we need to do a fresh marking iteration from the // indicated restart address. if (_foregroundGCIsActive && asynch) { // We may be running into repeated stack overflows, having @@ -4221,7 +4221,7 @@ bool CMSCollector::do_marking_st(bool asynch) { // should be incremental with periodic yields. _markBitMap.iterate(&markFromRootsClosure); // If _restart_addr is non-NULL, a marking stack overflow - // occured; we need to do a fresh iteration from the + // occurred; we need to do a fresh iteration from the // indicated restart address. while (_restart_addr != NULL) { if (_foregroundGCIsActive && asynch) { @@ -5204,13 +5204,12 @@ CMSParRemarkTask::do_work_steal(int i, Par_MarkRefsIntoAndScanClosure* cl, NOT_PRODUCT(int num_steals = 0;) oop obj_to_scan; CMSBitMap* bm = &(_collector->_markBitMap); - size_t num_from_overflow_list = - MIN2((size_t)work_q->max_elems()/4, - (size_t)ParGCDesiredObjsFromOverflowList); while (true) { // Completely finish any left over work from (an) earlier round(s) cl->trim_queue(0); + size_t num_from_overflow_list = MIN2((size_t)(work_q->max_elems() - work_q->size())/4, + (size_t)ParGCDesiredObjsFromOverflowList); // Now check if there's any work in the overflow list if (_collector->par_take_from_overflow_list(num_from_overflow_list, work_q)) { @@ -5622,13 +5621,12 @@ void CMSRefProcTaskProxy::do_work_steal(int i, OopTaskQueue* work_q = work_queue(i); NOT_PRODUCT(int num_steals = 0;) oop obj_to_scan; - size_t num_from_overflow_list = - MIN2((size_t)work_q->max_elems()/4, - (size_t)ParGCDesiredObjsFromOverflowList); while (true) { // Completely finish any left over work from (an) earlier round(s) drain->trim_queue(0); + size_t num_from_overflow_list = MIN2((size_t)(work_q->max_elems() - work_q->size())/4, + (size_t)ParGCDesiredObjsFromOverflowList); // Now check if there's any work in the overflow list if (_collector->par_take_from_overflow_list(num_from_overflow_list, work_q)) { @@ -9021,7 +9019,7 @@ void ASConcurrentMarkSweepGeneration::shrink_by(size_t desired_bytes) { // Transfer some number of overflown objects to usual marking // stack. Return true if some objects were transferred. bool MarkRefsIntoAndScanClosure::take_from_overflow_list() { - size_t num = MIN2((size_t)_mark_stack->capacity()/4, + size_t num = MIN2((size_t)(_mark_stack->capacity() - _mark_stack->length())/4, (size_t)ParGCDesiredObjsFromOverflowList); bool res = _collector->take_from_overflow_list(num, _mark_stack); diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index d36c6fc47df..dd5f5605595 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp index fbc5f4f151b..418dd584954 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp @@ -277,8 +277,6 @@ printHeapRegion(HeapRegion *hr) { gclog_or_tty->print("H: "); if (hr->in_collection_set()) gclog_or_tty->print("CS: "); - if (hr->popular()) - gclog_or_tty->print("pop: "); gclog_or_tty->print_cr("Region " PTR_FORMAT " (%s%s) " "[" PTR_FORMAT ", " PTR_FORMAT"] " "Used: " SIZE_FORMAT "K, garbage: " SIZE_FORMAT "K.", diff --git a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp index 2c23680ced6..5960d8cce26 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp index 2eb2bc0ca69..6f12a396216 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp @@ -145,14 +145,9 @@ void ConcurrentG1Refine::set_pya_restart() { if (G1RSBarrierUseQueue) { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); dcqs.abandon_logs(); - if (_cg1rThread->do_traversal()) { - _pya = PYA_restart; - } else { - _cg1rThread->set_do_traversal(true); - // Reset the post-yield actions. - _pya = PYA_continue; - _last_pya = PYA_continue; - } + // Reset the post-yield actions. + _pya = PYA_continue; + _last_pya = PYA_continue; } else { _pya = PYA_restart; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp index 1436e5a1c52..a2717150206 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp index 110c08327c3..b099908a7a7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp @@ -133,14 +133,12 @@ void ConcurrentG1RefineThread::queueBasedRefinement() { _co_tracker.update(false); if (G1SmoothConcRefine) { - start_vtime_sec = os::elapsedVTime(); prev_buffer_num = curr_buffer_num; - _sts.leave(); os::sleep(Thread::current(), (jlong) _interval_ms, false); _sts.join(); + start_vtime_sec = os::elapsedVTime(); } - n_logs++; } // Make sure we harvest the PYA, if any. diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index c7a7ca7dc8f..fb4f502cf94 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -107,7 +107,7 @@ void CMBitMapRO::mostly_disjoint_range_union(BitMap* from_bitmap, #ifndef PRODUCT bool CMBitMapRO::covers(ReservedSpace rs) const { // assert(_bm.map() == _virtual_space.low(), "map inconsistency"); - assert(((size_t)_bm.size() * (1 << _shifter)) == _bmWordSize, + assert(((size_t)_bm.size() * (size_t)(1 << _shifter)) == _bmWordSize, "size inconsistency"); return _bmStartWord == (HeapWord*)(rs.base()) && _bmWordSize == rs.size()>>LogHeapWordSize; @@ -420,6 +420,10 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs, _has_overflown(false), _concurrent(false), + _has_aborted(false), + _restart_for_overflow(false), + _concurrent_marking_in_progress(false), + _should_gray_objects(false), // _verbose_level set below @@ -1228,7 +1232,16 @@ public: if (!_final && _regions_done == 0) _start_vtime_sec = os::elapsedVTime(); - if (hr->continuesHumongous()) return false; + if (hr->continuesHumongous()) { + HeapRegion* hum_start = hr->humongous_start_region(); + // If the head region of the humongous region has been determined + // to be alive, then all the tail regions should be marked + // such as well. + if (_region_bm->at(hum_start->hrs_index())) { + _region_bm->par_at_put(hr->hrs_index(), 1); + } + return false; + } HeapWord* nextTop = hr->next_top_at_mark_start(); HeapWord* start = hr->top_at_conc_mark_count(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index db4b4dfb834..274f8c19e6e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp index e26df0caae0..277ac636ecb 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp @@ -107,7 +107,7 @@ void ConcurrentMarkThread::run() { if (PrintGC) { gclog_or_tty->date_stamp(PrintGCDateStamps); gclog_or_tty->stamp(PrintGCTimeStamps); - tty->print_cr("[GC concurrent-mark-start]"); + gclog_or_tty->print_cr("[GC concurrent-mark-start]"); } if (!g1_policy->in_young_gc_mode()) { @@ -320,8 +320,6 @@ void ConcurrentMarkThread::sleepBeforeNextCycle() { set_in_progress(); clear_started(); if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-starting"); - - return; } // Note: this method, although exported by the ConcurrentMarkSweepThread, diff --git a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp index f3934812dd1..ec26c6a46ef 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp @@ -78,8 +78,8 @@ size_t DirtyCardQueueSet::num_par_ids() { void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock, int max_completed_queue, - Mutex* lock) { - PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue); + Mutex* lock, PtrQueueSet* fl_owner) { + PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue, fl_owner); set_buffer_size(DCQBarrierQueueBufferSize); set_process_completed_threshold(DCQBarrierProcessCompletedThreshold); diff --git a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp index 86876fd949d..7a6f3f27bbd 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp @@ -88,7 +88,7 @@ public: void initialize(Monitor* cbl_mon, Mutex* fl_lock, int max_completed_queue = 0, - Mutex* lock = NULL); + Mutex* lock = NULL, PtrQueueSet* fl_owner = NULL); // The number of parallel ids that can be claimed to allow collector or // mutator threads to do card-processing work. diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 1c6766b9947..fb4a0c79868 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,21 +42,6 @@ // Local to this file. -// Finds the first HeapRegion. -// No longer used, but might be handy someday. - -class FindFirstRegionClosure: public HeapRegionClosure { - HeapRegion* _a_region; -public: - FindFirstRegionClosure() : _a_region(NULL) {} - bool doHeapRegion(HeapRegion* r) { - _a_region = r; - return true; - } - HeapRegion* result() { return _a_region; } -}; - - class RefineCardTableEntryClosure: public CardTableEntryClosure { SuspendibleThreadSet* _sts; G1RemSet* _g1rs; @@ -136,6 +121,14 @@ public: int calls() { return _calls; } }; +class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure { +public: + bool do_card_ptr(jbyte* card_ptr, int worker_i) { + *card_ptr = CardTableModRefBS::dirty_card_val(); + return true; + } +}; + YoungList::YoungList(G1CollectedHeap* g1h) : _g1h(g1h), _head(NULL), _scan_only_head(NULL), _scan_only_tail(NULL), _curr_scan_only(NULL), @@ -778,6 +771,12 @@ void G1CollectedHeap::abandon_cur_alloc_region() { } } +void G1CollectedHeap::abandon_gc_alloc_regions() { + // first, make sure that the GC alloc region list is empty (it should!) + assert(_gc_alloc_region_list == NULL, "invariant"); + release_gc_alloc_regions(true /* totally */); +} + class PostMCRemSetClearClosure: public HeapRegionClosure { ModRefBarrierSet* _mr_bs; public: @@ -812,6 +811,40 @@ public: } }; +class RebuildRSOutOfRegionClosure: public HeapRegionClosure { + G1CollectedHeap* _g1h; + UpdateRSOopClosure _cl; + int _worker_i; +public: + RebuildRSOutOfRegionClosure(G1CollectedHeap* g1, int worker_i = 0) : + _cl(g1->g1_rem_set()->as_HRInto_G1RemSet(), worker_i), + _worker_i(worker_i), + _g1h(g1) + { } + bool doHeapRegion(HeapRegion* r) { + if (!r->continuesHumongous()) { + _cl.set_from(r); + r->oop_iterate(&_cl); + } + return false; + } +}; + +class ParRebuildRSTask: public AbstractGangTask { + G1CollectedHeap* _g1; +public: + ParRebuildRSTask(G1CollectedHeap* g1) + : AbstractGangTask("ParRebuildRSTask"), + _g1(g1) + { } + + void work(int i) { + RebuildRSOutOfRegionClosure rebuild_rs(_g1, i); + _g1->heap_region_par_iterate_chunked(&rebuild_rs, i, + HeapRegion::RebuildRSClaimValue); + } +}; + void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, size_t word_size) { ResourceMark rm; @@ -872,6 +905,7 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, // Make sure we'll choose a new allocation region afterwards. abandon_cur_alloc_region(); + abandon_gc_alloc_regions(); assert(_cur_alloc_region == NULL, "Invariant."); g1_rem_set()->as_HRInto_G1RemSet()->cleanupHRRS(); tear_down_region_lists(); @@ -912,30 +946,42 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); + prepare_for_verify(); Universe::verify(false); } NOT_PRODUCT(ref_processor()->verify_no_references_recorded()); reset_gc_time_stamp(); // Since everything potentially moved, we will clear all remembered - // sets, and clear all cards. Later we will also cards in the used - // portion of the heap after the resizing (which could be a shrinking.) - // We will also reset the GC time stamps of the regions. + // sets, and clear all cards. Later we will rebuild remebered + // sets. We will also reset the GC time stamps of the regions. PostMCRemSetClearClosure rs_clear(mr_bs()); heap_region_iterate(&rs_clear); // Resize the heap if necessary. resize_if_necessary_after_full_collection(full ? 0 : word_size); - // Since everything potentially moved, we will clear all remembered - // sets, but also dirty all cards corresponding to used regions. - PostMCRemSetInvalidateClosure rs_invalidate(mr_bs()); - heap_region_iterate(&rs_invalidate); if (_cg1r->use_cache()) { _cg1r->clear_and_record_card_counts(); _cg1r->clear_hot_cache(); } + // Rebuild remembered sets of all regions. + if (ParallelGCThreads > 0) { + ParRebuildRSTask rebuild_rs_task(this); + assert(check_heap_region_claim_values( + HeapRegion::InitialClaimValue), "sanity check"); + set_par_threads(workers()->total_workers()); + workers()->run_task(&rebuild_rs_task); + set_par_threads(0); + assert(check_heap_region_claim_values( + HeapRegion::RebuildRSClaimValue), "sanity check"); + reset_heap_region_claim_values(); + } else { + RebuildRSOutOfRegionClosure rebuild_rs(this); + heap_region_iterate(&rebuild_rs); + } + if (PrintGC) { print_size_transition(gclog_or_tty, g1h_prev_used, used(), capacity()); } @@ -961,7 +1007,8 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, // dirtied, so this should abandon those logs, and set "do_traversal" // to true. concurrent_g1_refine()->set_pya_restart(); - + assert(!G1DeferredRSUpdate + || (G1DeferredRSUpdate && (dirty_card_queue_set().completed_buffers_num() == 0)), "Should not be any"); assert(regions_accounted_for(), "Region leakage!"); } @@ -1145,13 +1192,12 @@ G1CollectedHeap::free_region_if_totally_empty_work(HeapRegion* hr, bool par) { assert(!hr->continuesHumongous(), "should have filtered these out"); size_t res = 0; - if (!hr->popular() && hr->used() > 0 && hr->garbage_bytes() == hr->used()) { - if (!hr->is_young()) { - if (G1PolicyVerbose > 0) - gclog_or_tty->print_cr("Freeing empty region "PTR_FORMAT "(" SIZE_FORMAT " bytes)" - " during cleanup", hr, hr->used()); - free_region_work(hr, pre_used, cleared_h, freed_regions, list, par); - } + if (hr->used() > 0 && hr->garbage_bytes() == hr->used() && + !hr->is_young()) { + if (G1PolicyVerbose > 0) + gclog_or_tty->print_cr("Freeing empty region "PTR_FORMAT "(" SIZE_FORMAT " bytes)" + " during cleanup", hr, hr->used()); + free_region_work(hr, pre_used, cleared_h, freed_regions, list, par); } } @@ -1252,7 +1298,7 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) } void G1CollectedHeap::shrink(size_t shrink_bytes) { - release_gc_alloc_regions(); + release_gc_alloc_regions(true /* totally */); tear_down_region_lists(); // We will rebuild them in a moment. shrink_helper(shrink_bytes); rebuild_region_lists(); @@ -1280,10 +1326,6 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _refine_cte_cl(NULL), _free_region_list(NULL), _free_region_list_size(0), _free_regions(0), - _popular_object_boundary(NULL), - _cur_pop_hr_index(0), - _popular_regions_to_be_evacuated(NULL), - _pop_obj_rc_at_copy(), _full_collection(false), _unclean_region_list(), _unclean_regions_coming(false), @@ -1291,8 +1333,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _gc_time_stamp(0), _surviving_young_words(NULL), _in_cset_fast_test(NULL), - _in_cset_fast_test_base(NULL) -{ + _in_cset_fast_test_base(NULL) { _g1h = this; // To catch bugs. if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) { vm_exit_during_initialization("Failed necessary allocation."); @@ -1317,9 +1358,19 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : } for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - _gc_alloc_regions[ap] = NULL; - _gc_alloc_region_counts[ap] = 0; + _gc_alloc_regions[ap] = NULL; + _gc_alloc_region_counts[ap] = 0; + _retained_gc_alloc_regions[ap] = NULL; + // by default, we do not retain a GC alloc region for each ap; + // we'll override this, when appropriate, below + _retain_gc_alloc_region[ap] = false; } + + // We will try to remember the last half-full tenured region we + // allocated to at the end of a collection so that we can re-use it + // during the next collection. + _retain_gc_alloc_region[GCAllocForTenured] = true; + guarantee(_task_queues != NULL, "task_queues allocation failure."); } @@ -1351,9 +1402,34 @@ jint G1CollectedHeap::initialize() { // Reserve the maximum. PermanentGenerationSpec* pgs = collector_policy()->permanent_generation(); // Includes the perm-gen. + + const size_t total_reserved = max_byte_size + pgs->max_size(); + char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); + ReservedSpace heap_rs(max_byte_size + pgs->max_size(), HeapRegion::GrainBytes, - false /*ism*/); + false /*ism*/, addr); + + if (UseCompressedOops) { + if (addr != NULL && !heap_rs.is_reserved()) { + // Failed to reserve at specified address - the requested memory + // region is taken already, for example, by 'java' launcher. + // Try again to reserver heap higher. + addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); + ReservedSpace heap_rs0(total_reserved, HeapRegion::GrainBytes, + false /*ism*/, addr); + if (addr != NULL && !heap_rs0.is_reserved()) { + // Failed to reserve at specified address again - give up. + addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); + assert(addr == NULL, ""); + ReservedSpace heap_rs1(total_reserved, HeapRegion::GrainBytes, + false /*ism*/, addr); + heap_rs = heap_rs1; + } else { + heap_rs = heap_rs0; + } + } + } if (!heap_rs.is_reserved()) { vm_exit_during_initialization("Could not reserve enough space for object heap"); @@ -1424,26 +1500,11 @@ jint G1CollectedHeap::initialize() { _czft = new ConcurrentZFThread(); } - - - // Allocate the popular regions; take them off free lists. - size_t pop_byte_size = G1NumPopularRegions * HeapRegion::GrainBytes; - expand(pop_byte_size); - _popular_object_boundary = - _g1_reserved.start() + (G1NumPopularRegions * HeapRegion::GrainWords); - for (int i = 0; i < G1NumPopularRegions; i++) { - HeapRegion* hr = newAllocRegion(HeapRegion::GrainWords); - // assert(hr != NULL && hr->bottom() < _popular_object_boundary, - // "Should be enough, and all should be below boundary."); - hr->set_popular(true); - } - assert(_cur_pop_hr_index == 0, "Start allocating at the first region."); - // Initialize the from_card cache structure of HeapRegionRemSet. HeapRegionRemSet::init_heap(max_regions()); - // Now expand into the rest of the initial heap size. - expand(init_byte_size - pop_byte_size); + // Now expand into the initial heap size. + expand(init_byte_size); // Perform any initialization actions delegated to the policy. g1_policy()->init(); @@ -1466,6 +1527,13 @@ jint G1CollectedHeap::initialize() { G1DirtyCardQueueMax, Shared_DirtyCardQ_lock); } + if (G1DeferredRSUpdate) { + dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon, + DirtyCardQ_FL_lock, + 0, + Shared_DirtyCardQ_lock, + &JavaThread::dirty_card_queue_set()); + } // In case we're keeping closure specialization stats, initialize those // counts and that mechanism. SpecializationStats::clear(); @@ -1551,8 +1619,7 @@ size_t G1CollectedHeap::recalculate_used() const { class SumUsedRegionsClosure: public HeapRegionClosure { size_t _num; public: - // _num is set to 1 to account for the popular region - SumUsedRegionsClosure() : _num(G1NumPopularRegions) {} + SumUsedRegionsClosure() : _num(0) {} bool doHeapRegion(HeapRegion* r) { if (r->continuesHumongous() || r->used() > 0 || r->is_gc_alloc_region()) { _num += 1; @@ -1655,14 +1722,20 @@ public: } }; -void G1CollectedHeap::oop_iterate(OopClosure* cl) { +void G1CollectedHeap::oop_iterate(OopClosure* cl, bool do_perm) { IterateOopClosureRegionClosure blk(_g1_committed, cl); _hrs->iterate(&blk); + if (do_perm) { + perm_gen()->oop_iterate(cl); + } } -void G1CollectedHeap::oop_iterate(MemRegion mr, OopClosure* cl) { +void G1CollectedHeap::oop_iterate(MemRegion mr, OopClosure* cl, bool do_perm) { IterateOopClosureRegionClosure blk(mr, cl); _hrs->iterate(&blk); + if (do_perm) { + perm_gen()->oop_iterate(cl); + } } // Iterates an ObjectClosure over all objects within a HeapRegion. @@ -1679,9 +1752,12 @@ public: } }; -void G1CollectedHeap::object_iterate(ObjectClosure* cl) { +void G1CollectedHeap::object_iterate(ObjectClosure* cl, bool do_perm) { IterateObjectClosureRegionClosure blk(cl); _hrs->iterate(&blk); + if (do_perm) { + perm_gen()->object_iterate(cl); + } } void G1CollectedHeap::object_iterate_since_last_GC(ObjectClosure* cl) { @@ -2058,15 +2134,7 @@ public: bool doHeapRegion(HeapRegion* r) { guarantee(_par || r->claim_value() == HeapRegion::InitialClaimValue, "Should be unclaimed at verify points."); - if (r->isHumongous()) { - if (r->startsHumongous()) { - // Verify the single H object. - oop(r->bottom())->verify(); - size_t word_sz = oop(r->bottom())->size(); - guarantee(r->top() == r->bottom() + word_sz, - "Only one object in a humongous region"); - } - } else { + if (!r->continuesHumongous()) { VerifyObjsInRegionClosure not_dead_yet_cl(r); r->verify(_allow_dirty); r->object_iterate(¬_dead_yet_cl); @@ -2118,6 +2186,7 @@ public: _g1h(g1h), _allow_dirty(allow_dirty) { } void work(int worker_i) { + HandleMark hm; VerifyRegionClosure blk(_allow_dirty, true); _g1h->heap_region_par_iterate_chunked(&blk, worker_i, HeapRegion::ParVerifyClaimValue); @@ -2222,9 +2291,6 @@ void G1CollectedHeap::print_tracing_info() const { if (SummarizeG1ZFStats) { ConcurrentZFThread::print_summary_info(); } - if (G1SummarizePopularity) { - print_popularity_summary_info(); - } g1_policy()->print_yg_surv_rate_info(); GCOverheadReporter::printGCOverhead(); @@ -2316,10 +2382,9 @@ class VerifyMarkedObjsClosure: public ObjectClosure { void G1CollectedHeap::checkConcurrentMark() { VerifyMarkedObjsClosure verifycl(this); - doConcurrentMark(); // MutexLockerEx x(getMarkBitMapLock(), // Mutex::_no_safepoint_check_flag); - object_iterate(&verifycl); + object_iterate(&verifycl, false); } void G1CollectedHeap::do_sync_mark() { @@ -2400,30 +2465,19 @@ G1CollectedHeap::cleanup_surviving_young_words() { // void -G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { +G1CollectedHeap::do_collection_pause_at_safepoint() { char verbose_str[128]; sprintf(verbose_str, "GC pause "); - if (popular_region != NULL) - strcat(verbose_str, "(popular)"); - else if (g1_policy()->in_young_gc_mode()) { + if (g1_policy()->in_young_gc_mode()) { if (g1_policy()->full_young_gcs()) strcat(verbose_str, "(young)"); else strcat(verbose_str, "(partial)"); } - bool reset_should_initiate_conc_mark = false; - if (popular_region != NULL && g1_policy()->should_initiate_conc_mark()) { - // we currently do not allow an initial mark phase to be piggy-backed - // on a popular pause - reset_should_initiate_conc_mark = true; - g1_policy()->unset_should_initiate_conc_mark(); - } if (g1_policy()->should_initiate_conc_mark()) strcat(verbose_str, " (initial-mark)"); - GCCauseSetter x(this, (popular_region == NULL ? - GCCause::_g1_inc_collection_pause : - GCCause::_g1_pop_region_collection_pause)); + GCCauseSetter x(this, GCCause::_g1_inc_collection_pause); // if PrintGCDetails is on, we'll print long statistics information // in the collector policy code, so let's not print this as the output @@ -2493,7 +2547,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { guarantee(_in_cset_fast_test == NULL, "invariant"); guarantee(_in_cset_fast_test_base == NULL, "invariant"); - _in_cset_fast_test_length = n_regions(); + _in_cset_fast_test_length = max_regions(); _in_cset_fast_test_base = NEW_C_HEAP_ARRAY(bool, _in_cset_fast_test_length); memset(_in_cset_fast_test_base, false, @@ -2513,8 +2567,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { } save_marks(); - // We must do this before any possible evacuation that should propogate - // marks, including evacuation of popular objects in a popular pause. + // We must do this before any possible evacuation that should propagate + // marks. if (mark_in_progress()) { double start_time_sec = os::elapsedTime(); @@ -2531,29 +2585,15 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { assert(regions_accounted_for(), "Region leakage."); - bool abandoned = false; - if (mark_in_progress()) concurrent_mark()->newCSet(); // Now choose the CS. - if (popular_region == NULL) { - g1_policy()->choose_collection_set(); - } else { - // We may be evacuating a single region (for popularity). - g1_policy()->record_popular_pause_preamble_start(); - popularity_pause_preamble(popular_region); - g1_policy()->record_popular_pause_preamble_end(); - abandoned = (g1_policy()->collection_set() == NULL); - // Now we allow more regions to be added (we have to collect - // all popular regions). - if (!abandoned) { - g1_policy()->choose_collection_set(popular_region); - } - } + g1_policy()->choose_collection_set(); + // We may abandon a pause if we find no region that will fit in the MMU // pause. - abandoned = (g1_policy()->collection_set() == NULL); + bool abandoned = (g1_policy()->collection_set() == NULL); // Nothing to do if we were unable to choose a collection set. if (!abandoned) { @@ -2578,13 +2618,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { _in_cset_fast_test = NULL; _in_cset_fast_test_base = NULL; - if (popular_region != NULL) { - // We have to wait until now, because we don't want the region to - // be rescheduled for pop-evac during RS update. - popular_region->set_popular_pending(false); - } - - release_gc_alloc_regions(); + release_gc_alloc_regions(false /* totally */); cleanup_surviving_young_words(); @@ -2626,18 +2660,17 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { #endif // SCAN_ONLY_VERBOSE double end_time_sec = os::elapsedTime(); - if (!evacuation_failed()) { - g1_policy()->record_pause_time((end_time_sec - start_time_sec)*1000.0); - } + double pause_time_ms = (end_time_sec - start_time_sec) * MILLIUNITS; + g1_policy()->record_pause_time_ms(pause_time_ms); GCOverheadReporter::recordSTWEnd(end_time_sec); - g1_policy()->record_collection_pause_end(popular_region != NULL, - abandoned); + g1_policy()->record_collection_pause_end(abandoned); assert(regions_accounted_for(), "Region leakage."); if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); + prepare_for_verify(); Universe::verify(false); } @@ -2664,9 +2697,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { assert(verify_region_lists(), "Bad region lists."); - if (reset_should_initiate_conc_mark) - g1_policy()->set_should_initiate_conc_mark(); - if (ExitAfterGCNum > 0 && total_collections() == ExitAfterGCNum) { gclog_or_tty->print_cr("Stopping after GC #%d", ExitAfterGCNum); print_tracing_info(); @@ -2676,6 +2706,10 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { void G1CollectedHeap::set_gc_alloc_region(int purpose, HeapRegion* r) { assert(purpose >= 0 && purpose < GCAllocPurposeCount, "invalid purpose"); + // make sure we don't call set_gc_alloc_region() multiple times on + // the same region + assert(r == NULL || !r->is_gc_alloc_region(), + "shouldn't already be a GC alloc region"); HeapWord* original_top = NULL; if (r != NULL) original_top = r->top(); @@ -2765,6 +2799,12 @@ void G1CollectedHeap::forget_alloc_region_list() { while (_gc_alloc_region_list != NULL) { HeapRegion* r = _gc_alloc_region_list; assert(r->is_gc_alloc_region(), "Invariant."); + // We need HeapRegion::oops_on_card_seq_iterate_careful() to work on + // newly allocated data in order to be able to apply deferred updates + // before the GC is done for verification purposes (i.e to allow + // G1HRRSFlushLogBuffersOnVerify). It's safe thing to do after the + // collection. + r->ContiguousSpace::set_saved_mark(); _gc_alloc_region_list = r->next_gc_alloc_region(); r->set_next_gc_alloc_region(NULL); r->set_is_gc_alloc_region(false); @@ -2792,23 +2832,55 @@ bool G1CollectedHeap::check_gc_alloc_regions() { } void G1CollectedHeap::get_gc_alloc_regions() { + // First, let's check that the GC alloc region list is empty (it should) + assert(_gc_alloc_region_list == NULL, "invariant"); + for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { + assert(_gc_alloc_regions[ap] == NULL, "invariant"); + // Create new GC alloc regions. - HeapRegion* alloc_region = _gc_alloc_regions[ap]; - // Clear this alloc region, so that in case it turns out to be - // unacceptable, we end up with no allocation region, rather than a bad - // one. - _gc_alloc_regions[ap] = NULL; - if (alloc_region == NULL || alloc_region->in_collection_set()) { - // Can't re-use old one. Allocate a new one. + HeapRegion* alloc_region = _retained_gc_alloc_regions[ap]; + _retained_gc_alloc_regions[ap] = NULL; + + if (alloc_region != NULL) { + assert(_retain_gc_alloc_region[ap], "only way to retain a GC region"); + + // let's make sure that the GC alloc region is not tagged as such + // outside a GC operation + assert(!alloc_region->is_gc_alloc_region(), "sanity"); + + if (alloc_region->in_collection_set() || + alloc_region->top() == alloc_region->end() || + alloc_region->top() == alloc_region->bottom()) { + // we will discard the current GC alloc region if it's in the + // collection set (it can happen!), if it's already full (no + // point in using it), or if it's empty (this means that it + // was emptied during a cleanup and it should be on the free + // list now). + + alloc_region = NULL; + } + } + + if (alloc_region == NULL) { + // we will get a new GC alloc region alloc_region = newAllocRegionWithExpansion(ap, 0); } + if (alloc_region != NULL) { + assert(_gc_alloc_regions[ap] == NULL, "pre-condition"); set_gc_alloc_region(ap, alloc_region); } + + assert(_gc_alloc_regions[ap] == NULL || + _gc_alloc_regions[ap]->is_gc_alloc_region(), + "the GC alloc region should be tagged as such"); + assert(_gc_alloc_regions[ap] == NULL || + _gc_alloc_regions[ap] == _gc_alloc_region_list, + "the GC alloc region should be the same as the GC alloc list head"); } // Set alternative regions for allocation purposes that have reached - // thier limit. + // their limit. for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { GCAllocPurpose alt_purpose = g1_policy()->alternative_purpose(ap); if (_gc_alloc_regions[ap] == NULL && alt_purpose != ap) { @@ -2818,28 +2890,56 @@ void G1CollectedHeap::get_gc_alloc_regions() { assert(check_gc_alloc_regions(), "alloc regions messed up"); } -void G1CollectedHeap::release_gc_alloc_regions() { +void G1CollectedHeap::release_gc_alloc_regions(bool totally) { // We keep a separate list of all regions that have been alloc regions in - // the current collection pause. Forget that now. + // the current collection pause. Forget that now. This method will + // untag the GC alloc regions and tear down the GC alloc region + // list. It's desirable that no regions are tagged as GC alloc + // outside GCs. forget_alloc_region_list(); // The current alloc regions contain objs that have survived // collection. Make them no longer GC alloc regions. for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { HeapRegion* r = _gc_alloc_regions[ap]; - if (r != NULL && r->is_empty()) { - { + _retained_gc_alloc_regions[ap] = NULL; + + if (r != NULL) { + // we retain nothing on _gc_alloc_regions between GCs + set_gc_alloc_region(ap, NULL); + _gc_alloc_region_counts[ap] = 0; + + if (r->is_empty()) { + // we didn't actually allocate anything in it; let's just put + // it on the free list MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); r->set_zero_fill_complete(); put_free_region_on_list_locked(r); + } else if (_retain_gc_alloc_region[ap] && !totally) { + // retain it so that we can use it at the beginning of the next GC + _retained_gc_alloc_regions[ap] = r; } } - // set_gc_alloc_region will also NULLify all aliases to the region - set_gc_alloc_region(ap, NULL); - _gc_alloc_region_counts[ap] = 0; } } +#ifndef PRODUCT +// Useful for debugging + +void G1CollectedHeap::print_gc_alloc_regions() { + gclog_or_tty->print_cr("GC alloc regions"); + for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { + HeapRegion* r = _gc_alloc_regions[ap]; + if (r == NULL) { + gclog_or_tty->print_cr(" %2d : "PTR_FORMAT, ap, NULL); + } else { + gclog_or_tty->print_cr(" %2d : "PTR_FORMAT" "SIZE_FORMAT, + ap, r->bottom(), r->used()); + } + } +} +#endif // PRODUCT + void G1CollectedHeap::init_for_evac_failure(OopsInHeapRegionClosure* cl) { _drain_in_progress = false; set_evac_failure_closure(cl); @@ -2919,27 +3019,51 @@ public: } }; -class RecreateRSetEntriesClosure: public OopClosure { +class UpdateRSetImmediate : public OopsInHeapRegionClosure { private: G1CollectedHeap* _g1; G1RemSet* _g1_rem_set; - HeapRegion* _from; public: - RecreateRSetEntriesClosure(G1CollectedHeap* g1, HeapRegion* from) : - _g1(g1), _g1_rem_set(g1->g1_rem_set()), _from(from) - {} + UpdateRSetImmediate(G1CollectedHeap* g1) : + _g1(g1), _g1_rem_set(g1->g1_rem_set()) {} void do_oop(narrowOop* p) { guarantee(false, "NYI"); } void do_oop(oop* p) { assert(_from->is_in_reserved(p), "paranoia"); - if (*p != NULL) { - _g1_rem_set->write_ref(_from, p); + if (*p != NULL && !_from->is_survivor()) { + _g1_rem_set->par_write_ref(_from, p, 0); } } }; +class UpdateRSetDeferred : public OopsInHeapRegionClosure { +private: + G1CollectedHeap* _g1; + DirtyCardQueue *_dcq; + CardTableModRefBS* _ct_bs; + +public: + UpdateRSetDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) : + _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) {} + + void do_oop(narrowOop* p) { + guarantee(false, "NYI"); + } + void do_oop(oop* p) { + assert(_from->is_in_reserved(p), "paranoia"); + if (!_from->is_in_reserved(*p) && !_from->is_survivor()) { + size_t card_index = _ct_bs->index_for(p); + if (_ct_bs->mark_card_deferred(card_index)) { + _dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index)); + } + } + } +}; + + + class RemoveSelfPointerClosure: public ObjectClosure { private: G1CollectedHeap* _g1; @@ -2947,11 +3071,11 @@ private: HeapRegion* _hr; size_t _prev_marked_bytes; size_t _next_marked_bytes; + OopsInHeapRegionClosure *_cl; public: - RemoveSelfPointerClosure(G1CollectedHeap* g1, HeapRegion* hr) : - _g1(g1), _cm(_g1->concurrent_mark()), _hr(hr), - _prev_marked_bytes(0), _next_marked_bytes(0) - {} + RemoveSelfPointerClosure(G1CollectedHeap* g1, OopsInHeapRegionClosure* cl) : + _g1(g1), _cm(_g1->concurrent_mark()), _prev_marked_bytes(0), + _next_marked_bytes(0), _cl(cl) {} size_t prev_marked_bytes() { return _prev_marked_bytes; } size_t next_marked_bytes() { return _next_marked_bytes; } @@ -2989,8 +3113,7 @@ public: // that, if evacuation fails, we might have remembered set // entries missing given that we skipped cards on the // collection set. So, we'll recreate such entries now. - RecreateRSetEntriesClosure cl(_g1, _hr); - obj->oop_iterate(&cl); + obj->oop_iterate(_cl); assert(_cm->isPrevMarked(obj), "Should be marked!"); } else { // The object has been either evacuated or is dead. Fill it with a @@ -3003,14 +3126,23 @@ public: }; void G1CollectedHeap::remove_self_forwarding_pointers() { + UpdateRSetImmediate immediate_update(_g1h); + DirtyCardQueue dcq(&_g1h->dirty_card_queue_set()); + UpdateRSetDeferred deferred_update(_g1h, &dcq); + OopsInHeapRegionClosure *cl; + if (G1DeferredRSUpdate) { + cl = &deferred_update; + } else { + cl = &immediate_update; + } HeapRegion* cur = g1_policy()->collection_set(); - while (cur != NULL) { assert(g1_policy()->assertMarkedBytesDataOK(), "Should be!"); + RemoveSelfPointerClosure rspc(_g1h, cl); if (cur->evacuation_failed()) { - RemoveSelfPointerClosure rspc(_g1h, cur); assert(cur->in_collection_set(), "bad CS"); + cl->set_region(cur); cur->object_iterate(&rspc); // A number of manipulations to make the TAMS be the current top, @@ -3519,6 +3651,9 @@ class G1ParScanThreadState : public StackObj { protected: G1CollectedHeap* _g1h; RefToScanQueue* _refs; + DirtyCardQueue _dcq; + CardTableModRefBS* _ct_bs; + G1RemSet* _g1_rem; typedef GrowableArray OverflowQueue; OverflowQueue* _overflowed_refs; @@ -3560,10 +3695,34 @@ protected: void add_to_undo_waste(size_t waste) { _undo_waste += waste; } + DirtyCardQueue& dirty_card_queue() { return _dcq; } + CardTableModRefBS* ctbs() { return _ct_bs; } + + void immediate_rs_update(HeapRegion* from, oop* p, int tid) { + if (!from->is_survivor()) { + _g1_rem->par_write_ref(from, p, tid); + } + } + + void deferred_rs_update(HeapRegion* from, oop* p, int tid) { + // If the new value of the field points to the same region or + // is the to-space, we don't need to include it in the Rset updates. + if (!from->is_in_reserved(*p) && !from->is_survivor()) { + size_t card_index = ctbs()->index_for(p); + // If the card hasn't been added to the buffer, do it. + if (ctbs()->mark_card_deferred(card_index)) { + dirty_card_queue().enqueue((jbyte*)ctbs()->byte_for_index(card_index)); + } + } + } + public: G1ParScanThreadState(G1CollectedHeap* g1h, int queue_num) : _g1h(g1h), _refs(g1h->task_queue(queue_num)), + _dcq(&g1h->dirty_card_queue_set()), + _ct_bs((CardTableModRefBS*)_g1h->barrier_set()), + _g1_rem(g1h->g1_rem_set()), _hash_seed(17), _queue_num(queue_num), _term_attempts(0), _age_table(false), @@ -3641,6 +3800,14 @@ public: int refs_to_scan() { return refs()->size(); } int overflowed_refs_to_scan() { return overflowed_refs()->length(); } + void update_rs(HeapRegion* from, oop* p, int tid) { + if (G1DeferredRSUpdate) { + deferred_rs_update(from, p, tid); + } else { + immediate_rs_update(from, p, tid); + } + } + HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz) { HeapWord* obj = NULL; @@ -3809,7 +3976,6 @@ public: } }; - G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : _g1(g1), _g1_rem(_g1->g1_rem_set()), _cm(_g1->concurrent_mark()), _par_scan_state(par_scan_state) { } @@ -3835,7 +4001,7 @@ void G1ParScanClosure::do_oop_nv(oop* p) { assert(obj == *p, "the value of *p should not have changed"); _par_scan_state->push_on_queue(p); } else { - _g1_rem->par_write_ref(_from, p, _par_scan_state->queue_num()); + _par_scan_state->update_rs(_from, p, _par_scan_state->queue_num()); } } } @@ -3973,13 +4139,13 @@ void G1ParCopyClosurepar_write_ref(_from, p, _par_scan_state->queue_num()); + _par_scan_state->update_rs(_from, p, _par_scan_state->queue_num()); } } // When scanning moved objs, must look at all oops. if (barrier == G1BarrierEvac && obj != NULL) { - _g1_rem->par_write_ref(_from, p, _par_scan_state->queue_num()); + _par_scan_state->update_rs(_from, p, _par_scan_state->queue_num()); } if (do_gen_barrier && obj != NULL) { @@ -4128,6 +4294,7 @@ public: G1ParScanExtRootClosure only_scan_root_cl(_g1h, &pss); G1ParScanPermClosure only_scan_perm_cl(_g1h, &pss); G1ParScanHeapRSClosure only_scan_heap_rs_cl(_g1h, &pss); + G1ParScanAndMarkExtRootClosure scan_mark_root_cl(_g1h, &pss); G1ParScanAndMarkPermClosure scan_mark_perm_cl(_g1h, &pss); G1ParScanAndMarkHeapRSClosure scan_mark_heap_rs_cl(_g1h, &pss); @@ -4383,7 +4550,6 @@ void G1CollectedHeap::evacuate_collection_set() { g1_rem_set()->prepare_for_oops_into_collection_set_do(); concurrent_g1_refine()->set_use_cache(false); int n_workers = (ParallelGCThreads > 0 ? workers()->total_workers() : 1); - set_par_threads(n_workers); G1ParTask g1_par_task(this, n_workers, _task_queues); @@ -4391,8 +4557,9 @@ void G1CollectedHeap::evacuate_collection_set() { change_strong_roots_parity(); // In preparation for parallel strong roots. rem_set()->prepare_for_younger_refs_iterate(true); - double start_par = os::elapsedTime(); + assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty"); + double start_par = os::elapsedTime(); if (ParallelGCThreads > 0) { // The individual threads will set their evac-failure closures. workers()->run_task(&g1_par_task); @@ -4412,8 +4579,8 @@ void G1CollectedHeap::evacuate_collection_set() { G1KeepAliveClosure keep_alive(this); JNIHandles::weak_oops_do(&is_alive, &keep_alive); } - g1_rem_set()->cleanup_after_oops_into_collection_set_do(); + concurrent_g1_refine()->set_use_cache(true); finalize_for_evac_failure(); @@ -4424,7 +4591,6 @@ void G1CollectedHeap::evacuate_collection_set() { if (evacuation_failed()) { remove_self_forwarding_pointers(); - if (PrintGCDetails) { gclog_or_tty->print(" (evacuation failed)"); } else if (PrintGC) { @@ -4432,6 +4598,14 @@ void G1CollectedHeap::evacuate_collection_set() { } } + if (G1DeferredRSUpdate) { + RedirtyLoggedCardTableEntryFastClosure redirty; + dirty_card_queue_set().set_closure(&redirty); + dirty_card_queue_set().apply_closure_to_all_completed_buffers(); + JavaThread::dirty_card_queue_set().merge_bufferlists(&dirty_card_queue_set()); + assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); + } + COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } @@ -4468,7 +4642,6 @@ G1CollectedHeap::free_region_work(HeapRegion* hr, size_t& freed_regions, UncleanRegionList* list, bool par) { - assert(!hr->popular(), "should not free popular regions"); pre_used += hr->used(); if (hr->isHumongous()) { assert(hr->startsHumongous(), @@ -4552,12 +4725,6 @@ void G1CollectedHeap::cleanUpCardTable() { void G1CollectedHeap::do_collection_pause_if_appropriate(size_t word_size) { - // First do any popular regions. - HeapRegion* hr; - while ((hr = popular_region_to_evac()) != NULL) { - evac_popular_region(hr); - } - // Now do heuristic pauses. if (g1_policy()->should_do_collection_pause(word_size)) { do_collection_pause(); } @@ -4953,7 +5120,7 @@ class RegionCounter: public HeapRegionClosure { public: RegionCounter() : _n(0) {} bool doHeapRegion(HeapRegion* r) { - if (r->is_empty() && !r->popular()) { + if (r->is_empty()) { assert(!r->isHumongous(), "H regions should not be empty."); _n++; } @@ -5097,14 +5264,8 @@ public: r->set_zero_fill_allocated(); } else { assert(r->is_empty(), "tautology"); - if (r->popular()) { - if (r->zero_fill_state() != HeapRegion::Allocated) { - r->ensure_zero_filled_locked(); - r->set_zero_fill_allocated(); - } - } else { - _n++; - switch (r->zero_fill_state()) { + _n++; + switch (r->zero_fill_state()) { case HeapRegion::NotZeroFilled: case HeapRegion::ZeroFilling: _g1->put_region_on_unclean_list_locked(r); @@ -5115,7 +5276,6 @@ public: case HeapRegion::ZeroFilled: _g1->put_free_region_on_list_locked(r); break; - } } } return false; @@ -5163,376 +5323,6 @@ void G1CollectedHeap::set_used_regions_to_need_zero_fill() { heap_region_iterate(&rs); } -class CountObjClosure: public ObjectClosure { - size_t _n; -public: - CountObjClosure() : _n(0) {} - void do_object(oop obj) { _n++; } - size_t n() { return _n; } -}; - -size_t G1CollectedHeap::pop_object_used_objs() { - size_t sum_objs = 0; - for (int i = 0; i < G1NumPopularRegions; i++) { - CountObjClosure cl; - _hrs->at(i)->object_iterate(&cl); - sum_objs += cl.n(); - } - return sum_objs; -} - -size_t G1CollectedHeap::pop_object_used_bytes() { - size_t sum_bytes = 0; - for (int i = 0; i < G1NumPopularRegions; i++) { - sum_bytes += _hrs->at(i)->used(); - } - return sum_bytes; -} - - -static int nq = 0; - -HeapWord* G1CollectedHeap::allocate_popular_object(size_t word_size) { - while (_cur_pop_hr_index < G1NumPopularRegions) { - HeapRegion* cur_pop_region = _hrs->at(_cur_pop_hr_index); - HeapWord* res = cur_pop_region->allocate(word_size); - if (res != NULL) { - // We account for popular objs directly in the used summary: - _summary_bytes_used += (word_size * HeapWordSize); - return res; - } - // Otherwise, try the next region (first making sure that we remember - // the last "top" value as the "next_top_at_mark_start", so that - // objects made popular during markings aren't automatically considered - // live). - cur_pop_region->note_end_of_copying(); - // Otherwise, try the next region. - _cur_pop_hr_index++; - } - // XXX: For now !!! - vm_exit_out_of_memory(word_size, - "Not enough pop obj space (To Be Fixed)"); - return NULL; -} - -class HeapRegionList: public CHeapObj { - public: - HeapRegion* hr; - HeapRegionList* next; -}; - -void G1CollectedHeap::schedule_popular_region_evac(HeapRegion* r) { - // This might happen during parallel GC, so protect by this lock. - MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); - // We don't schedule regions whose evacuations are already pending, or - // are already being evacuated. - if (!r->popular_pending() && !r->in_collection_set()) { - r->set_popular_pending(true); - if (G1TracePopularity) { - gclog_or_tty->print_cr("Scheduling region "PTR_FORMAT" " - "["PTR_FORMAT", "PTR_FORMAT") for pop-object evacuation.", - r, r->bottom(), r->end()); - } - HeapRegionList* hrl = new HeapRegionList; - hrl->hr = r; - hrl->next = _popular_regions_to_be_evacuated; - _popular_regions_to_be_evacuated = hrl; - } -} - -HeapRegion* G1CollectedHeap::popular_region_to_evac() { - MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); - HeapRegion* res = NULL; - while (_popular_regions_to_be_evacuated != NULL && res == NULL) { - HeapRegionList* hrl = _popular_regions_to_be_evacuated; - _popular_regions_to_be_evacuated = hrl->next; - res = hrl->hr; - // The G1RSPopLimit may have increased, so recheck here... - if (res->rem_set()->occupied() < (size_t) G1RSPopLimit) { - // Hah: don't need to schedule. - if (G1TracePopularity) { - gclog_or_tty->print_cr("Unscheduling region "PTR_FORMAT" " - "["PTR_FORMAT", "PTR_FORMAT") " - "for pop-object evacuation (size %d < limit %d)", - res, res->bottom(), res->end(), - res->rem_set()->occupied(), G1RSPopLimit); - } - res->set_popular_pending(false); - res = NULL; - } - // We do not reset res->popular() here; if we did so, it would allow - // the region to be "rescheduled" for popularity evacuation. Instead, - // this is done in the collection pause, with the world stopped. - // So the invariant is that the regions in the list have the popularity - // boolean set, but having the boolean set does not imply membership - // on the list (though there can at most one such pop-pending region - // not on the list at any time). - delete hrl; - } - return res; -} - -void G1CollectedHeap::evac_popular_region(HeapRegion* hr) { - while (true) { - // Don't want to do a GC pause while cleanup is being completed! - wait_for_cleanup_complete(); - - // Read the GC count while holding the Heap_lock - int gc_count_before = SharedHeap::heap()->total_collections(); - g1_policy()->record_stop_world_start(); - - { - MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back - VM_G1PopRegionCollectionPause op(gc_count_before, hr); - VMThread::execute(&op); - - // If the prolog succeeded, we didn't do a GC for this. - if (op.prologue_succeeded()) break; - } - // Otherwise we didn't. We should recheck the size, though, since - // the limit may have increased... - if (hr->rem_set()->occupied() < (size_t) G1RSPopLimit) { - hr->set_popular_pending(false); - break; - } - } -} - -void G1CollectedHeap::atomic_inc_obj_rc(oop obj) { - Atomic::inc(obj_rc_addr(obj)); -} - -class CountRCClosure: public OopsInHeapRegionClosure { - G1CollectedHeap* _g1h; - bool _parallel; -public: - CountRCClosure(G1CollectedHeap* g1h) : - _g1h(g1h), _parallel(ParallelGCThreads > 0) - {} - void do_oop(narrowOop* p) { - guarantee(false, "NYI"); - } - void do_oop(oop* p) { - oop obj = *p; - assert(obj != NULL, "Precondition."); - if (_parallel) { - // We go sticky at the limit to avoid excess contention. - // If we want to track the actual RC's further, we'll need to keep a - // per-thread hash table or something for the popular objects. - if (_g1h->obj_rc(obj) < G1ObjPopLimit) { - _g1h->atomic_inc_obj_rc(obj); - } - } else { - _g1h->inc_obj_rc(obj); - } - } -}; - -class EvacPopObjClosure: public ObjectClosure { - G1CollectedHeap* _g1h; - size_t _pop_objs; - size_t _max_rc; -public: - EvacPopObjClosure(G1CollectedHeap* g1h) : - _g1h(g1h), _pop_objs(0), _max_rc(0) {} - - void do_object(oop obj) { - size_t rc = _g1h->obj_rc(obj); - _max_rc = MAX2(rc, _max_rc); - if (rc >= (size_t) G1ObjPopLimit) { - _g1h->_pop_obj_rc_at_copy.add((double)rc); - size_t word_sz = obj->size(); - HeapWord* new_pop_loc = _g1h->allocate_popular_object(word_sz); - oop new_pop_obj = (oop)new_pop_loc; - Copy::aligned_disjoint_words((HeapWord*)obj, new_pop_loc, word_sz); - obj->forward_to(new_pop_obj); - G1ScanAndBalanceClosure scan_and_balance(_g1h); - new_pop_obj->oop_iterate_backwards(&scan_and_balance); - // preserve "next" mark bit if marking is in progress. - if (_g1h->mark_in_progress() && !_g1h->is_obj_ill(obj)) { - _g1h->concurrent_mark()->markAndGrayObjectIfNecessary(new_pop_obj); - } - - if (G1TracePopularity) { - gclog_or_tty->print_cr("Found obj " PTR_FORMAT " of word size " SIZE_FORMAT - " pop (%d), move to " PTR_FORMAT, - (void*) obj, word_sz, - _g1h->obj_rc(obj), (void*) new_pop_obj); - } - _pop_objs++; - } - } - size_t pop_objs() { return _pop_objs; } - size_t max_rc() { return _max_rc; } -}; - -class G1ParCountRCTask : public AbstractGangTask { - G1CollectedHeap* _g1h; - BitMap _bm; - - size_t getNCards() { - return (_g1h->capacity() + G1BlockOffsetSharedArray::N_bytes - 1) - / G1BlockOffsetSharedArray::N_bytes; - } - CountRCClosure _count_rc_closure; -public: - G1ParCountRCTask(G1CollectedHeap* g1h) : - AbstractGangTask("G1 Par RC Count task"), - _g1h(g1h), _bm(getNCards()), _count_rc_closure(g1h) - {} - - void work(int i) { - ResourceMark rm; - HandleMark hm; - _g1h->g1_rem_set()->oops_into_collection_set_do(&_count_rc_closure, i); - } -}; - -void G1CollectedHeap::popularity_pause_preamble(HeapRegion* popular_region) { - // We're evacuating a single region (for popularity). - if (G1TracePopularity) { - gclog_or_tty->print_cr("Doing pop region pause for ["PTR_FORMAT", "PTR_FORMAT")", - popular_region->bottom(), popular_region->end()); - } - g1_policy()->set_single_region_collection_set(popular_region); - size_t max_rc; - if (!compute_reference_counts_and_evac_popular(popular_region, - &max_rc)) { - // We didn't evacuate any popular objects. - // We increase the RS popularity limit, to prevent this from - // happening in the future. - if (G1RSPopLimit < (1 << 30)) { - G1RSPopLimit *= 2; - } - // For now, interesting enough for a message: -#if 1 - gclog_or_tty->print_cr("In pop region pause for ["PTR_FORMAT", "PTR_FORMAT"), " - "failed to find a pop object (max = %d).", - popular_region->bottom(), popular_region->end(), - max_rc); - gclog_or_tty->print_cr("Increased G1RSPopLimit to %d.", G1RSPopLimit); -#endif // 0 - // Also, we reset the collection set to NULL, to make the rest of - // the collection do nothing. - assert(popular_region->next_in_collection_set() == NULL, - "should be single-region."); - popular_region->set_in_collection_set(false); - popular_region->set_popular_pending(false); - g1_policy()->clear_collection_set(); - } -} - -bool G1CollectedHeap:: -compute_reference_counts_and_evac_popular(HeapRegion* popular_region, - size_t* max_rc) { - HeapWord* rc_region_bot; - HeapWord* rc_region_end; - - // Set up the reference count region. - HeapRegion* rc_region = newAllocRegion(HeapRegion::GrainWords); - if (rc_region != NULL) { - rc_region_bot = rc_region->bottom(); - rc_region_end = rc_region->end(); - } else { - rc_region_bot = NEW_C_HEAP_ARRAY(HeapWord, HeapRegion::GrainWords); - if (rc_region_bot == NULL) { - vm_exit_out_of_memory(HeapRegion::GrainWords, - "No space for RC region."); - } - rc_region_end = rc_region_bot + HeapRegion::GrainWords; - } - - if (G1TracePopularity) - gclog_or_tty->print_cr("RC region is ["PTR_FORMAT", "PTR_FORMAT")", - rc_region_bot, rc_region_end); - if (rc_region_bot > popular_region->bottom()) { - _rc_region_above = true; - _rc_region_diff = - pointer_delta(rc_region_bot, popular_region->bottom(), 1); - } else { - assert(rc_region_bot < popular_region->bottom(), "Can't be equal."); - _rc_region_above = false; - _rc_region_diff = - pointer_delta(popular_region->bottom(), rc_region_bot, 1); - } - g1_policy()->record_pop_compute_rc_start(); - // Count external references. - g1_rem_set()->prepare_for_oops_into_collection_set_do(); - if (ParallelGCThreads > 0) { - - set_par_threads(workers()->total_workers()); - G1ParCountRCTask par_count_rc_task(this); - workers()->run_task(&par_count_rc_task); - set_par_threads(0); - - } else { - CountRCClosure count_rc_closure(this); - g1_rem_set()->oops_into_collection_set_do(&count_rc_closure, 0); - } - g1_rem_set()->cleanup_after_oops_into_collection_set_do(); - g1_policy()->record_pop_compute_rc_end(); - - // Now evacuate popular objects. - g1_policy()->record_pop_evac_start(); - EvacPopObjClosure evac_pop_obj_cl(this); - popular_region->object_iterate(&evac_pop_obj_cl); - *max_rc = evac_pop_obj_cl.max_rc(); - - // Make sure the last "top" value of the current popular region is copied - // as the "next_top_at_mark_start", so that objects made popular during - // markings aren't automatically considered live. - HeapRegion* cur_pop_region = _hrs->at(_cur_pop_hr_index); - cur_pop_region->note_end_of_copying(); - - if (rc_region != NULL) { - free_region(rc_region); - } else { - FREE_C_HEAP_ARRAY(HeapWord, rc_region_bot); - } - g1_policy()->record_pop_evac_end(); - - return evac_pop_obj_cl.pop_objs() > 0; -} - -class CountPopObjInfoClosure: public HeapRegionClosure { - size_t _objs; - size_t _bytes; - - class CountObjClosure: public ObjectClosure { - int _n; - public: - CountObjClosure() : _n(0) {} - void do_object(oop obj) { _n++; } - size_t n() { return _n; } - }; - -public: - CountPopObjInfoClosure() : _objs(0), _bytes(0) {} - bool doHeapRegion(HeapRegion* r) { - _bytes += r->used(); - CountObjClosure blk; - r->object_iterate(&blk); - _objs += blk.n(); - return false; - } - size_t objs() { return _objs; } - size_t bytes() { return _bytes; } -}; - - -void G1CollectedHeap::print_popularity_summary_info() const { - CountPopObjInfoClosure blk; - for (int i = 0; i <= _cur_pop_hr_index; i++) { - blk.doHeapRegion(_hrs->at(i)); - } - gclog_or_tty->print_cr("\nPopular objects: %d objs, %d bytes.", - blk.objs(), blk.bytes()); - gclog_or_tty->print_cr(" RC at copy = [avg = %5.2f, max = %5.2f, sd = %5.2f].", - _pop_obj_rc_at_copy.avg(), - _pop_obj_rc_at_copy.maximum(), - _pop_obj_rc_at_copy.sd()); -} - void G1CollectedHeap::set_refine_cte_cl_concurrency(bool concurrent) { _refine_cte_cl->set_concurrent(concurrent); } @@ -5606,7 +5396,6 @@ bool G1CollectedHeap::regions_accounted_for() { } bool G1CollectedHeap::print_region_accounting_info() { - gclog_or_tty->print_cr("P regions: %d.", G1NumPopularRegions); gclog_or_tty->print_cr("Free regions: %d (count: %d count list %d) (clean: %d unclean: %d).", free_regions(), count_free_regions(), count_free_regions_list(), diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 2e139b7f2d2..c0eca678db8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ class HeapRegion; class HeapRegionSeq; -class HeapRegionList; class PermanentGenerationSpec; class GenerationSpec; class OopsInHeapRegionClosure; @@ -143,7 +142,6 @@ class G1CollectedHeap : public SharedHeap { friend class VM_GenCollectForPermanentAllocation; friend class VM_G1CollectFull; friend class VM_G1IncCollectionPause; - friend class VM_G1PopRegionCollectionPause; friend class VMStructs; // Closures used in implementation. @@ -172,7 +170,6 @@ private: NumAPIs = HeapRegion::MaxAge }; - // The one and only G1CollectedHeap, so static functions can find it. static G1CollectedHeap* _g1h; @@ -217,11 +214,20 @@ private: // Postcondition: cur_alloc_region == NULL. void abandon_cur_alloc_region(); + void abandon_gc_alloc_regions(); // The to-space memory regions into which objects are being copied during // a GC. HeapRegion* _gc_alloc_regions[GCAllocPurposeCount]; size_t _gc_alloc_region_counts[GCAllocPurposeCount]; + // These are the regions, one per GCAllocPurpose, that are half-full + // at the end of a collection and that we want to reuse during the + // next collection. + HeapRegion* _retained_gc_alloc_regions[GCAllocPurposeCount]; + // This specifies whether we will keep the last half-full region at + // the end of a collection so that it can be reused during the next + // collection (this is specified per GCAllocPurpose) + bool _retain_gc_alloc_region[GCAllocPurposeCount]; // A list of the regions that have been set to be alloc regions in the // current collection. @@ -245,10 +251,6 @@ private: // than the current allocation region. size_t _summary_bytes_used; - // Summary information about popular objects; method to print it. - NumberSeq _pop_obj_rc_at_copy; - void print_popularity_summary_info() const; - // This is used for a quick test on whether a reference points into // the collection set or not. Basically, we have an array, with one // byte per region, and that byte denotes whether the corresponding @@ -439,10 +441,8 @@ protected: virtual void do_collection_pause(); // The guts of the incremental collection pause, executed by the vm - // thread. If "popular_region" is non-NULL, this pause should evacuate - // this single region whose remembered set has gotten large, moving - // any popular objects to one of the popular regions. - virtual void do_collection_pause_at_safepoint(HeapRegion* popular_region); + // thread. + virtual void do_collection_pause_at_safepoint(); // Actually do the work of evacuating the collection set. virtual void evacuate_collection_set(); @@ -457,6 +457,10 @@ protected: // And it's mod ref barrier set, used to track updates for the above. ModRefBarrierSet* _mr_bs; + // A set of cards that cover the objects for which the Rsets should be updated + // concurrently after the collection. + DirtyCardQueueSet _dirty_card_queue_set; + // The Heap Region Rem Set Iterator. HeapRegionRemSetIterator** _rem_set_iterator; @@ -585,8 +589,21 @@ protected: // Ensure that the relevant gc_alloc regions are set. void get_gc_alloc_regions(); - // We're done with GC alloc regions; release them, as appropriate. - void release_gc_alloc_regions(); + // We're done with GC alloc regions. We are going to tear down the + // gc alloc list and remove the gc alloc tag from all the regions on + // that list. However, we will also retain the last (i.e., the one + // that is half-full) GC alloc region, per GCAllocPurpose, for + // possible reuse during the next collection, provided + // _retain_gc_alloc_region[] indicates that it should be the + // case. Said regions are kept in the _retained_gc_alloc_regions[] + // array. If the parameter totally is set, we will not retain any + // regions, irrespective of what _retain_gc_alloc_region[] + // indicates. + void release_gc_alloc_regions(bool totally); +#ifndef PRODUCT + // Useful for debugging. + void print_gc_alloc_regions(); +#endif // !PRODUCT // ("Weak") Reference processing support ReferenceProcessor* _ref_processor; @@ -600,72 +617,18 @@ protected: SubTasksDone* _process_strong_tasks; - // Allocate space to hold a popular object. Result is guaranteed below - // "popular_object_boundary()". Note: CURRENTLY halts the system if we - // run out of space to hold popular objects. - HeapWord* allocate_popular_object(size_t word_size); - - // The boundary between popular and non-popular objects. - HeapWord* _popular_object_boundary; - - HeapRegionList* _popular_regions_to_be_evacuated; - - // Compute which objects in "single_region" are popular. If any are, - // evacuate them to a popular region, leaving behind forwarding pointers, - // and select "popular_region" as the single collection set region. - // Otherwise, leave the collection set null. - void popularity_pause_preamble(HeapRegion* populer_region); - - // Compute which objects in "single_region" are popular, and evacuate - // them to a popular region, leaving behind forwarding pointers. - // Returns "true" if at least one popular object is discovered and - // evacuated. In any case, "*max_rc" is set to the maximum reference - // count of an object in the region. - bool compute_reference_counts_and_evac_popular(HeapRegion* populer_region, - size_t* max_rc); - // Subroutines used in the above. - bool _rc_region_above; - size_t _rc_region_diff; - jint* obj_rc_addr(oop obj) { - uintptr_t obj_addr = (uintptr_t)obj; - if (_rc_region_above) { - jint* res = (jint*)(obj_addr + _rc_region_diff); - assert((uintptr_t)res > obj_addr, "RC region is above."); - return res; - } else { - jint* res = (jint*)(obj_addr - _rc_region_diff); - assert((uintptr_t)res < obj_addr, "RC region is below."); - return res; - } - } - jint obj_rc(oop obj) { - return *obj_rc_addr(obj); - } - void inc_obj_rc(oop obj) { - (*obj_rc_addr(obj))++; - } - void atomic_inc_obj_rc(oop obj); - - - // Number of popular objects and bytes (latter is cheaper!). - size_t pop_object_used_objs(); - size_t pop_object_used_bytes(); - - // Index of the popular region in which allocation is currently being - // done. - int _cur_pop_hr_index; - // List of regions which require zero filling. UncleanRegionList _unclean_region_list; bool _unclean_regions_coming; - bool check_age_cohort_well_formed_work(int a, HeapRegion* hr); - public: void set_refine_cte_cl_concurrency(bool concurrent); RefToScanQueue *task_queue(int i); + // A set of cards where updates happened during the GC + DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; } + // Create a G1CollectedHeap with the specified policy. // Must call the initialize method afterwards. // May not return if something goes wrong. @@ -902,14 +865,25 @@ public: // Iterate over all the ref-containing fields of all objects, calling // "cl.do_oop" on each. - virtual void oop_iterate(OopClosure* cl); + virtual void oop_iterate(OopClosure* cl) { + oop_iterate(cl, true); + } + void oop_iterate(OopClosure* cl, bool do_perm); // Same as above, restricted to a memory region. - virtual void oop_iterate(MemRegion mr, OopClosure* cl); + virtual void oop_iterate(MemRegion mr, OopClosure* cl) { + oop_iterate(mr, cl, true); + } + void oop_iterate(MemRegion mr, OopClosure* cl, bool do_perm); // Iterate over all objects, calling "cl.do_object" on each. - virtual void object_iterate(ObjectClosure* cl); - virtual void safe_object_iterate(ObjectClosure* cl) { object_iterate(cl); } + virtual void object_iterate(ObjectClosure* cl) { + object_iterate(cl, true); + } + virtual void safe_object_iterate(ObjectClosure* cl) { + object_iterate(cl, true); + } + void object_iterate(ObjectClosure* cl, bool do_perm); // Iterate over all objects allocated since the last collection, calling // "cl.do_object" on each. The heap must have been initialized properly @@ -1038,21 +1012,6 @@ public: // words. virtual size_t large_typearray_limit(); - // All popular objects are guaranteed to have addresses below this - // boundary. - HeapWord* popular_object_boundary() { - return _popular_object_boundary; - } - - // Declare the region as one that should be evacuated because its - // remembered set is too large. - void schedule_popular_region_evac(HeapRegion* r); - // If there is a popular region to evacuate it, remove it from the list - // and return it. - HeapRegion* popular_region_to_evac(); - // Evacuate the given popular region. - void evac_popular_region(HeapRegion* r); - // Returns "true" iff the given word_size is "very large". static bool isHumongous(size_t word_size) { return word_size >= VeryLargeInWords; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp index 4d88ee4cbb6..d022044e0b0 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 949e3f99700..d259ad38ea0 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,10 +91,8 @@ G1CollectorPolicy::G1CollectorPolicy() : _all_mod_union_times_ms(new NumberSeq()), - _non_pop_summary(new NonPopSummary()), - _pop_summary(new PopSummary()), - _non_pop_abandoned_summary(new NonPopAbandonedSummary()), - _pop_abandoned_summary(new PopAbandonedSummary()), + _summary(new Summary()), + _abandoned_summary(new AbandonedSummary()), _cur_clear_ct_time_ms(0.0), @@ -109,9 +107,6 @@ G1CollectorPolicy::G1CollectorPolicy() : _cur_aux_times_ms(new double[_aux_num]), _cur_aux_times_set(new bool[_aux_num]), - _pop_compute_rc_start(0.0), - _pop_evac_start(0.0), - _concurrent_mark_init_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), _concurrent_mark_remark_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), _concurrent_mark_cleanup_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), @@ -224,16 +219,6 @@ G1CollectorPolicy::G1CollectorPolicy() : _par_last_termination_times_ms = new double[_parallel_gc_threads]; - // we store the data from the first pass during popularity pauses - _pop_par_last_update_rs_start_times_ms = new double[_parallel_gc_threads]; - _pop_par_last_update_rs_times_ms = new double[_parallel_gc_threads]; - _pop_par_last_update_rs_processed_buffers = new double[_parallel_gc_threads]; - - _pop_par_last_scan_rs_start_times_ms = new double[_parallel_gc_threads]; - _pop_par_last_scan_rs_times_ms = new double[_parallel_gc_threads]; - - _pop_par_last_closure_app_times_ms = new double[_parallel_gc_threads]; - // start conservatively _expensive_region_limit_ms = 0.5 * (double) G1MaxPauseTimeMS; @@ -1014,7 +999,7 @@ void G1CollectorPolicy::record_full_collection_end() { _all_full_gc_times_ms->add(full_gc_time_ms); - update_recent_gc_times(end_sec, full_gc_time_sec); + update_recent_gc_times(end_sec, full_gc_time_ms); _g1->clear_full_collection(); @@ -1047,23 +1032,6 @@ void G1CollectorPolicy::record_full_collection_end() { calculate_young_list_target_config(); } -void G1CollectorPolicy::record_pop_compute_rc_start() { - _pop_compute_rc_start = os::elapsedTime(); -} -void G1CollectorPolicy::record_pop_compute_rc_end() { - double ms = (os::elapsedTime() - _pop_compute_rc_start)*1000.0; - _cur_popular_compute_rc_time_ms = ms; - _pop_compute_rc_start = 0.0; -} -void G1CollectorPolicy::record_pop_evac_start() { - _pop_evac_start = os::elapsedTime(); -} -void G1CollectorPolicy::record_pop_evac_end() { - double ms = (os::elapsedTime() - _pop_evac_start)*1000.0; - _cur_popular_evac_time_ms = ms; - _pop_evac_start = 0.0; -} - void G1CollectorPolicy::record_before_bytes(size_t bytes) { _bytes_in_to_space_before_gc += bytes; } @@ -1087,6 +1055,7 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec, assert(_g1->used_regions() == _g1->recalculate_used_regions(), "sanity"); + assert(_g1->used() == _g1->recalculate_used(), "sanity"); double s_w_t_ms = (start_time_sec - _stop_world_start) * 1000.0; _all_stop_world_times_ms->add(s_w_t_ms); @@ -1119,13 +1088,6 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec, _par_last_scan_new_refs_times_ms[i] = -666.0; _par_last_obj_copy_times_ms[i] = -666.0; _par_last_termination_times_ms[i] = -666.0; - - _pop_par_last_update_rs_start_times_ms[i] = -666.0; - _pop_par_last_update_rs_times_ms[i] = -666.0; - _pop_par_last_update_rs_processed_buffers[i] = -666.0; - _pop_par_last_scan_rs_start_times_ms[i] = -666.0; - _pop_par_last_scan_rs_times_ms[i] = -666.0; - _pop_par_last_closure_app_times_ms[i] = -666.0; } #endif @@ -1184,25 +1146,6 @@ void G1CollectorPolicy::tag_scan_only(size_t short_lived_scan_only_length) { guarantee( false, "we should never reach here" ); } -void G1CollectorPolicy::record_popular_pause_preamble_start() { - _cur_popular_preamble_start_ms = os::elapsedTime() * 1000.0; -} - -void G1CollectorPolicy::record_popular_pause_preamble_end() { - _cur_popular_preamble_time_ms = - (os::elapsedTime() * 1000.0) - _cur_popular_preamble_start_ms; - - // copy the recorded statistics of the first pass to temporary arrays - for (int i = 0; i < _parallel_gc_threads; ++i) { - _pop_par_last_update_rs_start_times_ms[i] = _par_last_update_rs_start_times_ms[i]; - _pop_par_last_update_rs_times_ms[i] = _par_last_update_rs_times_ms[i]; - _pop_par_last_update_rs_processed_buffers[i] = _par_last_update_rs_processed_buffers[i]; - _pop_par_last_scan_rs_start_times_ms[i] = _par_last_scan_rs_start_times_ms[i]; - _pop_par_last_scan_rs_times_ms[i] = _par_last_scan_rs_times_ms[i]; - _pop_par_last_closure_app_times_ms[i] = _par_last_obj_copy_times_ms[i]; - } -} - void G1CollectorPolicy::record_mark_closure_time(double mark_closure_time_ms) { _mark_closure_time_ms = mark_closure_time_ms; } @@ -1464,8 +1407,7 @@ double G1CollectorPolicy::max_sum (double* data1, // Anything below that is considered to be zero #define MIN_TIMER_GRANULARITY 0.0000001 -void G1CollectorPolicy::record_collection_pause_end(bool popular, - bool abandoned) { +void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { double end_time_sec = os::elapsedTime(); double elapsed_ms = _last_pause_time_ms; bool parallel = ParallelGCThreads > 0; @@ -1475,6 +1417,7 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, size_t cur_used_bytes = _g1->used(); assert(cur_used_bytes == _g1->recalculate_used(), "It should!"); bool last_pause_included_initial_mark = false; + bool update_stats = !abandoned && !_g1->evacuation_failed(); #ifndef PRODUCT if (G1YoungSurvRateVerbose) { @@ -1535,7 +1478,7 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, _n_pauses++; - if (!abandoned) { + if (update_stats) { _recent_CH_strong_roots_times_ms->add(_cur_CH_strong_roots_dur_ms); _recent_G1_strong_roots_times_ms->add(_cur_G1_strong_roots_dur_ms); _recent_evac_times_ms->add(evac_ms); @@ -1585,42 +1528,10 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, } PauseSummary* summary; - if (!abandoned && !popular) - summary = _non_pop_summary; - else if (!abandoned && popular) - summary = _pop_summary; - else if (abandoned && !popular) - summary = _non_pop_abandoned_summary; - else if (abandoned && popular) - summary = _pop_abandoned_summary; - else - guarantee(false, "should not get here!"); - - double pop_update_rs_time; - double pop_update_rs_processed_buffers; - double pop_scan_rs_time; - double pop_closure_app_time; - double pop_other_time; - - if (popular) { - PopPreambleSummary* preamble_summary = summary->pop_preamble_summary(); - guarantee(preamble_summary != NULL, "should not be null!"); - - pop_update_rs_time = avg_value(_pop_par_last_update_rs_times_ms); - pop_update_rs_processed_buffers = - sum_of_values(_pop_par_last_update_rs_processed_buffers); - pop_scan_rs_time = avg_value(_pop_par_last_scan_rs_times_ms); - pop_closure_app_time = avg_value(_pop_par_last_closure_app_times_ms); - pop_other_time = _cur_popular_preamble_time_ms - - (pop_update_rs_time + pop_scan_rs_time + pop_closure_app_time + - _cur_popular_evac_time_ms); - - preamble_summary->record_pop_preamble_time_ms(_cur_popular_preamble_time_ms); - preamble_summary->record_pop_update_rs_time_ms(pop_update_rs_time); - preamble_summary->record_pop_scan_rs_time_ms(pop_scan_rs_time); - preamble_summary->record_pop_closure_app_time_ms(pop_closure_app_time); - preamble_summary->record_pop_evacuation_time_ms(_cur_popular_evac_time_ms); - preamble_summary->record_pop_other_time_ms(pop_other_time); + if (abandoned) { + summary = _abandoned_summary; + } else { + summary = _summary; } double ext_root_scan_time = avg_value(_par_last_ext_root_scan_times_ms); @@ -1635,8 +1546,10 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, double obj_copy_time = avg_value(_par_last_obj_copy_times_ms); double termination_time = avg_value(_par_last_termination_times_ms); - double parallel_other_time; - if (!abandoned) { + double parallel_other_time = _cur_collection_par_time_ms - + (update_rs_time + ext_root_scan_time + mark_stack_scan_time + + scan_only_time + scan_rs_time + obj_copy_time + termination_time); + if (update_stats) { MainBodySummary* body_summary = summary->main_body_summary(); guarantee(body_summary != NULL, "should not be null!"); @@ -1654,9 +1567,6 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, body_summary->record_parallel_time_ms(_cur_collection_par_time_ms); body_summary->record_clear_ct_time_ms(_cur_clear_ct_time_ms); body_summary->record_termination_time_ms(termination_time); - parallel_other_time = _cur_collection_par_time_ms - - (update_rs_time + ext_root_scan_time + mark_stack_scan_time + - scan_only_time + scan_rs_time + obj_copy_time + termination_time); body_summary->record_parallel_other_time_ms(parallel_other_time); } body_summary->record_mark_closure_time_ms(_mark_closure_time_ms); @@ -1693,8 +1603,6 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, } double other_time_ms = elapsed_ms; - if (popular) - other_time_ms -= _cur_popular_preamble_time_ms; if (!abandoned) { if (_satb_drain_time_set) @@ -1711,41 +1619,24 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, if (PrintGCDetails) { gclog_or_tty->print_cr("%s%s, %1.8lf secs]", - (popular && !abandoned) ? " (popular)" : - (!popular && abandoned) ? " (abandoned)" : - (popular && abandoned) ? " (popular/abandoned)" : "", + abandoned ? " (abandoned)" : "", (last_pause_included_initial_mark) ? " (initial-mark)" : "", elapsed_ms / 1000.0); if (!abandoned) { - if (_satb_drain_time_set) + if (_satb_drain_time_set) { print_stats(1, "SATB Drain Time", _cur_satb_drain_time_ms); - if (_last_satb_drain_processed_buffers >= 0) + } + if (_last_satb_drain_processed_buffers >= 0) { print_stats(2, "Processed Buffers", _last_satb_drain_processed_buffers); - } - if (popular) - print_stats(1, "Popularity Preamble", _cur_popular_preamble_time_ms); - if (parallel) { - if (popular) { - print_par_stats(2, "Update RS (Start)", _pop_par_last_update_rs_start_times_ms, false); - print_par_stats(2, "Update RS", _pop_par_last_update_rs_times_ms); + } + if (parallel) { + print_stats(1, "Parallel Time", _cur_collection_par_time_ms); + print_par_stats(2, "Update RS (Start)", _par_last_update_rs_start_times_ms, false); + print_par_stats(2, "Update RS", _par_last_update_rs_times_ms); if (G1RSBarrierUseQueue) print_par_buffers(3, "Processed Buffers", - _pop_par_last_update_rs_processed_buffers, true); - print_par_stats(2, "Scan RS", _pop_par_last_scan_rs_times_ms); - print_par_stats(2, "Closure app", _pop_par_last_closure_app_times_ms); - print_stats(2, "Evacuation", _cur_popular_evac_time_ms); - print_stats(2, "Other", pop_other_time); - } - if (!abandoned) { - print_stats(1, "Parallel Time", _cur_collection_par_time_ms); - if (!popular) { - print_par_stats(2, "Update RS (Start)", _par_last_update_rs_start_times_ms, false); - print_par_stats(2, "Update RS", _par_last_update_rs_times_ms); - if (G1RSBarrierUseQueue) - print_par_buffers(3, "Processed Buffers", - _par_last_update_rs_processed_buffers, true); - } + _par_last_update_rs_processed_buffers, true); print_par_stats(2, "Ext Root Scanning", _par_last_ext_root_scan_times_ms); print_par_stats(2, "Mark Stack Scanning", _par_last_mark_stack_scan_times_ms); print_par_stats(2, "Scan-Only Scanning", _par_last_scan_only_times_ms); @@ -1756,25 +1647,11 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, print_par_stats(2, "Termination", _par_last_termination_times_ms); print_stats(2, "Other", parallel_other_time); print_stats(1, "Clear CT", _cur_clear_ct_time_ms); - } - } else { - if (popular) { - print_stats(2, "Update RS", pop_update_rs_time); + } else { + print_stats(1, "Update RS", update_rs_time); if (G1RSBarrierUseQueue) - print_stats(3, "Processed Buffers", - (int)pop_update_rs_processed_buffers); - print_stats(2, "Scan RS", pop_scan_rs_time); - print_stats(2, "Closure App", pop_closure_app_time); - print_stats(2, "Evacuation", _cur_popular_evac_time_ms); - print_stats(2, "Other", pop_other_time); - } - if (!abandoned) { - if (!popular) { - print_stats(1, "Update RS", update_rs_time); - if (G1RSBarrierUseQueue) - print_stats(2, "Processed Buffers", - (int)update_rs_processed_buffers); - } + print_stats(2, "Processed Buffers", + (int)update_rs_processed_buffers); print_stats(1, "Ext Root Scanning", ext_root_scan_time); print_stats(1, "Mark Stack Scanning", mark_stack_scan_time); print_stats(1, "Scan-Only Scanning", scan_only_time); @@ -1801,8 +1678,10 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, gclog_or_tty->print_cr("]"); _all_pause_times_ms->add(elapsed_ms); - summary->record_total_time_ms(elapsed_ms); - summary->record_other_time_ms(other_time_ms); + if (update_stats) { + summary->record_total_time_ms(elapsed_ms); + summary->record_other_time_ms(other_time_ms); + } for (int i = 0; i < _aux_num; ++i) if (_cur_aux_times_set[i]) _all_aux_times_ms[i].add(_cur_aux_times_ms[i]); @@ -1852,7 +1731,7 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, // - if (!popular && !abandoned) { + if (update_stats) { double pause_time_ms = elapsed_ms; size_t diff = 0; @@ -2451,36 +2330,8 @@ void G1CollectorPolicy::check_other_times(int level, void G1CollectorPolicy::print_summary(PauseSummary* summary) const { bool parallel = ParallelGCThreads > 0; MainBodySummary* body_summary = summary->main_body_summary(); - PopPreambleSummary* preamble_summary = summary->pop_preamble_summary(); - if (summary->get_total_seq()->num() > 0) { - print_summary_sd(0, - (preamble_summary == NULL) ? "Non-Popular Pauses" : - "Popular Pauses", - summary->get_total_seq()); - if (preamble_summary != NULL) { - print_summary(1, "Popularity Preamble", - preamble_summary->get_pop_preamble_seq()); - print_summary(2, "Update RS", preamble_summary->get_pop_update_rs_seq()); - print_summary(2, "Scan RS", preamble_summary->get_pop_scan_rs_seq()); - print_summary(2, "Closure App", - preamble_summary->get_pop_closure_app_seq()); - print_summary(2, "Evacuation", - preamble_summary->get_pop_evacuation_seq()); - print_summary(2, "Other", preamble_summary->get_pop_other_seq()); - { - NumberSeq* other_parts[] = { - preamble_summary->get_pop_update_rs_seq(), - preamble_summary->get_pop_scan_rs_seq(), - preamble_summary->get_pop_closure_app_seq(), - preamble_summary->get_pop_evacuation_seq() - }; - NumberSeq calc_other_times_ms(preamble_summary->get_pop_preamble_seq(), - 4, other_parts); - check_other_times(2, preamble_summary->get_pop_other_seq(), - &calc_other_times_ms); - } - } + print_summary_sd(0, "Evacuation Pauses", summary->get_total_seq()); if (body_summary != NULL) { print_summary(1, "SATB Drain", body_summary->get_satb_drain_seq()); if (parallel) { @@ -2534,19 +2385,15 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { // parallel NumberSeq* other_parts[] = { body_summary->get_satb_drain_seq(), - (preamble_summary == NULL) ? NULL : - preamble_summary->get_pop_preamble_seq(), body_summary->get_parallel_seq(), body_summary->get_clear_ct_seq() }; - calc_other_times_ms = NumberSeq (summary->get_total_seq(), - 4, other_parts); + calc_other_times_ms = NumberSeq(summary->get_total_seq(), + 3, other_parts); } else { // serial NumberSeq* other_parts[] = { body_summary->get_satb_drain_seq(), - (preamble_summary == NULL) ? NULL : - preamble_summary->get_pop_preamble_seq(), body_summary->get_update_rs_seq(), body_summary->get_ext_root_scan_seq(), body_summary->get_mark_stack_scan_seq(), @@ -2555,16 +2402,11 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { body_summary->get_obj_copy_seq() }; calc_other_times_ms = NumberSeq(summary->get_total_seq(), - 8, other_parts); + 7, other_parts); } } else { // abandoned - NumberSeq* other_parts[] = { - (preamble_summary == NULL) ? NULL : - preamble_summary->get_pop_preamble_seq() - }; - calc_other_times_ms = NumberSeq(summary->get_total_seq(), - 1, other_parts); + calc_other_times_ms = NumberSeq(); } check_other_times(1, summary->get_other_seq(), &calc_other_times_ms); } @@ -2576,18 +2418,12 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { } void -G1CollectorPolicy::print_abandoned_summary(PauseSummary* non_pop_summary, - PauseSummary* pop_summary) const { +G1CollectorPolicy::print_abandoned_summary(PauseSummary* summary) const { bool printed = false; - if (non_pop_summary->get_total_seq()->num() > 0) { + if (summary->get_total_seq()->num() > 0) { printed = true; - print_summary(non_pop_summary); + print_summary(summary); } - if (pop_summary->get_total_seq()->num() > 0) { - printed = true; - print_summary(pop_summary); - } - if (!printed) { print_indent(0); gclog_or_tty->print_cr("none"); @@ -2605,15 +2441,11 @@ void G1CollectorPolicy::print_tracing_info() const { gclog_or_tty->print_cr(" Partial Young GC Pauses: %8d", _partial_young_pause_num); gclog_or_tty->print_cr(""); - gclog_or_tty->print_cr("NON-POPULAR PAUSES"); - print_summary(_non_pop_summary); - - gclog_or_tty->print_cr("POPULAR PAUSES"); - print_summary(_pop_summary); + gclog_or_tty->print_cr("EVACUATION PAUSES"); + print_summary(_summary); gclog_or_tty->print_cr("ABANDONED PAUSES"); - print_abandoned_summary(_non_pop_abandoned_summary, - _pop_abandoned_summary); + print_abandoned_summary(_abandoned_summary); gclog_or_tty->print_cr("MISC"); print_summary_sd(0, "Stop World", _all_stop_world_times_ms); @@ -2699,14 +2531,6 @@ void G1CollectorPolicy::update_conc_refine_data() { _conc_refine_enabled++; } -void G1CollectorPolicy::set_single_region_collection_set(HeapRegion* hr) { - assert(collection_set() == NULL, "Must be no current CS."); - _collection_set_size = 0; - _collection_set_bytes_used_before = 0; - add_to_collection_set(hr); - count_CS_bytes_used(); -} - bool G1CollectorPolicy::should_add_next_region_to_young_list() { assert(in_young_gc_mode(), "should be in young GC mode"); @@ -2784,15 +2608,6 @@ void G1CollectorPolicy::calculate_survivors_policy() } } - -void -G1CollectorPolicy_BestRegionsFirst:: -set_single_region_collection_set(HeapRegion* hr) { - G1CollectorPolicy::set_single_region_collection_set(hr); - _collectionSetChooser->removeRegion(hr); -} - - bool G1CollectorPolicy_BestRegionsFirst::should_do_collection_pause(size_t word_size) { @@ -3058,19 +2873,13 @@ add_to_collection_set(HeapRegion* hr) { void G1CollectorPolicy_BestRegionsFirst:: -choose_collection_set(HeapRegion* pop_region) { +choose_collection_set() { double non_young_start_time_sec; start_recording_regions(); - if (pop_region != NULL) { - _target_pause_time_ms = (double) G1MaxPauseTimeMS; - } else { - guarantee(_target_pause_time_ms > -1.0, - "_target_pause_time_ms should have been set!"); - } - - // pop region is either null (and so is CS), or else it *is* the CS. - assert(_collection_set == pop_region, "Precondition"); + guarantee(_target_pause_time_ms > -1.0, + "_target_pause_time_ms should have been set!"); + assert(_collection_set == NULL, "Precondition"); double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); double predicted_pause_time_ms = base_time_ms; @@ -3097,15 +2906,13 @@ choose_collection_set(HeapRegion* pop_region) { size_t expansion_bytes = _g1->expansion_regions() * HeapRegion::GrainBytes; - if (pop_region == NULL) { - _collection_set_bytes_used_before = 0; - _collection_set_size = 0; - } + _collection_set_bytes_used_before = 0; + _collection_set_size = 0; // Adjust for expansion and slop. max_live_bytes = max_live_bytes + expansion_bytes; - assert(pop_region != NULL || _g1->regions_accounted_for(), "Region leakage!"); + assert(_g1->regions_accounted_for(), "Region leakage!"); HeapRegion* hr; if (in_young_gc_mode()) { @@ -3132,14 +2939,9 @@ choose_collection_set(HeapRegion* pop_region) { double predicted_time_ms = predict_region_elapsed_time_ms(hr, true); time_remaining_ms -= predicted_time_ms; predicted_pause_time_ms += predicted_time_ms; - if (hr == pop_region) { - // The popular region was young. Skip over it. - assert(hr->in_collection_set(), "It's the pop region."); - } else { - assert(!hr->in_collection_set(), "It's not the pop region."); - add_to_collection_set(hr); - record_cset_region(hr, true); - } + assert(!hr->in_collection_set(), "invariant"); + add_to_collection_set(hr); + record_cset_region(hr, true); max_live_bytes -= MIN2(hr->max_live_bytes(), max_live_bytes); if (G1PolicyVerbose > 0) { gclog_or_tty->print_cr(" Added [" PTR_FORMAT ", " PTR_FORMAT") to CS.", @@ -3162,10 +2964,6 @@ choose_collection_set(HeapRegion* pop_region) { // don't bother adding more regions... goto choose_collection_set_end; } - } else if (pop_region != NULL) { - // We're not in young mode, and we chose a popular region; don't choose - // any more. - return; } if (!in_young_gc_mode() || !full_young_gcs()) { @@ -3175,7 +2973,7 @@ choose_collection_set(HeapRegion* pop_region) { do { hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms, avg_prediction); - if (hr != NULL && !hr->popular()) { + if (hr != NULL) { double predicted_time_ms = predict_region_elapsed_time_ms(hr, false); time_remaining_ms -= predicted_time_ms; predicted_pause_time_ms += predicted_time_ms; @@ -3222,8 +3020,8 @@ expand_if_possible(size_t numRegions) { } void G1CollectorPolicy_BestRegionsFirst:: -record_collection_pause_end(bool popular, bool abandoned) { - G1CollectorPolicy::record_collection_pause_end(popular, abandoned); +record_collection_pause_end(bool abandoned) { + G1CollectorPolicy::record_collection_pause_end(abandoned); assert(assertMarkedBytesDataOK(), "Marked regions not OK at pause end."); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index 1649584cd31..3043b7b674e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,6 @@ public: \ } class MainBodySummary; -class PopPreambleSummary; class PauseSummary: public CHeapObj { define_num_seq(total) @@ -55,7 +54,6 @@ class PauseSummary: public CHeapObj { public: virtual MainBodySummary* main_body_summary() { return NULL; } - virtual PopPreambleSummary* pop_preamble_summary() { return NULL; } }; class MainBodySummary: public CHeapObj { @@ -75,36 +73,13 @@ class MainBodySummary: public CHeapObj { define_num_seq(clear_ct) // parallel only }; -class PopPreambleSummary: public CHeapObj { - define_num_seq(pop_preamble) - define_num_seq(pop_update_rs) - define_num_seq(pop_scan_rs) - define_num_seq(pop_closure_app) - define_num_seq(pop_evacuation) - define_num_seq(pop_other) -}; - -class NonPopSummary: public PauseSummary, - public MainBodySummary { +class Summary: public PauseSummary, + public MainBodySummary { public: virtual MainBodySummary* main_body_summary() { return this; } }; -class PopSummary: public PauseSummary, - public MainBodySummary, - public PopPreambleSummary { -public: - virtual MainBodySummary* main_body_summary() { return this; } - virtual PopPreambleSummary* pop_preamble_summary() { return this; } -}; - -class NonPopAbandonedSummary: public PauseSummary { -}; - -class PopAbandonedSummary: public PauseSummary, - public PopPreambleSummary { -public: - virtual PopPreambleSummary* pop_preamble_summary() { return this; } +class AbandonedSummary: public PauseSummary { }; class G1CollectorPolicy: public CollectorPolicy { @@ -146,10 +121,6 @@ protected: double _cur_satb_drain_time_ms; double _cur_clear_ct_time_ms; bool _satb_drain_time_set; - double _cur_popular_preamble_start_ms; - double _cur_popular_preamble_time_ms; - double _cur_popular_compute_rc_time_ms; - double _cur_popular_evac_time_ms; double _cur_CH_strong_roots_end_sec; double _cur_CH_strong_roots_dur_ms; @@ -173,10 +144,8 @@ protected: TruncatedSeq* _concurrent_mark_remark_times_ms; TruncatedSeq* _concurrent_mark_cleanup_times_ms; - NonPopSummary* _non_pop_summary; - PopSummary* _pop_summary; - NonPopAbandonedSummary* _non_pop_abandoned_summary; - PopAbandonedSummary* _pop_abandoned_summary; + Summary* _summary; + AbandonedSummary* _abandoned_summary; NumberSeq* _all_pause_times_ms; NumberSeq* _all_full_gc_times_ms; @@ -210,18 +179,6 @@ protected: double* _par_last_obj_copy_times_ms; double* _par_last_termination_times_ms; - // there are two pases during popular pauses, so we need to store - // somewhere the results of the first pass - double* _pop_par_last_update_rs_start_times_ms; - double* _pop_par_last_update_rs_times_ms; - double* _pop_par_last_update_rs_processed_buffers; - double* _pop_par_last_scan_rs_start_times_ms; - double* _pop_par_last_scan_rs_times_ms; - double* _pop_par_last_closure_app_times_ms; - - double _pop_compute_rc_start; - double _pop_evac_start; - // indicates that we are in young GC mode bool _in_young_gc_mode; @@ -634,8 +591,7 @@ protected: NumberSeq* calc_other_times_ms) const; void print_summary (PauseSummary* stats) const; - void print_abandoned_summary(PauseSummary* non_pop_summary, - PauseSummary* pop_summary) const; + void print_abandoned_summary(PauseSummary* summary) const; void print_summary (int level, const char* str, NumberSeq* seq) const; void print_summary_sd (int level, const char* str, NumberSeq* seq) const; @@ -856,9 +812,6 @@ public: virtual void record_collection_pause_start(double start_time_sec, size_t start_used); - virtual void record_popular_pause_preamble_start(); - virtual void record_popular_pause_preamble_end(); - // Must currently be called while the world is stopped. virtual void record_concurrent_mark_init_start(); virtual void record_concurrent_mark_init_end(); @@ -881,7 +834,7 @@ public: virtual void record_collection_pause_end_CH_strong_roots(); virtual void record_collection_pause_end_G1_strong_roots(); - virtual void record_collection_pause_end(bool popular, bool abandoned); + virtual void record_collection_pause_end(bool abandoned); // Record the fact that a full collection occurred. virtual void record_full_collection_start(); @@ -966,7 +919,7 @@ public: record_termination_time(0, ms); } - void record_pause_time(double ms) { + void record_pause_time_ms(double ms) { _last_pause_time_ms = ms; } @@ -990,12 +943,6 @@ public: _cur_aux_times_ms[i] += ms; } - void record_pop_compute_rc_start(); - void record_pop_compute_rc_end(); - - void record_pop_evac_start(); - void record_pop_evac_end(); - // Record the fact that "bytes" bytes allocated in a region. void record_before_bytes(size_t bytes); void record_after_bytes(size_t bytes); @@ -1008,9 +955,7 @@ public: // Choose a new collection set. Marks the chosen regions as being // "in_collection_set", and links them together. The head and number of // the collection set are available via access methods. - // If "pop_region" is non-NULL, it is a popular region that has already - // been added to the collection set. - virtual void choose_collection_set(HeapRegion* pop_region = NULL) = 0; + virtual void choose_collection_set() = 0; void clear_collection_set() { _collection_set = NULL; } @@ -1018,9 +963,6 @@ public: // current collection set. HeapRegion* collection_set() { return _collection_set; } - // Sets the collection set to the given single region. - virtual void set_single_region_collection_set(HeapRegion* hr); - // The number of elements in the current collection set. size_t collection_set_size() { return _collection_set_size; } @@ -1203,7 +1145,7 @@ class G1CollectorPolicy_BestRegionsFirst: public G1CollectorPolicy { // If the estimated is less then desirable, resize if possible. void expand_if_possible(size_t numRegions); - virtual void choose_collection_set(HeapRegion* pop_region = NULL); + virtual void choose_collection_set(); virtual void record_collection_pause_start(double start_time_sec, size_t start_used); virtual void record_concurrent_mark_cleanup_end(size_t freed_bytes, @@ -1214,9 +1156,8 @@ public: G1CollectorPolicy_BestRegionsFirst() { _collectionSetChooser = new CollectionSetChooser(); } - void record_collection_pause_end(bool popular, bool abandoned); + void record_collection_pause_end(bool abandoned); bool should_do_collection_pause(size_t word_size); - virtual void set_single_region_collection_set(HeapRegion* hr); // This is not needed any more, after the CSet choosing code was // changed to use the pause prediction work. But let's leave the // hook in just in case. diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp index 8eb83a8bef6..05a258f7c65 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp index 42d177a1e59..2e4ba2f9f48 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp @@ -157,7 +157,6 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, class G1PrepareCompactClosure: public HeapRegionClosure { ModRefBarrierSet* _mrbs; CompactPoint _cp; - bool _popular_only; void free_humongous_region(HeapRegion* hr) { HeapWord* bot = hr->bottom(); @@ -172,17 +171,11 @@ class G1PrepareCompactClosure: public HeapRegionClosure { } public: - G1PrepareCompactClosure(CompactibleSpace* cs, bool popular_only) : + G1PrepareCompactClosure(CompactibleSpace* cs) : _cp(NULL, cs, cs->initialize_threshold()), - _mrbs(G1CollectedHeap::heap()->mr_bs()), - _popular_only(popular_only) + _mrbs(G1CollectedHeap::heap()->mr_bs()) {} bool doHeapRegion(HeapRegion* hr) { - if (_popular_only && !hr->popular()) - return true; // terminate early - else if (!_popular_only && hr->popular()) - return false; // skip this one. - if (hr->isHumongous()) { if (hr->startsHumongous()) { oop obj = oop(hr->bottom()); @@ -203,20 +196,15 @@ public: return false; } }; -// Stolen verbatim from g1CollectedHeap.cpp + +// Finds the first HeapRegion. class FindFirstRegionClosure: public HeapRegionClosure { HeapRegion* _a_region; - bool _find_popular; public: - FindFirstRegionClosure(bool find_popular) : - _a_region(NULL), _find_popular(find_popular) {} + FindFirstRegionClosure() : _a_region(NULL) {} bool doHeapRegion(HeapRegion* r) { - if (r->popular() == _find_popular) { - _a_region = r; - return true; - } else { - return false; - } + _a_region = r; + return true; } HeapRegion* result() { return _a_region; } }; @@ -242,30 +230,15 @@ void G1MarkSweep::mark_sweep_phase2() { TraceTime tm("phase 2", PrintGC && Verbose, true, gclog_or_tty); GenMarkSweep::trace("2"); - // First we compact the popular regions. - if (G1NumPopularRegions > 0) { - CompactibleSpace* sp = g1h->first_compactible_space(); - FindFirstRegionClosure cl(true /*find_popular*/); - g1h->heap_region_iterate(&cl); - HeapRegion *r = cl.result(); - assert(r->popular(), "should have found a popular region."); - assert(r == sp, "first popular heap region should " - "== first compactible space"); - G1PrepareCompactClosure blk(sp, true/*popular_only*/); - g1h->heap_region_iterate(&blk); - } - - // Now we do the regular regions. - FindFirstRegionClosure cl(false /*find_popular*/); + FindFirstRegionClosure cl; g1h->heap_region_iterate(&cl); HeapRegion *r = cl.result(); - assert(!r->popular(), "should have founda non-popular region."); CompactibleSpace* sp = r; if (r->isHumongous() && oop(r->bottom())->is_gc_marked()) { sp = r->next_compaction_space(); } - G1PrepareCompactClosure blk(sp, false/*popular_only*/); + G1PrepareCompactClosure blk(sp); g1h->heap_region_iterate(&blk); CompactPoint perm_cp(pg, NULL, NULL); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp index 2791bf6ee6b..1619770a663 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 7946c41ff79..f8674dd16c5 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,33 +105,6 @@ StupidG1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, _g1->heap_region_iterate(&rc); } -class UpdateRSOopClosure: public OopClosure { - HeapRegion* _from; - HRInto_G1RemSet* _rs; - int _worker_i; -public: - UpdateRSOopClosure(HRInto_G1RemSet* rs, int worker_i = 0) : - _from(NULL), _rs(rs), _worker_i(worker_i) { - guarantee(_rs != NULL, "Requires an HRIntoG1RemSet"); - } - - void set_from(HeapRegion* from) { - assert(from != NULL, "from region must be non-NULL"); - _from = from; - } - - virtual void do_oop(narrowOop* p) { - guarantee(false, "NYI"); - } - virtual void do_oop(oop* p) { - assert(_from != NULL, "from region must be non-NULL"); - _rs->par_write_ref(_from, p, _worker_i); - } - // Override: this closure is idempotent. - // bool idempotent() { return true; } - bool apply_to_weak_ref_discovered_field() { return true; } -}; - class UpdateRSOutOfRegionClosure: public HeapRegionClosure { G1CollectedHeap* _g1h; ModRefBarrierSet* _mr_bs; @@ -177,11 +150,19 @@ HRInto_G1RemSet::HRInto_G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs) _cards_scanned(NULL), _total_cards_scanned(0) { _seq_task = new SubTasksDone(NumSeqTasks); - _new_refs = NEW_C_HEAP_ARRAY(GrowableArray*, ParallelGCThreads); + guarantee(n_workers() > 0, "There should be some workers"); + _new_refs = NEW_C_HEAP_ARRAY(GrowableArray*, n_workers()); + for (uint i = 0; i < n_workers(); i++) { + _new_refs[i] = new (ResourceObj::C_HEAP) GrowableArray(8192,true); + } } HRInto_G1RemSet::~HRInto_G1RemSet() { delete _seq_task; + for (uint i = 0; i < n_workers(); i++) { + delete _new_refs[i]; + } + FREE_C_HEAP_ARRAY(GrowableArray*, _new_refs); } void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) { @@ -281,8 +262,9 @@ public: if (!_ct_bs->is_card_claimed(card_index) && !_ct_bs->is_card_dirty(card_index)) { assert(_ct_bs->is_card_clean(card_index) || - _ct_bs->is_card_claimed(card_index), - "Card is either dirty, clean, or claimed"); + _ct_bs->is_card_claimed(card_index) || + _ct_bs->is_card_deferred(card_index), + "Card is either clean, claimed or deferred"); if (_ct_bs->claim_card(card_index)) scanCard(card_index, card_region); } @@ -338,14 +320,12 @@ void HRInto_G1RemSet::scanRS(OopsInHeapRegionClosure* oc, int worker_i) { _g1p->record_scan_rs_start_time(worker_i, rs_time_start * 1000.0); _g1p->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0); - if (ParallelGCThreads > 0) { - // In this case, we called scanNewRefsRS and recorded the corresponding - // time. - double scan_new_refs_time_ms = _g1p->get_scan_new_refs_time(worker_i); - if (scan_new_refs_time_ms > 0.0) { - closure_app_time_ms += scan_new_refs_time_ms; - } + + double scan_new_refs_time_ms = _g1p->get_scan_new_refs_time(worker_i); + if (scan_new_refs_time_ms > 0.0) { + closure_app_time_ms += scan_new_refs_time_ms; } + _g1p->record_obj_copy_time(worker_i, closure_app_time_ms); } @@ -469,8 +449,8 @@ HRInto_G1RemSet::scanNewRefsRS(OopsInHeapRegionClosure* oc, double scan_new_refs_start_sec = os::elapsedTime(); G1CollectedHeap* g1h = G1CollectedHeap::heap(); CardTableModRefBS* ct_bs = (CardTableModRefBS*) (g1h->barrier_set()); - while (_new_refs[worker_i]->is_nonempty()) { - oop* p = _new_refs[worker_i]->pop(); + for (int i = 0; i < _new_refs[worker_i]->length(); i++) { + oop* p = _new_refs[worker_i]->at(i); oop obj = *p; // *p was in the collection set when p was pushed on "_new_refs", but // another thread may have processed this location from an RS, so it @@ -480,10 +460,6 @@ HRInto_G1RemSet::scanNewRefsRS(OopsInHeapRegionClosure* oc, HeapRegion* r = g1h->heap_region_containing(p); DEBUG_ONLY(HeapRegion* to = g1h->heap_region_containing(obj)); - assert(ParallelGCThreads > 1 - || to->rem_set()->contains_reference(p), - "Invariant: pushed after being added." - "(Not reliable in parallel code.)"); oc->set_region(r); // If "p" has already been processed concurrently, this is // idempotent. @@ -526,20 +502,31 @@ HRInto_G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, } if (ParallelGCThreads > 0) { - // This is a temporary change to serialize the update and scanning - // of remembered sets. There are some race conditions when this is - // done in parallel and they are causing failures. When we resolve - // said race conditions, we'll revert back to parallel remembered - // set updating and scanning. See CRs 6677707 and 6677708. - if (worker_i == 0) { + // The two flags below were introduced temporarily to serialize + // the updating and scanning of remembered sets. There are some + // race conditions when these two operations are done in parallel + // and they are causing failures. When we resolve said race + // conditions, we'll revert back to parallel remembered set + // updating and scanning. See CRs 6677707 and 6677708. + if (G1EnableParallelRSetUpdating || (worker_i == 0)) { updateRS(worker_i); scanNewRefsRS(oc, worker_i); + } else { + _g1p->record_update_rs_start_time(worker_i, os::elapsedTime()); + _g1p->record_update_rs_processed_buffers(worker_i, 0.0); + _g1p->record_update_rs_time(worker_i, 0.0); + _g1p->record_scan_new_refs_time(worker_i, 0.0); + } + if (G1EnableParallelRSetScanning || (worker_i == 0)) { scanRS(oc, worker_i); + } else { + _g1p->record_scan_rs_start_time(worker_i, os::elapsedTime()); + _g1p->record_scan_rs_time(worker_i, 0.0); } } else { assert(worker_i == 0, "invariant"); - updateRS(0); + scanNewRefsRS(oc, 0); scanRS(oc, 0); } } @@ -559,11 +546,7 @@ prepare_for_oops_into_collection_set_do() { assert(!_par_traversal_in_progress, "Invariant between iterations."); if (ParallelGCThreads > 0) { set_par_traversal(true); - int n_workers = _g1->workers()->total_workers(); - _seq_task->set_par_threads(n_workers); - for (uint i = 0; i < ParallelGCThreads; i++) - _new_refs[i] = new (ResourceObj::C_HEAP) GrowableArray(8192,true); - + _seq_task->set_par_threads((int)n_workers()); if (cg1r->do_traversal()) { updateRS(0); // Have to do this again after updaters @@ -587,6 +570,51 @@ class cleanUpIteratorsClosure : public HeapRegionClosure { } }; +class UpdateRSetOopsIntoCSImmediate : public OopClosure { + G1CollectedHeap* _g1; +public: + UpdateRSetOopsIntoCSImmediate(G1CollectedHeap* g1) : _g1(g1) { } + virtual void do_oop(narrowOop* p) { + guarantee(false, "NYI"); + } + virtual void do_oop(oop* p) { + HeapRegion* to = _g1->heap_region_containing(*p); + if (to->in_collection_set()) { + to->rem_set()->add_reference(p, 0); + } + } +}; + +class UpdateRSetOopsIntoCSDeferred : public OopClosure { + G1CollectedHeap* _g1; + CardTableModRefBS* _ct_bs; + DirtyCardQueue* _dcq; +public: + UpdateRSetOopsIntoCSDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) : + _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) { } + virtual void do_oop(narrowOop* p) { + guarantee(false, "NYI"); + } + virtual void do_oop(oop* p) { + oop obj = *p; + if (_g1->obj_in_cs(obj)) { + size_t card_index = _ct_bs->index_for(p); + if (_ct_bs->mark_card_deferred(card_index)) { + _dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index)); + } + } + } +}; + +void HRInto_G1RemSet::new_refs_iterate(OopClosure* cl) { + for (size_t i = 0; i < n_workers(); i++) { + for (int j = 0; j < _new_refs[i]->length(); j++) { + oop* p = _new_refs[i]->at(j); + cl->do_oop(p); + } + } +} + void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() { guarantee( _cards_scanned != NULL, "invariant" ); _total_cards_scanned = 0; @@ -609,11 +637,25 @@ void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() { if (cg1r->do_traversal()) { cg1r->cg1rThread()->set_do_traversal(false); } - for (uint i = 0; i < ParallelGCThreads; i++) { - delete _new_refs[i]; - } set_par_traversal(false); } + + if (_g1->evacuation_failed()) { + // Restore remembered sets for the regions pointing into + // the collection set. + if (G1DeferredRSUpdate) { + DirtyCardQueue dcq(&_g1->dirty_card_queue_set()); + UpdateRSetOopsIntoCSDeferred deferred_update(_g1, &dcq); + new_refs_iterate(&deferred_update); + } else { + UpdateRSetOopsIntoCSImmediate immediate_update(_g1); + new_refs_iterate(&immediate_update); + } + } + for (uint i = 0; i < n_workers(); i++) { + _new_refs[i]->clear(); + } + assert(!_par_traversal_in_progress, "Invariant between iterations."); } @@ -980,9 +1022,8 @@ void HRInto_G1RemSet::print_summary_info() { gclog_or_tty->print_cr(" %d occupied cards represented.", blk.occupied()); gclog_or_tty->print_cr(" Max sz region = [" PTR_FORMAT ", " PTR_FORMAT " )" - " %s, cap = " SIZE_FORMAT "K, occ = " SIZE_FORMAT "K.", + ", cap = " SIZE_FORMAT "K, occ = " SIZE_FORMAT "K.", blk.max_mem_sz_region()->bottom(), blk.max_mem_sz_region()->end(), - (blk.max_mem_sz_region()->popular() ? "POP" : ""), (blk.max_mem_sz_region()->rem_set()->mem_size() + K - 1)/K, (blk.max_mem_sz_region()->rem_set()->occupied() + K - 1)/K); gclog_or_tty->print_cr(" Did %d coarsenings.", @@ -991,7 +1032,9 @@ void HRInto_G1RemSet::print_summary_info() { } } void HRInto_G1RemSet::prepare_for_verify() { - if (G1HRRSFlushLogBuffersOnVerify && VerifyBeforeGC && !_g1->full_collection()) { + if (G1HRRSFlushLogBuffersOnVerify && + (VerifyBeforeGC || VerifyAfterGC) + && !_g1->full_collection()) { cleanupHRRS(); _g1->set_refine_cte_cl_concurrency(false); if (SafepointSynchronize::is_at_safepoint()) { @@ -1002,5 +1045,7 @@ void HRInto_G1RemSet::prepare_for_verify() { _cg1r->set_use_cache(false); updateRS(0); _cg1r->set_use_cache(cg1r_use_cache); + + assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp index 9f03d394db2..e6439141196 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,6 +155,7 @@ protected: bool _par_traversal_in_progress; void set_par_traversal(bool b); GrowableArray** _new_refs; + void new_refs_iterate(OopClosure* cl); public: // This is called to reset dual hash tables after the gc pause @@ -214,3 +215,27 @@ public: int n() { return _n; }; HeapWord* start_first() { return _start_first; } }; + +class UpdateRSOopClosure: public OopClosure { + HeapRegion* _from; + HRInto_G1RemSet* _rs; + int _worker_i; +public: + UpdateRSOopClosure(HRInto_G1RemSet* rs, int worker_i = 0) : + _from(NULL), _rs(rs), _worker_i(worker_i) { + guarantee(_rs != NULL, "Requires an HRIntoG1RemSet"); + } + + void set_from(HeapRegion* from) { + assert(from != NULL, "from region must be non-NULL"); + _from = from; + } + + virtual void do_oop(narrowOop* p); + virtual void do_oop(oop* p); + + // Override: this closure is idempotent. + // bool idempotent() { return true; } + bool apply_to_weak_ref_discovered_field() { return true; } +}; + diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp index e3f1b5cc81d..00aa14452c2 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp @@ -31,24 +31,7 @@ inline size_t G1RemSet::n_workers() { } inline void HRInto_G1RemSet::write_ref_nv(HeapRegion* from, oop* p) { - oop obj = *p; - assert(from != NULL && from->is_in_reserved(p), - "p is not in a from"); - HeapRegion* to = _g1->heap_region_containing(obj); - if (from != to && to != NULL) { - if (!to->popular() && !from->is_survivor()) { -#if G1_REM_SET_LOGGING - gclog_or_tty->print_cr("Adding " PTR_FORMAT " (" PTR_FORMAT ") to RS" - " for region [" PTR_FORMAT ", " PTR_FORMAT ")", - p, obj, - to->bottom(), to->end()); -#endif - assert(to->rem_set() != NULL, "Need per-region 'into' remsets."); - if (to->rem_set()->add_reference(p)) { - _g1->schedule_popular_region_evac(to); - } - } - } + par_write_ref(from, p, 0); } inline void HRInto_G1RemSet::write_ref(HeapRegion* from, oop* p) { @@ -82,7 +65,18 @@ inline void HRInto_G1RemSet::par_write_ref(HeapRegion* from, oop* p, int tid) { HeapRegion* to = _g1->heap_region_containing(obj); // The test below could be optimized by applying a bit op to to and from. if (to != NULL && from != NULL && from != to) { - if (!to->popular() && !from->is_survivor()) { + // There is a tricky infinite loop if we keep pushing + // self forwarding pointers onto our _new_refs list. + // The _par_traversal_in_progress flag is true during the collection pause, + // false during the evacuation failure handing. + if (_par_traversal_in_progress && + to->in_collection_set() && !self_forwarded(obj)) { + _new_refs[tid]->push(p); + // Deferred updates to the Cset are either discarded (in the normal case), + // or processed (if an evacuation failure occurs) at the end + // of the collection. + // See HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do(). + } else { #if G1_REM_SET_LOGGING gclog_or_tty->print_cr("Adding " PTR_FORMAT " (" PTR_FORMAT ") to RS" " for region [" PTR_FORMAT ", " PTR_FORMAT ")", @@ -90,15 +84,16 @@ inline void HRInto_G1RemSet::par_write_ref(HeapRegion* from, oop* p, int tid) { to->bottom(), to->end()); #endif assert(to->rem_set() != NULL, "Need per-region 'into' remsets."); - if (to->rem_set()->add_reference(p, tid)) { - _g1->schedule_popular_region_evac(to); - } - } - // There is a tricky infinite loop if we keep pushing - // self forwarding pointers onto our _new_refs list. - if (_par_traversal_in_progress && - to->in_collection_set() && !self_forwarded(obj)) { - _new_refs[tid]->push(p); + to->rem_set()->add_reference(p, tid); } } } + +inline void UpdateRSOopClosure::do_oop(narrowOop* p) { + guarantee(false, "NYI"); +} + +inline void UpdateRSOopClosure::do_oop(oop* p) { + assert(_from != NULL, "from region must be non-NULL"); + _rs->par_write_ref(_from, p, _worker_i); +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index 43b1d59c852..f6589e75c78 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -172,6 +172,9 @@ develop(bool, G1RSBarrierUseQueue, true, \ "If true, use queueing RS barrier") \ \ + develop(bool, G1DeferredRSUpdate, true, \ + "If true, use deferred RS updates") \ + \ develop(bool, G1RSLogCheckCardTable, false, \ "If true, verify that no dirty cards remain after RS log " \ "processing.") \ @@ -182,15 +185,9 @@ product(intx, G1InefficientPausePct, 80, \ "Threshold of an 'inefficient' pauses (as % of cum efficiency.") \ \ - product(intx, G1RSPopLimit, 32768, \ - "Limit that defines popularity. Should go away! XXX") \ - \ develop(bool, G1RSCountHisto, false, \ "If true, print a histogram of RS occupancies after each pause") \ \ - product(intx, G1ObjPopLimit, 256, \ - "Limit that defines popularity for an object.") \ - \ product(bool, G1TraceFileOverwrite, false, \ "Allow the trace file to be overwritten") \ \ @@ -198,16 +195,6 @@ "When > 0, print the occupancies of the best and worst" \ "regions.") \ \ - develop(bool, G1TracePopularity, false, \ - "When true, provide detailed tracing of popularity.") \ - \ - product(bool, G1SummarizePopularity, false, \ - "When true, provide end-of-run-summarization of popularity.") \ - \ - product(intx, G1NumPopularRegions, 1, \ - "Number of regions reserved to hold popular objects. " \ - "Should go away later.") \ - \ develop(bool, G1PrintParCleanupStats, false, \ "When true, print extra stats about parallel cleanup.") \ \ @@ -292,6 +279,14 @@ \ product(uintx, G1FixedSurvivorSpaceSize, 0, \ "If non-0 is the size of the G1 survivor space, " \ - "otherwise SurvivorRatio is used to determine the size") + "otherwise SurvivorRatio is used to determine the size") \ + \ + experimental(bool, G1EnableParallelRSetUpdating, false, \ + "Enables the parallelization of remembered set updating " \ + "during evacuation pauses") \ + \ + experimental(bool, G1EnableParallelRSetScanning, false, \ + "Enables the parallelization of remembered set scanning " \ + "during evacuation pauses") G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp index 4cfb76464e4..5171bdb62cb 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 26817660e60..ee578bb2c4c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -104,7 +104,6 @@ public: HeapRegion* to = _g1h->heap_region_containing(*p); if (from != NULL && to != NULL && from != to && - !to->popular() && !to->isHumongous()) { jbyte cv_obj = *_bs->byte_for_const(_containing_obj); jbyte cv_field = *_bs->byte_for_const(p); @@ -285,8 +284,6 @@ void HeapRegion::hr_clear(bool par, bool clear_space) { } zero_marked_bytes(); set_sort_index(-1); - if ((uintptr_t)bottom() >= (uintptr_t)g1h->popular_object_boundary()) - set_popular(false); _offsets.resize(HeapRegion::GrainWords); init_top_at_mark_start(); @@ -371,7 +368,6 @@ HeapRegion(G1BlockOffsetSharedArray* sharedOffsetArray, _next_in_special_set(NULL), _orig_end(NULL), _claimed(InitialClaimValue), _evacuation_failed(false), _prev_marked_bytes(0), _next_marked_bytes(0), _sort_index(-1), - _popularity(NotPopular), _young_type(NotYoung), _next_young_region(NULL), _young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(-1), _rem_set(NULL), _zfs(NotZeroFilled) diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index 10ed5a7d19b..e0a801af30d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,15 +238,6 @@ class HeapRegion: public G1OffsetTableContigSpace { // See "sort_index" method. -1 means is not in the array. int _sort_index; - // Means it has (or at least had) a very large RS, and should not be - // considered for membership in a collection set. - enum PopularityState { - NotPopular, - PopularPending, - Popular - }; - PopularityState _popularity; - // double _gc_efficiency; // @@ -318,7 +309,8 @@ class HeapRegion: public G1OffsetTableContigSpace { FinalCountClaimValue = 1, NoteEndClaimValue = 2, ScrubRemSetClaimValue = 3, - ParVerifyClaimValue = 4 + ParVerifyClaimValue = 4, + RebuildRSClaimValue = 5 }; // Concurrent refinement requires contiguous heap regions (in which TLABs @@ -432,10 +424,6 @@ class HeapRegion: public G1OffsetTableContigSpace { _next_in_special_set = r; } - bool is_reserved() { - return popular(); - } - bool is_on_free_list() { return _is_on_free_list; } @@ -608,23 +596,6 @@ class HeapRegion: public G1OffsetTableContigSpace { init_top_at_mark_start(); } - bool popular() { return _popularity == Popular; } - void set_popular(bool b) { - if (b) { - _popularity = Popular; - } else { - _popularity = NotPopular; - } - } - bool popular_pending() { return _popularity == PopularPending; } - void set_popular_pending(bool b) { - if (b) { - _popularity = PopularPending; - } else { - _popularity = NotPopular; - } - } - // void calc_gc_efficiency(void); double gc_efficiency() { return _gc_efficiency;} diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index 5e54b091976..92bfe7c55a2 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -508,7 +508,7 @@ OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) : typedef PosParPRT* PosParPRTPtr; if (_max_fine_entries == 0) { assert(_mod_max_fine_entries_mask == 0, "Both or none."); - _max_fine_entries = (1 << G1LogRSRegionEntries); + _max_fine_entries = (size_t)(1 << G1LogRSRegionEntries); _mod_max_fine_entries_mask = _max_fine_entries - 1; #if SAMPLE_FOR_EVICTION assert(_fine_eviction_sample_size == 0 diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index e5a713109f9..aa8d3346fa9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -188,32 +188,6 @@ private: // the _outgoing_region_map. void clear_outgoing_entries(); -#if MAYBE - // Audit the given card index. - void audit_card(size_t card_num, HeapRegion* hr, u2* rc_arr, - HeapRegionRemSet* empty_cards, size_t* one_obj_cards); - - // Assumes that "audit_stage1" has been called for "hr", to set up - // "shadow" and "new_rs" appropriately. Identifies individual popular - // objects; returns "true" if any are found. - bool audit_find_pop(HeapRegion* hr, u2* rc_arr); - - // Assumes that "audit_stage1" has been called for "hr", to set up - // "shadow" and "new_rs" appropriately. Identifies individual popular - // objects, and determines the number of entries in "new_rs" if any such - // popular objects are ignored. If this is sufficiently small, returns - // "false" to indicate that a constraint should not be introduced. - // Otherwise, returns "true" to indicate that we should go ahead with - // adding the constraint. - bool audit_stag(HeapRegion* hr, u2* rc_arr); - - - u2* alloc_rc_array(); - - SeqHeapRegionRemSet* audit_post(u2* rc_arr, size_t multi_obj_crds, - SeqHeapRegionRemSet* empty_cards); -#endif - enum ParIterState { Unclaimed, Claimed, Complete }; ParIterState _iter_state; @@ -261,16 +235,14 @@ public: /* Used in the sequential case. Returns "true" iff this addition causes the size limit to be reached. */ - bool add_reference(oop* from) { + void add_reference(oop* from) { _other_regions.add_reference(from); - return false; } /* Used in the parallel case. Returns "true" iff this addition causes the size limit to be reached. */ - bool add_reference(oop* from, int tid) { + void add_reference(oop* from, int tid) { _other_regions.add_reference(from, tid); - return false; } // Records the fact that the current region contains an outgoing @@ -338,20 +310,6 @@ public: } void print() const; -#if MAYBE - // We are about to introduce a constraint, requiring the collection time - // of the region owning this RS to be <= "hr", and forgetting pointers - // from the owning region to "hr." Before doing so, examines this rem - // set for pointers to "hr", possibly identifying some popular objects., - // and possibly finding some cards to no longer contain pointers to "hr", - // - // These steps may prevent the the constraint from being necessary; in - // which case returns a set of cards now thought to contain no pointers - // into HR. In the normal (I assume) case, returns NULL, indicating that - // we should go ahead and add the constraint. - virtual SeqHeapRegionRemSet* audit(HeapRegion* hr) = 0; -#endif - // Called during a stop-world phase to perform any deferred cleanups. // The second version may be called by parallel threads after then finish // collection work. diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp index 5eeb42fbf6c..4e89c8cf979 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,6 @@ HeapRegionSeq::alloc_obj_from_region_index(int ind, size_t word_size) { // [first, cur) HeapRegion* curhr = _regions.at(cur); if (curhr->is_empty() - && !curhr->is_reserved() && (first == cur || (_regions.at(cur-1)->end() == curhr->bottom()))) { @@ -121,35 +120,27 @@ HeapRegionSeq::alloc_obj_from_region_index(int ind, size_t word_size) { } } -void HeapRegionSeq::print_empty_runs(bool reserved_are_empty) { +void HeapRegionSeq::print_empty_runs() { int empty_run = 0; int n_empty = 0; - bool at_least_one_reserved = false; int empty_run_start; for (int i = 0; i < _regions.length(); i++) { HeapRegion* r = _regions.at(i); if (r->continuesHumongous()) continue; - if (r->is_empty() && (reserved_are_empty || !r->is_reserved())) { + if (r->is_empty()) { assert(!r->isHumongous(), "H regions should not be empty."); if (empty_run == 0) empty_run_start = i; empty_run++; n_empty++; - if (r->is_reserved()) { - at_least_one_reserved = true; - } } else { if (empty_run > 0) { gclog_or_tty->print(" %d:%d", empty_run_start, empty_run); - if (reserved_are_empty && at_least_one_reserved) - gclog_or_tty->print("(R)"); empty_run = 0; - at_least_one_reserved = false; } } } if (empty_run > 0) { gclog_or_tty->print(" %d:%d", empty_run_start, empty_run); - if (reserved_are_empty && at_least_one_reserved) gclog_or_tty->print("(R)"); } gclog_or_tty->print_cr(" [tot = %d]", n_empty); } @@ -193,7 +184,6 @@ size_t HeapRegionSeq::free_suffix() { int cur = first; while (cur >= 0 && (_regions.at(cur)->is_empty() - && !_regions.at(cur)->is_reserved() && (first == cur || (_regions.at(cur+1)->bottom() == _regions.at(cur)->end())))) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp index 6ddec8d3fc4..6eee58edcd3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp @@ -104,8 +104,7 @@ class HeapRegionSeq: public CHeapObj { void print(); - // Prints out runs of empty regions. If the arg is "true" reserved - // (popular regions are considered "empty". - void print_empty_runs(bool reserved_are_empty); + // Prints out runs of empty regions. + void print_empty_runs(); }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp index c6a4faad931..1da8d520637 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp @@ -91,15 +91,17 @@ PtrQueueSet::PtrQueueSet(bool notify_when_complete) : _n_completed_buffers(0), _process_completed_threshold(0), _process_completed(false), _buf_free_list(NULL), _buf_free_list_sz(0) -{} +{ + _fl_owner = this; +} void** PtrQueueSet::allocate_buffer() { assert(_sz > 0, "Didn't set a buffer size."); - MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); - if (_buf_free_list != NULL) { - void** res = _buf_free_list; - _buf_free_list = (void**)_buf_free_list[0]; - _buf_free_list_sz--; + MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag); + if (_fl_owner->_buf_free_list != NULL) { + void** res = _fl_owner->_buf_free_list; + _fl_owner->_buf_free_list = (void**)_fl_owner->_buf_free_list[0]; + _fl_owner->_buf_free_list_sz--; // Just override the next pointer with NULL, just in case we scan this part // of the buffer. res[0] = NULL; @@ -111,10 +113,10 @@ void** PtrQueueSet::allocate_buffer() { void PtrQueueSet::deallocate_buffer(void** buf) { assert(_sz > 0, "Didn't set a buffer size."); - MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); - buf[0] = (void*)_buf_free_list; - _buf_free_list = buf; - _buf_free_list_sz++; + MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag); + buf[0] = (void*)_fl_owner->_buf_free_list; + _fl_owner->_buf_free_list = buf; + _fl_owner->_buf_free_list_sz++; } void PtrQueueSet::reduce_free_list() { @@ -207,3 +209,58 @@ void PtrQueueSet::set_buffer_size(size_t sz) { void PtrQueueSet::set_process_completed_threshold(size_t sz) { _process_completed_threshold = sz; } + +// Merge lists of buffers. Notify waiting threads if the length of the list +// exceeds threshold. The source queue is emptied as a result. The queues +// must share the monitor. +void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) { + assert(_cbl_mon == src->_cbl_mon, "Should share the same lock"); + MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); + if (_completed_buffers_tail == NULL) { + assert(_completed_buffers_head == NULL, "Well-formedness"); + _completed_buffers_head = src->_completed_buffers_head; + _completed_buffers_tail = src->_completed_buffers_tail; + } else { + assert(_completed_buffers_head != NULL, "Well formedness"); + if (src->_completed_buffers_head != NULL) { + _completed_buffers_tail->next = src->_completed_buffers_head; + _completed_buffers_tail = src->_completed_buffers_tail; + } + } + _n_completed_buffers += src->_n_completed_buffers; + + src->_n_completed_buffers = 0; + src->_completed_buffers_head = NULL; + src->_completed_buffers_tail = NULL; + + assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL || + _completed_buffers_head != NULL && _completed_buffers_tail != NULL, + "Sanity"); + + if (!_process_completed && + _n_completed_buffers >= _process_completed_threshold) { + _process_completed = true; + if (_notify_when_complete) + _cbl_mon->notify_all(); + } +} + +// Merge free lists of the two queues. The free list of the source +// queue is emptied as a result. The queues must share the same +// mutex that guards free lists. +void PtrQueueSet::merge_freelists(PtrQueueSet* src) { + assert(_fl_lock == src->_fl_lock, "Should share the same lock"); + MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); + if (_buf_free_list != NULL) { + void **p = _buf_free_list; + while (*p != NULL) { + p = (void**)*p; + } + *p = src->_buf_free_list; + } else { + _buf_free_list = src->_buf_free_list; + } + _buf_free_list_sz += src->_buf_free_list_sz; + src->_buf_free_list = NULL; + src->_buf_free_list_sz = 0; +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp index df5557c29a6..663dcba4fa6 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,6 +155,9 @@ protected: Mutex* _fl_lock; void** _buf_free_list; size_t _buf_free_list_sz; + // Queue set can share a freelist. The _fl_owner variable + // specifies the owner. It is set to "this" by default. + PtrQueueSet* _fl_owner; // The size of all buffers in the set. size_t _sz; @@ -188,10 +191,13 @@ public: // Because of init-order concerns, we can't pass these as constructor // arguments. void initialize(Monitor* cbl_mon, Mutex* fl_lock, - int max_completed_queue = 0) { + int max_completed_queue = 0, + PtrQueueSet *fl_owner = NULL) { _max_completed_queue = max_completed_queue; assert(cbl_mon != NULL && fl_lock != NULL, "Init order issue?"); - _cbl_mon = cbl_mon; _fl_lock = fl_lock; + _cbl_mon = cbl_mon; + _fl_lock = fl_lock; + _fl_owner = (fl_owner != NULL) ? fl_owner : this; } // Return an empty oop array of size _sz (required to be non-zero). @@ -228,4 +234,7 @@ public: void reduce_free_list(); size_t completed_buffers_num() { return _n_completed_buffers; } + + void merge_bufferlists(PtrQueueSet* src); + void merge_freelists(PtrQueueSet* src); }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp index af25662f603..b8ace43a14a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp @@ -504,6 +504,7 @@ void SparsePRT::cleanup() { // Make sure that the current and next tables agree. (Another mechanism // takes care of deleting now-unused tables.) _cur = _next; + set_expanded(false); } void SparsePRT::expand() { diff --git a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp index 7c914c7f65c..6ff7b62ee1d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -274,7 +274,7 @@ public: // Clean up all tables on the expanded list. Called single threaded. static void cleanup_all(); - RSHashTable* next() const { return _next; } + RSHashTable* cur() const { return _cur; } void init_iterator(SparsePRTIter* sprt_iter); @@ -300,7 +300,7 @@ public: {} void init(const SparsePRT* sprt) { - RSHashTableIter::init(sprt->next()); + RSHashTableIter::init(sprt->cur()); } bool has_next(size_t& card_index) { return RSHashTableIter::has_next(card_index); diff --git a/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.cpp b/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.cpp index dbd709a95f4..e1d2b1890f6 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.hpp b/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.hpp index 1f5aa2c8bee..889453b3cea 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp index e5753d53b42..40af9313c33 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp @@ -43,16 +43,9 @@ void VM_G1IncCollectionPause::doit() { JvmtiGCForAllocationMarker jgcm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); GCCauseSetter x(g1h, GCCause::_g1_inc_collection_pause); - g1h->do_collection_pause_at_safepoint(NULL); + g1h->do_collection_pause_at_safepoint(); } -void VM_G1PopRegionCollectionPause::doit() { - JvmtiGCForAllocationMarker jgcm; - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - g1h->do_collection_pause_at_safepoint(_pop_region); -} - - void VM_CGC_Operation::doit() { gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); diff --git a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp index a914cea3b48..47eb146e7de 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp @@ -77,20 +77,6 @@ class VM_G1IncCollectionPause: public VM_GC_Operation { } }; -class VM_G1PopRegionCollectionPause: public VM_GC_Operation { - HeapRegion* _pop_region; - public: - VM_G1PopRegionCollectionPause(int gc_count_before, HeapRegion* pop_region) : - VM_GC_Operation(gc_count_before), - _pop_region(pop_region) - {} - virtual VMOp_Type type() const { return VMOp_G1PopRegionCollectionPause; } - virtual void doit(); - virtual const char* name() const { - return "garbage-first popular region collection pause"; - } -}; - // Concurrent GC stop-the-world operations such as initial and final mark; // consider sharing these with CMS's counterparts. class VM_CGC_Operation: public VM_Operation { diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep b/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep index ac88dc1752b..a58a72c39a9 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep @@ -1,5 +1,5 @@ // -// Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 index 84942954651..ab466d70e1b 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 @@ -1,5 +1,5 @@ // -// Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge index 0e0ae1a1e0e..90161a4c7d7 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge @@ -1,5 +1,5 @@ // -// Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared b/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared index 99ce759a474..fca8d2f2ed3 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared @@ -1,5 +1,5 @@ // -// Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp index e2d0ebd701f..a0025382e01 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp index 89331a81bd3..dddb3bb7d3c 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp @@ -63,9 +63,8 @@ public: // return NULL. HeapWord* allocate(size_t word_sz) { HeapWord* res = _top; - HeapWord* new_top = _top + word_sz; - if (new_top <= _end) { - _top = new_top; + if (pointer_delta(_end, _top) >= word_sz) { + _top = _top + word_sz; return res; } else { return NULL; @@ -75,10 +74,9 @@ public: // Undo the last allocation in the buffer, which is required to be of the // "obj" of the given "word_sz". void undo_allocation(HeapWord* obj, size_t word_sz) { - assert(_top - word_sz >= _bottom - && _top - word_sz == obj, - "Bad undo_allocation"); - _top = _top - word_sz; + assert(pointer_delta(_top, _bottom) >= word_sz, "Bad undo"); + assert(pointer_delta(_top, obj) == word_sz, "Bad undo"); + _top = obj; } // The total (word) size of the buffer, including both allocated and diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp index a5010925b00..3628875eb3a 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,10 +34,12 @@ ParScanThreadState::ParScanThreadState(Space* to_space_, Generation* old_gen_, int thread_num_, ObjToScanQueueSet* work_queue_set_, + GrowableArray** overflow_stack_set_, size_t desired_plab_sz_, ParallelTaskTerminator& term_) : - _to_space(to_space_), _old_gen(old_gen_), _thread_num(thread_num_), + _to_space(to_space_), _old_gen(old_gen_), _young_gen(gen_), _thread_num(thread_num_), _work_queue(work_queue_set_->queue(thread_num_)), _to_space_full(false), + _overflow_stack(overflow_stack_set_[thread_num_]), _ageTable(false), // false ==> not the global age table, no perf data. _to_space_alloc_buffer(desired_plab_sz_), _to_space_closure(gen_, this), _old_gen_closure(gen_, this), @@ -81,7 +83,7 @@ void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) { assert(old->is_objArray(), "must be obj array"); assert(old->is_forwarded(), "must be forwarded"); assert(Universe::heap()->is_in_reserved(old), "must be in heap."); - assert(!_old_gen->is_in(old), "must be in young generation."); + assert(!old_gen()->is_in(old), "must be in young generation."); objArrayOop obj = objArrayOop(old->forwardee()); // Process ParGCArrayScanChunk elements now @@ -119,26 +121,68 @@ void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) { void ParScanThreadState::trim_queues(int max_size) { ObjToScanQueue* queue = work_queue(); - while (queue->size() > (juint)max_size) { - oop obj_to_scan; - if (queue->pop_local(obj_to_scan)) { - note_pop(); - - if ((HeapWord *)obj_to_scan < young_old_boundary()) { - if (obj_to_scan->is_objArray() && - obj_to_scan->is_forwarded() && - obj_to_scan->forwardee() != obj_to_scan) { - scan_partial_array_and_push_remainder(obj_to_scan); + do { + while (queue->size() > (juint)max_size) { + oop obj_to_scan; + if (queue->pop_local(obj_to_scan)) { + note_pop(); + if ((HeapWord *)obj_to_scan < young_old_boundary()) { + if (obj_to_scan->is_objArray() && + obj_to_scan->is_forwarded() && + obj_to_scan->forwardee() != obj_to_scan) { + scan_partial_array_and_push_remainder(obj_to_scan); + } else { + // object is in to_space + obj_to_scan->oop_iterate(&_to_space_closure); + } } else { - // object is in to_space - obj_to_scan->oop_iterate(&_to_space_closure); + // object is in old generation + obj_to_scan->oop_iterate(&_old_gen_closure); } - } else { - // object is in old generation - obj_to_scan->oop_iterate(&_old_gen_closure); } } + // For the case of compressed oops, we have a private, non-shared + // overflow stack, so we eagerly drain it so as to more evenly + // distribute load early. Note: this may be good to do in + // general rather than delay for the final stealing phase. + // If applicable, we'll transfer a set of objects over to our + // work queue, allowing them to be stolen and draining our + // private overflow stack. + } while (ParGCTrimOverflow && young_gen()->take_from_overflow_list(this)); +} + +bool ParScanThreadState::take_from_overflow_stack() { + assert(ParGCUseLocalOverflow, "Else should not call"); + assert(young_gen()->overflow_list() == NULL, "Error"); + ObjToScanQueue* queue = work_queue(); + GrowableArray* of_stack = overflow_stack(); + uint num_overflow_elems = of_stack->length(); + uint num_take_elems = MIN2(MIN2((queue->max_elems() - queue->size())/4, + (juint)ParGCDesiredObjsFromOverflowList), + num_overflow_elems); + // Transfer the most recent num_take_elems from the overflow + // stack to our work queue. + for (size_t i = 0; i != num_take_elems; i++) { + oop cur = of_stack->pop(); + oop obj_to_push = cur->forwardee(); + assert(Universe::heap()->is_in_reserved(cur), "Should be in heap"); + assert(!old_gen()->is_in_reserved(cur), "Should be in young gen"); + assert(Universe::heap()->is_in_reserved(obj_to_push), "Should be in heap"); + if (should_be_partially_scanned(obj_to_push, cur)) { + assert(arrayOop(cur)->length() == 0, "entire array remaining to be scanned"); + obj_to_push = cur; + } + bool ok = queue->push(obj_to_push); + assert(ok, "Should have succeeded"); } + assert(young_gen()->overflow_list() == NULL, "Error"); + return num_take_elems > 0; // was something transferred? +} + +void ParScanThreadState::push_on_overflow_stack(oop p) { + assert(ParGCUseLocalOverflow, "Else should not call"); + overflow_stack()->push(p); + assert(young_gen()->overflow_list() == NULL, "Error"); } HeapWord* ParScanThreadState::alloc_in_to_space_slow(size_t word_sz) { @@ -213,6 +257,7 @@ public: ParNewGeneration& gen, Generation& old_gen, ObjToScanQueueSet& queue_set, + GrowableArray** overflow_stacks_, size_t desired_plab_sz, ParallelTaskTerminator& term); inline ParScanThreadState& thread_sate(int i); @@ -235,6 +280,7 @@ private: ParScanThreadStateSet::ParScanThreadStateSet( int num_threads, Space& to_space, ParNewGeneration& gen, Generation& old_gen, ObjToScanQueueSet& queue_set, + GrowableArray** overflow_stack_set_, size_t desired_plab_sz, ParallelTaskTerminator& term) : ResourceArray(sizeof(ParScanThreadState), num_threads), _gen(gen), _next_gen(old_gen), _term(term), @@ -245,7 +291,7 @@ ParScanThreadStateSet::ParScanThreadStateSet( for (int i = 0; i < num_threads; ++i) { new ((ParScanThreadState*)_data + i) ParScanThreadState(&to_space, &gen, &old_gen, i, &queue_set, - desired_plab_sz, term); + overflow_stack_set_, desired_plab_sz, term); } } @@ -425,8 +471,7 @@ void ParNewGenTask::work(int i) { ResourceMark rm; HandleMark hm; // We would need multiple old-gen queues otherwise. - guarantee(gch->n_gens() == 2, - "Par young collection currently only works with one older gen."); + assert(gch->n_gens() == 2, "Par young collection currently only works with one older gen."); Generation* old_gen = gch->next_gen(_gen); @@ -473,6 +518,17 @@ ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level) for (uint i2 = 0; i2 < ParallelGCThreads; i2++) _task_queues->queue(i2)->initialize(); + _overflow_stacks = NEW_C_HEAP_ARRAY(GrowableArray*, ParallelGCThreads); + guarantee(_overflow_stacks != NULL, "Overflow stack set allocation failure"); + for (uint i = 0; i < ParallelGCThreads; i++) { + if (ParGCUseLocalOverflow) { + _overflow_stacks[i] = new (ResourceObj::C_HEAP) GrowableArray(512, true); + guarantee(_overflow_stacks[i] != NULL, "Overflow Stack allocation failure."); + } else { + _overflow_stacks[i] = NULL; + } + } + if (UsePerfData) { EXCEPTION_MARK; ResourceMark rm; @@ -738,7 +794,7 @@ void ParNewGeneration::collect(bool full, ParallelTaskTerminator _term(workers->total_workers(), task_queues()); ParScanThreadStateSet thread_state_set(workers->total_workers(), *to(), *this, *_next_gen, *task_queues(), - desired_plab_sz(), _term); + _overflow_stacks, desired_plab_sz(), _term); ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set); int n_workers = workers->total_workers(); @@ -1169,36 +1225,77 @@ bool ParNewGeneration::should_simulate_overflow() { } #endif +// In case we are using compressed oops, we need to be careful. +// If the object being pushed is an object array, then its length +// field keeps track of the "grey boundary" at which the next +// incremental scan will be done (see ParGCArrayScanChunk). +// When using compressed oops, this length field is kept in the +// lower 32 bits of the erstwhile klass word and cannot be used +// for the overflow chaining pointer (OCP below). As such the OCP +// would itself need to be compressed into the top 32-bits in this +// case. Unfortunately, see below, in the event that we have a +// promotion failure, the node to be pushed on the list can be +// outside of the Java heap, so the heap-based pointer compression +// would not work (we would have potential aliasing between C-heap +// and Java-heap pointers). For this reason, when using compressed +// oops, we simply use a worker-thread-local, non-shared overflow +// list in the form of a growable array, with a slightly different +// overflow stack draining strategy. If/when we start using fat +// stacks here, we can go back to using (fat) pointer chains +// (although some performance comparisons would be useful since +// single global lists have their own performance disadvantages +// as we were made painfully aware not long ago, see 6786503). #define BUSY (oop(0x1aff1aff)) void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadState* par_scan_state) { - // if the object has been forwarded to itself, then we cannot - // use the klass pointer for the linked list. Instead we have - // to allocate an oopDesc in the C-Heap and use that for the linked list. - // XXX This is horribly inefficient when a promotion failure occurs - // and should be fixed. XXX FIX ME !!! + assert(is_in_reserved(from_space_obj), "Should be from this generation"); + if (ParGCUseLocalOverflow) { + // In the case of compressed oops, we use a private, not-shared + // overflow stack. + par_scan_state->push_on_overflow_stack(from_space_obj); + } else { + assert(!UseCompressedOops, "Error"); + // if the object has been forwarded to itself, then we cannot + // use the klass pointer for the linked list. Instead we have + // to allocate an oopDesc in the C-Heap and use that for the linked list. + // XXX This is horribly inefficient when a promotion failure occurs + // and should be fixed. XXX FIX ME !!! #ifndef PRODUCT - Atomic::inc_ptr(&_num_par_pushes); - assert(_num_par_pushes > 0, "Tautology"); + Atomic::inc_ptr(&_num_par_pushes); + assert(_num_par_pushes > 0, "Tautology"); #endif - if (from_space_obj->forwardee() == from_space_obj) { - oopDesc* listhead = NEW_C_HEAP_ARRAY(oopDesc, 1); - listhead->forward_to(from_space_obj); - from_space_obj = listhead; - } - oop observed_overflow_list = _overflow_list; - oop cur_overflow_list; - do { - cur_overflow_list = observed_overflow_list; - if (cur_overflow_list != BUSY) { - from_space_obj->set_klass_to_list_ptr(cur_overflow_list); - } else { - from_space_obj->set_klass_to_list_ptr(NULL); + if (from_space_obj->forwardee() == from_space_obj) { + oopDesc* listhead = NEW_C_HEAP_ARRAY(oopDesc, 1); + listhead->forward_to(from_space_obj); + from_space_obj = listhead; } - observed_overflow_list = - (oop)Atomic::cmpxchg_ptr(from_space_obj, &_overflow_list, cur_overflow_list); - } while (cur_overflow_list != observed_overflow_list); + oop observed_overflow_list = _overflow_list; + oop cur_overflow_list; + do { + cur_overflow_list = observed_overflow_list; + if (cur_overflow_list != BUSY) { + from_space_obj->set_klass_to_list_ptr(cur_overflow_list); + } else { + from_space_obj->set_klass_to_list_ptr(NULL); + } + observed_overflow_list = + (oop)Atomic::cmpxchg_ptr(from_space_obj, &_overflow_list, cur_overflow_list); + } while (cur_overflow_list != observed_overflow_list); + } } +bool ParNewGeneration::take_from_overflow_list(ParScanThreadState* par_scan_state) { + bool res; + + if (ParGCUseLocalOverflow) { + res = par_scan_state->take_from_overflow_stack(); + } else { + assert(!UseCompressedOops, "Error"); + res = take_from_overflow_list_work(par_scan_state); + } + return res; +} + + // *NOTE*: The overflow list manipulation code here and // in CMSCollector:: are very similar in shape, // except that in the CMS case we thread the objects @@ -1213,14 +1310,14 @@ void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadSt // similar changes might be needed. // See CMSCollector::par_take_from_overflow_list() for // more extensive documentation comments. -bool -ParNewGeneration::take_from_overflow_list(ParScanThreadState* par_scan_state) { +bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan_state) { ObjToScanQueue* work_q = par_scan_state->work_queue(); - assert(work_q->size() == 0, "Should first empty local work queue"); // How many to take? - size_t objsFromOverflow = MIN2((size_t)work_q->max_elems()/4, + size_t objsFromOverflow = MIN2((size_t)(work_q->max_elems() - work_q->size())/4, (size_t)ParGCDesiredObjsFromOverflowList); + assert(par_scan_state->overflow_stack() == NULL, "Error"); + assert(!UseCompressedOops, "Error"); if (_overflow_list == NULL) return false; // Otherwise, there was something there; try claiming the list. diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp index b8de0b1e7ac..3e2ab80af2e 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,8 +33,8 @@ class ParEvacuateFollowersClosure; // but they must be here to allow ParScanClosure::do_oop_work to be defined // in genOopClosures.inline.hpp. -typedef OopTaskQueue ObjToScanQueue; -typedef OopTaskQueueSet ObjToScanQueueSet; +typedef OopTaskQueue ObjToScanQueue; +typedef OopTaskQueueSet ObjToScanQueueSet; // Enable this to get push/pop/steal stats. const int PAR_STATS_ENABLED = 0; @@ -55,6 +55,7 @@ class ParScanThreadState { friend class ParScanThreadStateSet; private: ObjToScanQueue *_work_queue; + GrowableArray* _overflow_stack; ParGCAllocBuffer _to_space_alloc_buffer; @@ -79,6 +80,9 @@ class ParScanThreadState { Space* _to_space; Space* to_space() { return _to_space; } + ParNewGeneration* _young_gen; + ParNewGeneration* young_gen() const { return _young_gen; } + Generation* _old_gen; Generation* old_gen() { return _old_gen; } @@ -112,7 +116,9 @@ class ParScanThreadState { ParScanThreadState(Space* to_space_, ParNewGeneration* gen_, Generation* old_gen_, int thread_num_, - ObjToScanQueueSet* work_queue_set_, size_t desired_plab_sz_, + ObjToScanQueueSet* work_queue_set_, + GrowableArray** overflow_stack_set_, + size_t desired_plab_sz_, ParallelTaskTerminator& term_); public: @@ -134,6 +140,11 @@ class ParScanThreadState { // Decrease queue size below "max_size". void trim_queues(int max_size); + // Private overflow stack usage + GrowableArray* overflow_stack() { return _overflow_stack; } + bool take_from_overflow_stack(); + void push_on_overflow_stack(oop p); + // Is new_obj a candidate for scan_partial_array_and_push_remainder method. inline bool should_be_partially_scanned(oop new_obj, oop old_obj) const; @@ -287,9 +298,12 @@ class ParNewGeneration: public DefNewGeneration { char pad[64 - sizeof(ObjToScanQueue)]; // prevent false sharing }; - // The per-thread work queues, available here for stealing. + // The per-worker-thread work queues ObjToScanQueueSet* _task_queues; + // Per-worker-thread local overflow stacks + GrowableArray** _overflow_stacks; + // Desired size of survivor space plab's PLABStats _plab_stats; @@ -378,13 +392,17 @@ class ParNewGeneration: public DefNewGeneration { NOT_PRODUCT(int _overflow_counter;) NOT_PRODUCT(bool should_simulate_overflow();) + // Accessor for overflow list + oop overflow_list() { return _overflow_list; } + // Push the given (from-space) object on the global overflow list. void push_on_overflow_list(oop from_space_obj, ParScanThreadState* par_scan_state); // If the global overflow list is non-empty, move some tasks from it - // onto "work_q" (which must be empty). No more than 1/4 of the - // max_elems of "work_q" are moved. + // onto "work_q" (which need not be empty). No more than 1/4 of the + // available space on "work_q" is used. bool take_from_overflow_list(ParScanThreadState* par_scan_state); + bool take_from_overflow_list_work(ParScanThreadState* par_scan_state); // The task queues to be used by parallel GC threads. ObjToScanQueueSet* task_queues() { diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp index cd260de6c82..8bf1a3e69f2 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp @@ -78,7 +78,7 @@ class CheckForUnmarkedObjects : public ObjectClosure { } // Card marks are not precise. The current system can leave us with - // a mismash of precise marks and begining of object marks. This means + // a mismash of precise marks and beginning of object marks. This means // we test for missing precise marks first. If any are found, we don't // fail unless the object head is also unmarked. virtual void do_object(oop obj) { @@ -258,7 +258,7 @@ void CardTableExtension::scavenge_contents_parallel(ObjectStartArray* start_arra if (!start_array->object_starts_in_range(slice_start, slice_end)) { continue; } - // Update our begining addr + // Update our beginning addr HeapWord* first_object = start_array->object_start(slice_start); debug_only(oop* first_object_within_slice = (oop*) first_object;) if (first_object < slice_start) { diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.hpp index d587d0ae291..f44bcbbb083 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.hpp @@ -127,7 +127,7 @@ class ObjectStartArray : public CHeapObj { // Optimized for finding the first object that crosses into // a given block. The blocks contain the offset of the last // object in that block. Scroll backwards by one, and the first - // object hit should be at the begining of the block + // object hit should be at the beginning of the block HeapWord* object_start(HeapWord* addr) const { assert(_covered_region.contains(addr), "Must be in covered region"); jbyte* block = block_for_addr(addr); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index 2d5334b780c..d0fa3a4eecf 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,12 +104,38 @@ jint ParallelScavengeHeap::initialize() { og_min_size, og_max_size, yg_min_size, yg_max_size); + const size_t total_reserved = pg_max_size + og_max_size + yg_max_size; + char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); + // The main part of the heap (old gen + young gen) can often use a larger page // size than is needed or wanted for the perm gen. Use the "compound // alignment" ReservedSpace ctor to avoid having to use the same page size for // all gens. + ReservedHeapSpace heap_rs(pg_max_size, pg_align, og_max_size + yg_max_size, - og_align); + og_align, addr); + + if (UseCompressedOops) { + if (addr != NULL && !heap_rs.is_reserved()) { + // Failed to reserve at specified address - the requested memory + // region is taken already, for example, by 'java' launcher. + // Try again to reserver heap higher. + addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); + ReservedHeapSpace heap_rs0(pg_max_size, pg_align, og_max_size + yg_max_size, + og_align, addr); + if (addr != NULL && !heap_rs0.is_reserved()) { + // Failed to reserve at specified address again - give up. + addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); + assert(addr == NULL, ""); + ReservedHeapSpace heap_rs1(pg_max_size, pg_align, og_max_size + yg_max_size, + og_align, addr); + heap_rs = heap_rs1; + } else { + heap_rs = heap_rs0; + } + } + } + os::trace_page_sizes("ps perm", pg_min_size, pg_max_size, pg_page_sz, heap_rs.base(), pg_max_size); os::trace_page_sizes("ps main", og_min_size + yg_min_size, @@ -799,6 +825,7 @@ HeapWord* ParallelScavengeHeap::block_start(const void* addr) const { if (young_gen()->is_in_reserved(addr)) { assert(young_gen()->is_in(addr), "addr should be in allocated part of young gen"); + if (Debugging) return NULL; // called from find() in debug.cpp Unimplemented(); } else if (old_gen()->is_in_reserved(addr)) { assert(old_gen()->is_in(addr), diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp index c268b6a2f86..2b8904cfa29 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/prefetchQueue.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/prefetchQueue.hpp index 5266d67319b..7c6f86d3ff8 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/prefetchQueue.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/prefetchQueue.hpp @@ -26,7 +26,7 @@ // PrefetchQueue is a FIFO queue of variable length (currently 8). // // We need to examine the performance penalty of variable lengths. -// We may also want to split this into cpu dependant bits. +// We may also want to split this into cpu dependent bits. // const int PREFETCH_QUEUE_SIZE = 8; diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp index 608eedb8fb1..568b5cf8350 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,6 +125,8 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { perm_gen->verify_object_start_array(); } + heap->pre_full_gc_dump(); + // Filled in below to track the state of the young gen after the collection. bool eden_empty; bool survivors_empty; @@ -363,6 +365,8 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { Universe::print_heap_after_gc(); } + heap->post_full_gc_dump(); + #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); #endif diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp index 4cc90cd2de2..96dd8a96d88 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp index 2d31e5d72a0..47d0aab44ec 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp index 686c65b2c53..76577c3c569 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -508,6 +508,7 @@ ParallelCompactData::summarize_split_space(size_t src_region, assert(destination <= target_end, "sanity"); assert(destination + _region_data[src_region].data_size() > target_end, "region should not fit into target space"); + assert(is_region_aligned(target_end), "sanity"); size_t split_region = src_region; HeapWord* split_destination = destination; @@ -538,14 +539,12 @@ ParallelCompactData::summarize_split_space(size_t src_region, // max(top, max(new_top, clear_top)) // // where clear_top is a new field in SpaceInfo. Would have to set clear_top - // to destination + partial_obj_size, where both have the values passed to - // this routine. + // to target_end. const RegionData* const sr = region(split_region); const size_t beg_idx = addr_to_region_idx(region_align_up(sr->destination() + sr->partial_obj_size())); - const size_t end_idx = - addr_to_region_idx(region_align_up(destination + partial_obj_size)); + const size_t end_idx = addr_to_region_idx(target_end); if (TraceParallelOldGCSummaryPhase) { gclog_or_tty->print_cr("split: clearing source_region field in [" @@ -1982,6 +1981,8 @@ void PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { heap->record_gen_tops_before_GC(); } + heap->pre_full_gc_dump(); + _print_phases = PrintGCDetails && PrintParallelOldGCPhaseTimes; // Make sure data structures are sane, make the heap parsable, and do other @@ -2204,6 +2205,8 @@ void PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { gc_task_manager()->print_task_time_stamps(); } + heap->post_full_gc_dump(); + #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); #endif diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp index eb9ed0fc86b..0a4ba77581d 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp index 11b6118322b..92a41738ed8 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp index f0bc6a85e8b..adfa59e684f 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp index 4003e19c614..943bb006528 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.hpp index c3c1035998a..d2ad54aa350 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp index 1b12c6bf802..d78fbae12de 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp b/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp index 64fe87f7ca9..5a1a42142ab 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ * */ -/* Copyright 1992 Sun Microsystems, Inc. and Stanford University. +/* Copyright 1992-2009 Sun Microsystems, Inc. and Stanford University. See the LICENSE file for license information. */ # include "incls/_precompiled.incl" diff --git a/hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp b/hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp index fffef2af1ad..beb33cd852b 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ * */ -/* Copyright 1992 Sun Microsystems, Inc. and Stanford University. +/* Copyright 1992-2009 Sun Microsystems, Inc. and Stanford University. See the LICENSE file for license information. */ // Age table for adaptive feedback-mediated tenuring (scavenging) diff --git a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp index a3787c8cd29..747f56b2cc9 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ void MutableNUMASpace::ensure_parsability() { for (int i = 0; i < lgrp_spaces()->length(); i++) { LGRPSpace *ls = lgrp_spaces()->at(i); MutableSpace *s = ls->space(); - if (s->top() < top()) { // For all spaces preceeding the one containing top() + if (s->top() < top()) { // For all spaces preceding the one containing top() if (s->free_in_words() > 0) { size_t area_touched_words = pointer_delta(s->end(), s->top()); CollectedHeap::fill_with_object(s->top(), area_touched_words); diff --git a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp index 128db555b58..0fc182a37ac 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp index 90e1d3ca2ca..3cd21b51515 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.hpp b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.hpp index 98382d6c410..940894595f4 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp index 7b4b76696a0..c230275275a 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp @@ -121,7 +121,7 @@ void VM_GC_HeapInspection::doit() { // make the heap parsable (no need to retire TLABs) ch->ensure_parsability(false); } - HeapInspection::heap_inspection(_out); + HeapInspection::heap_inspection(_out, _need_prologue /* need_prologue */); } diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp index fcce0cc3b51..6ff704fdf18 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp @@ -112,13 +112,16 @@ class VM_GC_HeapInspection: public VM_GC_Operation { private: outputStream* _out; bool _full_gc; + bool _need_prologue; public: - VM_GC_HeapInspection(outputStream* out, bool request_full_gc) : + VM_GC_HeapInspection(outputStream* out, bool request_full_gc, + bool need_prologue) : VM_GC_Operation(0 /* total collections, dummy, ignored */, 0 /* total full collections, dummy, ignored */, request_full_gc) { _out = out; _full_gc = request_full_gc; + _need_prologue = need_prologue; } ~VM_GC_HeapInspection() {} diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp index 3e5cf87c1d4..7e2daebd4de 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -294,3 +294,29 @@ void CollectedHeap::resize_all_tlabs() { ThreadLocalAllocBuffer::resize_all_tlabs(); } } + +void CollectedHeap::pre_full_gc_dump() { + if (HeapDumpBeforeFullGC) { + TraceTime tt("Heap Dump: ", PrintGCDetails, false, gclog_or_tty); + // We are doing a "major" collection and a heap dump before + // major collection has been requested. + HeapDumper::dump_heap(); + } + if (PrintClassHistogramBeforeFullGC) { + TraceTime tt("Class Histogram: ", PrintGCDetails, true, gclog_or_tty); + VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */, false /* ! prologue */); + inspector.doit(); + } +} + +void CollectedHeap::post_full_gc_dump() { + if (HeapDumpAfterFullGC) { + TraceTime tt("Heap Dump", PrintGCDetails, false, gclog_or_tty); + HeapDumper::dump_heap(); + } + if (PrintClassHistogramAfterFullGC) { + TraceTime tt("Class Histogram", PrintGCDetails, true, gclog_or_tty); + VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */, false /* ! prologue */); + inspector.doit(); + } +} diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp index 210e6b32b90..3db5224bb59 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -514,6 +514,10 @@ class CollectedHeap : public CHeapObj { // Perform any cleanup actions necessary before allowing a verification. virtual void prepare_for_verify() = 0; + // Generate any dumps preceding or following a full gc + void pre_full_gc_dump(); + void post_full_gc_dump(); + virtual void print() const = 0; virtual void print_on(outputStream* st) const = 0; diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp index c8e59edac33..9b65c40b95a 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/gc_interface/gcCause.hpp b/hotspot/src/share/vm/gc_interface/gcCause.hpp index bae001c9ca7..da23c8e70d4 100644 --- a/hotspot/src/share/vm/gc_interface/gcCause.hpp +++ b/hotspot/src/share/vm/gc_interface/gcCause.hpp @@ -60,7 +60,7 @@ class GCCause : public AllStatic { _old_generation_too_full_to_scavenge, _adaptive_size_policy, - _g1_inc_collection_pause, _g1_pop_region_collection_pause, + _g1_inc_collection_pause, _last_ditch_collection, _last_gc_cause diff --git a/hotspot/src/share/vm/includeDB_compiler2 b/hotspot/src/share/vm/includeDB_compiler2 index bf84589334c..6ba7bfaf867 100644 --- a/hotspot/src/share/vm/includeDB_compiler2 +++ b/hotspot/src/share/vm/includeDB_compiler2 @@ -1,5 +1,5 @@ // -// Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/includeDB_core b/hotspot/src/share/vm/includeDB_core index 8d39f327758..a88800f29f0 100644 --- a/hotspot/src/share/vm/includeDB_core +++ b/hotspot/src/share/vm/includeDB_core @@ -1,5 +1,5 @@ // -// Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -176,7 +176,7 @@ arguments.cpp management.hpp arguments.cpp oop.inline.hpp arguments.cpp os_.inline.hpp arguments.cpp universe.inline.hpp -arguments.cpp vm_version_.hpp +arguments.cpp vm_version_.hpp arguments.hpp java.hpp arguments.hpp perfData.hpp @@ -241,7 +241,7 @@ assembler.hpp oopRecorder.hpp assembler.hpp register_.hpp assembler.hpp relocInfo.hpp assembler.hpp top.hpp -assembler.hpp vm_version_.hpp +assembler.hpp vm_version_.hpp assembler.inline.hpp assembler.hpp assembler.inline.hpp codeBuffer.hpp @@ -280,7 +280,7 @@ atomic.hpp allocation.hpp atomic_.inline.hpp atomic.hpp atomic_.inline.hpp os.hpp -atomic_.inline.hpp vm_version_.hpp +atomic_.inline.hpp vm_version_.hpp // attachListener is jck optional, put cpp deps in includeDB_features @@ -474,6 +474,7 @@ cardTableModRefBS.cpp java.hpp cardTableModRefBS.cpp mutexLocker.hpp cardTableModRefBS.cpp sharedHeap.hpp cardTableModRefBS.cpp space.hpp +cardTableModRefBS.cpp space.inline.hpp cardTableModRefBS.cpp universe.hpp cardTableModRefBS.cpp virtualspace.hpp @@ -2094,6 +2095,7 @@ interp_masm_.cpp interp_masm_.hpp interp_masm_.cpp interpreterRuntime.hpp interp_masm_.cpp interpreter.hpp interp_masm_.cpp jvmtiExport.hpp +interp_masm_.cpp jvmtiRedefineClassesTrace.hpp interp_masm_.cpp jvmtiThreadState.hpp interp_masm_.cpp markOop.hpp interp_masm_.cpp methodDataOop.hpp @@ -2176,7 +2178,7 @@ interpreterRuntime.cpp templateTable.hpp interpreterRuntime.cpp threadCritical.hpp interpreterRuntime.cpp universe.inline.hpp interpreterRuntime.cpp vmSymbols.hpp -interpreterRuntime.cpp vm_version_.hpp +interpreterRuntime.cpp vm_version_.hpp interpreterRuntime.hpp bytecode.hpp interpreterRuntime.hpp frame.inline.hpp @@ -2279,7 +2281,7 @@ java.cpp timer.hpp java.cpp universe.hpp java.cpp vmError.hpp java.cpp vm_operations.hpp -java.cpp vm_version_.hpp +java.cpp vm_version_.hpp java.cpp vtune.hpp java.hpp os.hpp @@ -3152,6 +3154,8 @@ oopsHierarchy.cpp thread.hpp oopsHierarchy.cpp thread_.inline.hpp orderAccess.cpp orderAccess.hpp +orderAccess.cpp stubRoutines.hpp +orderAccess.cpp thread.hpp orderAccess.hpp allocation.hpp orderAccess.hpp os.hpp @@ -3485,7 +3489,7 @@ register.hpp top.hpp register_.cpp register_.hpp register_.hpp register.hpp -register_.hpp vm_version_.hpp +register_.hpp vm_version_.hpp registerMap.hpp globalDefinitions.hpp registerMap.hpp register_.hpp @@ -3670,6 +3674,7 @@ sharedRuntime.cpp interpreterRuntime.hpp sharedRuntime.cpp interpreter.hpp sharedRuntime.cpp javaCalls.hpp sharedRuntime.cpp jvmtiExport.hpp +sharedRuntime.cpp jvmtiRedefineClassesTrace.hpp sharedRuntime.cpp nativeInst_.hpp sharedRuntime.cpp nativeLookup.hpp sharedRuntime.cpp oop.inline.hpp @@ -3699,6 +3704,7 @@ sharedRuntime_.cpp compiledICHolderOop.hpp sharedRuntime_.cpp debugInfoRec.hpp sharedRuntime_.cpp icBuffer.hpp sharedRuntime_.cpp interpreter.hpp +sharedRuntime_.cpp jvmtiRedefineClassesTrace.hpp sharedRuntime_.cpp sharedRuntime.hpp sharedRuntime_.cpp vframeArray.hpp sharedRuntime_.cpp vmreg_.inline.hpp @@ -3835,7 +3841,7 @@ statSampler.cpp resourceArea.hpp statSampler.cpp statSampler.hpp statSampler.cpp systemDictionary.hpp statSampler.cpp vmSymbols.hpp -statSampler.cpp vm_version_.hpp +statSampler.cpp vm_version_.hpp statSampler.hpp perfData.hpp statSampler.hpp task.hpp @@ -4579,22 +4585,23 @@ vm_operations.hpp top.hpp vm_version.cpp arguments.hpp vm_version.cpp oop.inline.hpp vm_version.cpp universe.hpp -vm_version.cpp vm_version_.hpp +vm_version.cpp vm_version_.hpp vm_version.hpp allocation.hpp vm_version.hpp ostream.hpp -vm_version_.cpp assembler_.inline.hpp -vm_version_.cpp java.hpp -vm_version_.cpp os_.inline.hpp -vm_version_.cpp resourceArea.hpp -vm_version_.cpp stubCodeGenerator.hpp -vm_version_.cpp vm_version_.hpp +vm_version_.cpp assembler_.inline.hpp +vm_version_.cpp java.hpp +vm_version_.cpp os_.inline.hpp +vm_version_.cpp resourceArea.hpp +vm_version_.cpp stubCodeGenerator.hpp +vm_version_.cpp vm_version_.hpp -vm_version_.hpp globals_extension.hpp -vm_version_.hpp vm_version.hpp +vm_version_.hpp globals_extension.hpp +vm_version_.hpp vm_version.hpp -vm_version_.cpp vm_version_.hpp +vm_version_.cpp os.hpp +vm_version_.cpp vm_version_.hpp vmreg.cpp assembler.hpp vmreg.cpp vmreg.hpp diff --git a/hotspot/src/share/vm/includeDB_features b/hotspot/src/share/vm/includeDB_features index e136dfe784a..863f6513340 100644 --- a/hotspot/src/share/vm/includeDB_features +++ b/hotspot/src/share/vm/includeDB_features @@ -1,5 +1,5 @@ // -// Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/includeDB_gc b/hotspot/src/share/vm/includeDB_gc index 336148bf8fa..076540d31ff 100644 --- a/hotspot/src/share/vm/includeDB_gc +++ b/hotspot/src/share/vm/includeDB_gc @@ -1,5 +1,5 @@ // -// Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,12 @@ collectedHeap.cpp collectedHeap.hpp collectedHeap.cpp collectedHeap.inline.hpp +collectedHeap.cpp heapDumper.hpp collectedHeap.cpp init.hpp collectedHeap.cpp oop.inline.hpp collectedHeap.cpp systemDictionary.hpp collectedHeap.cpp thread_.inline.hpp +collectedHeap.cpp vmGCOperations.hpp collectedHeap.hpp allocation.hpp collectedHeap.hpp barrierSet.hpp diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp index 76fbb53b83c..581ddfb160b 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp @@ -22,7 +22,7 @@ * */ -// This file contains the platform-independant parts +// This file contains the platform-independent parts // of the abstract interpreter and the abstract interpreter generator. // Organization of the interpreter(s). There exists two different interpreters in hotpot diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 351d29cc9cc..e20ea9d1876 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2642,7 +2642,7 @@ handle_return: // two interpreted frames). We need to save the current arguments in C heap so that // the deoptimized frame when it restarts can copy the arguments to its expression // stack and re-execute the call. We also have to notify deoptimization that this - // has occured and to pick the preerved args copy them to the deoptimized frame's + // has occurred and to pick the preserved args copy them to the deoptimized frame's // java expression stack. Yuck. // THREAD->popframe_preserve_args(in_ByteSize(METHOD->size_of_parameters() * wordSize), diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp index a1504851a38..ea68b860b4c 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp index b765dcebe98..a40991d09ab 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp @@ -22,7 +22,7 @@ * */ -// This file holds platform-independant bodies of inline functions for the C++ based interpreter +// This file holds platform-independent bodies of inline functions for the C++ based interpreter #ifdef CC_INTERP diff --git a/hotspot/src/share/vm/interpreter/cppInterpreter.hpp b/hotspot/src/share/vm/interpreter/cppInterpreter.hpp index 9e4b87fba5a..bb61d4009eb 100644 --- a/hotspot/src/share/vm/interpreter/cppInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/cppInterpreter.hpp @@ -24,7 +24,7 @@ #ifdef CC_INTERP -// This file contains the platform-independant parts +// This file contains the platform-independent parts // of the c++ interpreter class CppInterpreter: public AbstractInterpreter { diff --git a/hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp index 3ce3ce15628..b077f4224c6 100644 --- a/hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp +++ b/hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp @@ -22,7 +22,7 @@ * */ -// This file contains the platform-independant parts +// This file contains the platform-independent parts // of the template interpreter generator. #ifdef CC_INTERP diff --git a/hotspot/src/share/vm/interpreter/interpreter.hpp b/hotspot/src/share/vm/interpreter/interpreter.hpp index eb316c5bce7..767b748dadc 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.hpp +++ b/hotspot/src/share/vm/interpreter/interpreter.hpp @@ -22,7 +22,7 @@ * */ -// This file contains the platform-independant parts +// This file contains the platform-independent parts // of the interpreter and the interpreter generator. //------------------------------------------------------------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp index 791b4777ae3..cf6089c3b81 100644 --- a/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp +++ b/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp @@ -22,7 +22,7 @@ * */ -// This file contains the platform-independant parts +// This file contains the platform-independent parts // of the interpreter generator. diff --git a/hotspot/src/share/vm/interpreter/invocationCounter.cpp b/hotspot/src/share/vm/interpreter/invocationCounter.cpp index cb650778556..7ecc70d1997 100644 --- a/hotspot/src/share/vm/interpreter/invocationCounter.cpp +++ b/hotspot/src/share/vm/interpreter/invocationCounter.cpp @@ -47,6 +47,8 @@ void InvocationCounter::set_carry() { // executed many more times before re-entering the VM. int old_count = count(); int new_count = MIN2(old_count, (int) (CompileThreshold / 2)); + // prevent from going to zero, to distinguish from never-executed methods + if (new_count == 0) new_count = 1; if (old_count != new_count) set(state(), new_count); } diff --git a/hotspot/src/share/vm/interpreter/rewriter.cpp b/hotspot/src/share/vm/interpreter/rewriter.cpp index 323ea8f9a28..77815389539 100644 --- a/hotspot/src/share/vm/interpreter/rewriter.cpp +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp index f6c89f9bd18..e6442351647 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp @@ -22,7 +22,7 @@ * */ -// This file contains the platform-independant parts +// This file contains the platform-independent parts // of the template interpreter and the template interpreter generator. #ifndef CC_INTERP diff --git a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp index 452e1c534ec..52425a04538 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp @@ -22,7 +22,7 @@ * */ -// This file contains the platform-independant parts +// This file contains the platform-independent parts // of the template interpreter generator. #ifndef CC_INTERP diff --git a/hotspot/src/share/vm/libadt/dict.cpp b/hotspot/src/share/vm/libadt/dict.cpp index 003dd6a4f05..ba0757d0e8b 100644 --- a/hotspot/src/share/vm/libadt/dict.cpp +++ b/hotspot/src/share/vm/libadt/dict.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -306,7 +306,7 @@ void Dict::print() { // Convert string to hash key. This algorithm implements a universal hash // function with the multipliers frozen (ok, so it's not universal). The // multipliers (and allowable characters) are all odd, so the resultant sum -// is odd - guarenteed not divisible by any power of two, so the hash tables +// is odd - guaranteed not divisible by any power of two, so the hash tables // can be any power of two with good results. Also, I choose multipliers // that have only 2 bits set (the low is always set to be odd) so // multiplication requires only shifts and adds. Characters are required to @@ -326,7 +326,7 @@ int hashstr(const void *t) { } //------------------------------hashptr-------------------------------------- -// Slimey cheap hash function; no guarenteed performance. Better than the +// Slimey cheap hash function; no guaranteed performance. Better than the // default for pointers, especially on MS-DOS machines. int hashptr(const void *key) { #ifdef __TURBOC__ @@ -336,7 +336,7 @@ int hashptr(const void *key) { #endif } -// Slimey cheap hash function; no guarenteed performance. +// Slimey cheap hash function; no guaranteed performance. int hashkey(const void *key) { return (intptr_t)key; } diff --git a/hotspot/src/share/vm/libadt/dict.hpp b/hotspot/src/share/vm/libadt/dict.hpp index 93f86829e09..a3553ed873e 100644 --- a/hotspot/src/share/vm/libadt/dict.hpp +++ b/hotspot/src/share/vm/libadt/dict.hpp @@ -86,10 +86,10 @@ class Dict : public ResourceObj { // Dictionary structure // Hashing functions int hashstr(const void *s); // Nice string hash -// Slimey cheap hash function; no guarenteed performance. Better than the +// Slimey cheap hash function; no guaranteed performance. Better than the // default for pointers, especially on MS-DOS machines. int hashptr(const void *key); -// Slimey cheap hash function; no guarenteed performance. +// Slimey cheap hash function; no guaranteed performance. int hashkey(const void *key); // Key comparators diff --git a/hotspot/src/share/vm/libadt/port.hpp b/hotspot/src/share/vm/libadt/port.hpp index 68a84f1a4ce..5d6d527bdd0 100644 --- a/hotspot/src/share/vm/libadt/port.hpp +++ b/hotspot/src/share/vm/libadt/port.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/blockOffsetTable.hpp b/hotspot/src/share/vm/memory/blockOffsetTable.hpp index 670dd86d79b..b812a243190 100644 --- a/hotspot/src/share/vm/memory/blockOffsetTable.hpp +++ b/hotspot/src/share/vm/memory/blockOffsetTable.hpp @@ -235,7 +235,7 @@ class BlockOffsetArray: public BlockOffsetTable { }; static size_t power_to_cards_back(uint i) { - return 1 << (LogBase * i); + return (size_t)(1 << (LogBase * i)); } static size_t power_to_words_back(uint i) { return power_to_cards_back(i) * N_words; diff --git a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp index ee9ed1fc8be..59d69e0c581 100644 --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -217,15 +217,28 @@ void CardTableModRefBS::resize_covered_region(MemRegion new_region) { (HeapWord*) align_size_up((uintptr_t)new_end, _page_size); assert(new_end_aligned >= (HeapWord*) new_end, "align up, but less"); + // Check the other regions (excludes "ind") to ensure that + // the new_end_aligned does not intrude onto the committed + // space of another region. int ri = 0; for (ri = 0; ri < _cur_covered_regions; ri++) { if (ri != ind) { if (_committed[ri].contains(new_end_aligned)) { - assert((new_end_aligned >= _committed[ri].start()) && - (_committed[ri].start() > _committed[ind].start()), + // The prior check included in the assert + // (new_end_aligned >= _committed[ri].start()) + // is redundant with the "contains" test. + // Any region containing the new end + // should start at or beyond the region found (ind) + // for the new end (committed regions are not expected to + // be proper subsets of other committed regions). + assert(_committed[ri].start() >= _committed[ind].start(), "New end of committed region is inconsistent"); new_end_aligned = _committed[ri].start(); - assert(new_end_aligned > _committed[ind].start(), + // new_end_aligned can be equal to the start of its + // committed region (i.e., of "ind") if a second + // region following "ind" also start at the same location + // as "ind". + assert(new_end_aligned >= _committed[ind].start(), "New end of committed region is before start"); debug_only(collided = true;) // Should only collide with 1 region @@ -343,18 +356,62 @@ void CardTableModRefBS::write_ref_field_work(void* field, oop newVal) { inline_write_ref_field(field, newVal); } +/* + Claimed and deferred bits are used together in G1 during the evacuation + pause. These bits can have the following state transitions: + 1. The claimed bit can be put over any other card state. Except that + the "dirty -> dirty and claimed" transition is checked for in + G1 code and is not used. + 2. Deferred bit can be set only if the previous state of the card + was either clean or claimed. mark_card_deferred() is wait-free. + We do not care if the operation is be successful because if + it does not it will only result in duplicate entry in the update + buffer because of the "cache-miss". So it's not worth spinning. + */ + bool CardTableModRefBS::claim_card(size_t card_index) { jbyte val = _byte_map[card_index]; - if (val != claimed_card_val()) { - jbyte res = Atomic::cmpxchg((jbyte) claimed_card_val(), &_byte_map[card_index], val); - if (res == val) + assert(val != dirty_card_val(), "Shouldn't claim a dirty card"); + while (val == clean_card_val() || + (val & (clean_card_mask_val() | claimed_card_val())) != claimed_card_val()) { + jbyte new_val = val; + if (val == clean_card_val()) { + new_val = (jbyte)claimed_card_val(); + } else { + new_val = val | (jbyte)claimed_card_val(); + } + jbyte res = Atomic::cmpxchg(new_val, &_byte_map[card_index], val); + if (res == val) { return true; - else return false; + } + val = res; } return false; } +bool CardTableModRefBS::mark_card_deferred(size_t card_index) { + jbyte val = _byte_map[card_index]; + // It's already processed + if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) { + return false; + } + // Cached bit can be installed either on a clean card or on a claimed card. + jbyte new_val = val; + if (val == clean_card_val()) { + new_val = (jbyte)deferred_card_val(); + } else { + if (val & claimed_card_val()) { + new_val = val | (jbyte)deferred_card_val(); + } + } + if (new_val != val) { + Atomic::cmpxchg(new_val, &_byte_map[card_index], val); + } + return true; +} + + void CardTableModRefBS::non_clean_card_iterate(Space* sp, MemRegion mr, DirtyCardToOopClosure* dcto_cl, diff --git a/hotspot/src/share/vm/memory/cardTableModRefBS.hpp b/hotspot/src/share/vm/memory/cardTableModRefBS.hpp index 9a48ab5497d..46a5dd9f6b9 100644 --- a/hotspot/src/share/vm/memory/cardTableModRefBS.hpp +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,11 +52,15 @@ class CardTableModRefBS: public ModRefBarrierSet { enum CardValues { clean_card = -1, + // The mask contains zeros in places for all other values. + clean_card_mask = clean_card - 31, + dirty_card = 0, precleaned_card = 1, - claimed_card = 3, - last_card = 4, - CT_MR_BS_last_reserved = 10 + claimed_card = 2, + deferred_card = 4, + last_card = 8, + CT_MR_BS_last_reserved = 16 }; // dirty and precleaned are equivalent wrt younger_refs_iter. @@ -254,9 +258,11 @@ public: }; static int clean_card_val() { return clean_card; } + static int clean_card_mask_val() { return clean_card_mask; } static int dirty_card_val() { return dirty_card; } static int claimed_card_val() { return claimed_card; } static int precleaned_card_val() { return precleaned_card; } + static int deferred_card_val() { return deferred_card; } // For RTTI simulation. bool is_a(BarrierSet::Name bsn) { @@ -329,7 +335,8 @@ public: } bool is_card_claimed(size_t card_index) { - return _byte_map[card_index] == claimed_card_val(); + jbyte val = _byte_map[card_index]; + return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val(); } bool claim_card(size_t card_index); @@ -338,6 +345,13 @@ public: return _byte_map[card_index] == clean_card_val(); } + bool is_card_deferred(size_t card_index) { + jbyte val = _byte_map[card_index]; + return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); + } + + bool mark_card_deferred(size_t card_index); + // Card marking array base (adjusted for heap low boundary) // This would be the 0th element of _byte_map, if the heap started at 0x0. // But since the heap starts at some higher address, this points to somewhere @@ -434,6 +448,10 @@ public: return byte_for(p) - _byte_map; } + const jbyte* byte_for_index(const size_t card_index) const { + return _byte_map + card_index; + } + void verify(); void verify_guard(); diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index b68f94c0aeb..2f317bf77d8 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -35,14 +35,14 @@ extern address JVM_FunctionAtStart(); extern address JVM_FunctionAtEnd(); -// Complain and stop. All error conditions occuring during the writing of +// Complain and stop. All error conditions occurring during the writing of // an archive file should stop the process. Unrecoverable errors during // the reading of the archive file should stop the process. static void fail(const char *msg, va_list ap) { // This occurs very early during initialization: tty is not initialized. jio_fprintf(defaultStream::error_stream(), - "An error has occured while processing the" + "An error has occurred while processing the" " shared archive file.\n"); jio_vfprintf(defaultStream::error_stream(), msg, ap); jio_fprintf(defaultStream::error_stream(), "\n"); diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 5bb817f0280..048bd0eca29 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -218,6 +218,31 @@ char* GenCollectedHeap::allocate(size_t alignment, heap_address -= total_reserved; } else { heap_address = NULL; // any address will do. + if (UseCompressedOops) { + heap_address = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); + *_total_reserved = total_reserved; + *_n_covered_regions = n_covered_regions; + *heap_rs = ReservedHeapSpace(total_reserved, alignment, + UseLargePages, heap_address); + + if (heap_address != NULL && !heap_rs->is_reserved()) { + // Failed to reserve at specified address - the requested memory + // region is taken already, for example, by 'java' launcher. + // Try again to reserver heap higher. + heap_address = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); + *heap_rs = ReservedHeapSpace(total_reserved, alignment, + UseLargePages, heap_address); + + if (heap_address != NULL && !heap_rs->is_reserved()) { + // Failed to reserve at specified address again - give up. + heap_address = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); + assert(heap_address == NULL, ""); + *heap_rs = ReservedHeapSpace(total_reserved, alignment, + UseLargePages, heap_address); + } + } + return heap_address; + } } *_total_reserved = total_reserved; @@ -456,6 +481,9 @@ void GenCollectedHeap::do_collection(bool full, int max_level_collected = starting_level; for (int i = starting_level; i <= max_level; i++) { if (_gens[i]->should_collect(full, size, is_tlab)) { + if (i == n_gens() - 1) { // a major collection is to happen + pre_full_gc_dump(); // do any pre full gc dumps + } // Timer for individual generations. Last argument is false: no CR TraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, gclog_or_tty); TraceCollectorStats tcs(_gens[i]->counters()); @@ -573,6 +601,10 @@ void GenCollectedHeap::do_collection(bool full, // a whole heap collection. complete = complete || (max_level_collected == n_gens() - 1); + if (complete) { // We did a "major" collection + post_full_gc_dump(); // do any post full gc dumps + } + if (PrintGCDetails) { print_heap_change(gch_prev_used); diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.hpp b/hotspot/src/share/vm/memory/genCollectedHeap.hpp index 3ab20cfd19f..0630eec6395 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/generation.cpp b/hotspot/src/share/vm/memory/generation.cpp index d7b1d9f871d..117ee18526c 100644 --- a/hotspot/src/share/vm/memory/generation.cpp +++ b/hotspot/src/share/vm/memory/generation.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/generation.hpp b/hotspot/src/share/vm/memory/generation.hpp index 206949901e4..985e9db1028 100644 --- a/hotspot/src/share/vm/memory/generation.hpp +++ b/hotspot/src/share/vm/memory/generation.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp index b0986d1e3ff..ced1bf23c01 100644 --- a/hotspot/src/share/vm/memory/heap.cpp +++ b/hotspot/src/share/vm/memory/heap.cpp @@ -112,7 +112,7 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size, const size_t rs_align = page_size == (size_t) os::vm_page_size() ? 0 : MAX2(page_size, granularity); - ReservedSpace rs(r_size, rs_align, rs_align > 0); + ReservedCodeSpace rs(r_size, rs_align, rs_align > 0); os::trace_page_sizes("code heap", committed_size, reserved_size, page_size, rs.base(), rs.size()); if (!_memory.initialize(rs, c_size)) { diff --git a/hotspot/src/share/vm/memory/heapInspection.cpp b/hotspot/src/share/vm/memory/heapInspection.cpp index 3bc17bea600..4216b1301dd 100644 --- a/hotspot/src/share/vm/memory/heapInspection.cpp +++ b/hotspot/src/share/vm/memory/heapInspection.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -233,7 +233,7 @@ class RecordInstanceClosure : public ObjectClosure { size_t missed_count() { return _missed_count; } }; -void HeapInspection::heap_inspection(outputStream* st) { +void HeapInspection::heap_inspection(outputStream* st, bool need_prologue) { ResourceMark rm; HeapWord* ref; @@ -244,7 +244,9 @@ void HeapInspection::heap_inspection(outputStream* st) { case CollectedHeap::GenCollectedHeap: { is_shared_heap = true; SharedHeap* sh = (SharedHeap*)heap; - sh->gc_prologue(false /* !full */); // get any necessary locks, etc. + if (need_prologue) { + sh->gc_prologue(false /* !full */); // get any necessary locks, etc. + } ref = sh->perm_gen()->used_region().start(); break; } @@ -290,7 +292,7 @@ void HeapInspection::heap_inspection(outputStream* st) { } st->flush(); - if (is_shared_heap) { + if (need_prologue && is_shared_heap) { SharedHeap* sh = (SharedHeap*)heap; sh->gc_epilogue(false /* !full */); // release all acquired locks, etc. } diff --git a/hotspot/src/share/vm/memory/heapInspection.hpp b/hotspot/src/share/vm/memory/heapInspection.hpp index ac2c708a532..4364607c3c4 100644 --- a/hotspot/src/share/vm/memory/heapInspection.hpp +++ b/hotspot/src/share/vm/memory/heapInspection.hpp @@ -127,6 +127,6 @@ class KlassInfoHisto : public StackObj { class HeapInspection : public AllStatic { public: - static void heap_inspection(outputStream* st) KERNEL_RETURN; + static void heap_inspection(outputStream* st, bool need_prologue) KERNEL_RETURN; static void find_instances_at_safepoint(klassOop k, GrowableArray* result) KERNEL_RETURN; }; diff --git a/hotspot/src/share/vm/memory/oopFactory.cpp b/hotspot/src/share/vm/memory/oopFactory.cpp index 32bd1f82236..99763784255 100644 --- a/hotspot/src/share/vm/memory/oopFactory.cpp +++ b/hotspot/src/share/vm/memory/oopFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/oopFactory.hpp b/hotspot/src/share/vm/memory/oopFactory.hpp index a0db0f52172..add1aed4df0 100644 --- a/hotspot/src/share/vm/memory/oopFactory.hpp +++ b/hotspot/src/share/vm/memory/oopFactory.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/permGen.cpp b/hotspot/src/share/vm/memory/permGen.cpp index 65635fe26cf..787da381e52 100644 --- a/hotspot/src/share/vm/memory/permGen.cpp +++ b/hotspot/src/share/vm/memory/permGen.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/permGen.hpp b/hotspot/src/share/vm/memory/permGen.hpp index 454b10f7986..1b57828499e 100644 --- a/hotspot/src/share/vm/memory/permGen.hpp +++ b/hotspot/src/share/vm/memory/permGen.hpp @@ -36,7 +36,7 @@ class PermGen : public CHeapObj { friend class VMStructs; protected: size_t _capacity_expansion_limit; // maximum expansion allowed without a - // full gc occuring + // full gc occurring HeapWord* mem_allocate_in_gen(size_t size, Generation* gen); diff --git a/hotspot/src/share/vm/memory/referenceProcessor.cpp b/hotspot/src/share/vm/memory/referenceProcessor.cpp index ac6f4777e5f..36d95144f46 100644 --- a/hotspot/src/share/vm/memory/referenceProcessor.cpp +++ b/hotspot/src/share/vm/memory/referenceProcessor.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/sharedHeap.cpp b/hotspot/src/share/vm/memory/sharedHeap.cpp index 392487a31ad..d1ec7e0fda5 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.cpp +++ b/hotspot/src/share/vm/memory/sharedHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/sharedHeap.hpp b/hotspot/src/share/vm/memory/sharedHeap.hpp index c8c570e87db..c44800a9bc4 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.hpp +++ b/hotspot/src/share/vm/memory/sharedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index 00f97001384..53c3c2600e1 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/space.hpp b/hotspot/src/share/vm/memory/space.hpp index f055638e8dd..e6164ba19ef 100644 --- a/hotspot/src/share/vm/memory/space.hpp +++ b/hotspot/src/share/vm/memory/space.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/tenuredGeneration.cpp b/hotspot/src/share/vm/memory/tenuredGeneration.cpp index 56eed211d98..eb601c51f2c 100644 --- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp +++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp index 01d7d6e6a2f..be7538604ff 100644 --- a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp +++ b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 88243f2d56c..b854d64892c 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,7 +99,8 @@ size_t Universe::_heap_capacity_at_last_gc; size_t Universe::_heap_used_at_last_gc = 0; CollectedHeap* Universe::_collectedHeap = NULL; -address Universe::_heap_base = NULL; + +NarrowOopStruct Universe::_narrow_oop = { NULL, 0, true }; void Universe::basic_type_classes_do(void f(klassOop)) { @@ -729,6 +730,53 @@ jint universe_init() { return JNI_OK; } +// Choose the heap base address and oop encoding mode +// when compressed oops are used: +// Unscaled - Use 32-bits oops without encoding when +// NarrowOopHeapBaseMin + heap_size < 4Gb +// ZeroBased - Use zero based compressed oops with encoding when +// NarrowOopHeapBaseMin + heap_size < 32Gb +// HeapBased - Use compressed oops with heap base + encoding. + +// 4Gb +static const uint64_t NarrowOopHeapMax = (uint64_t(max_juint) + 1); +// 32Gb +static const uint64_t OopEncodingHeapMax = NarrowOopHeapMax << LogMinObjAlignmentInBytes; + +char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { +#ifdef _LP64 + if (UseCompressedOops) { + assert(mode == UnscaledNarrowOop || + mode == ZeroBasedNarrowOop || + mode == HeapBasedNarrowOop, "mode is invalid"); + + const size_t total_size = heap_size + HeapBaseMinAddress; + if (total_size <= OopEncodingHeapMax && (mode != HeapBasedNarrowOop)) { + if (total_size <= NarrowOopHeapMax && (mode == UnscaledNarrowOop) && + (Universe::narrow_oop_shift() == 0)) { + // Use 32-bits oops without encoding and + // place heap's top on the 4Gb boundary + return (char*)(NarrowOopHeapMax - heap_size); + } else { + // Can't reserve with NarrowOopShift == 0 + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); + if (mode == UnscaledNarrowOop || + mode == ZeroBasedNarrowOop && total_size <= NarrowOopHeapMax) { + // Use zero based compressed oops with encoding and + // place heap's top on the 32Gb boundary in case + // total_size > 4Gb or failed to reserve below 4Gb. + return (char*)(OopEncodingHeapMax - heap_size); + } + } + } else { + // Can't reserve below 32Gb. + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); + } + } +#endif + return NULL; // also return NULL (don't care) for 32-bit VM +} + jint Universe::initialize_heap() { if (UseParallelGC) { @@ -773,6 +821,8 @@ jint Universe::initialize_heap() { if (status != JNI_OK) { return status; } + +#ifdef _LP64 if (UseCompressedOops) { // Subtract a page because something can get allocated at heap base. // This also makes implicit null checking work, because the @@ -780,8 +830,49 @@ jint Universe::initialize_heap() { // See needs_explicit_null_check. // Only set the heap base for compressed oops because it indicates // compressed oops for pstack code. - Universe::_heap_base = Universe::heap()->base() - os::vm_page_size(); + if (PrintCompressedOopsMode) { + tty->cr(); + tty->print("heap address: "PTR_FORMAT, Universe::heap()->base()); + } + if ((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax) { + // Can't reserve heap below 32Gb. + Universe::set_narrow_oop_base(Universe::heap()->base() - os::vm_page_size()); + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); + if (PrintCompressedOopsMode) { + tty->print(", Compressed Oops with base: "PTR_FORMAT, Universe::narrow_oop_base()); + } + } else { + Universe::set_narrow_oop_base(0); + if (PrintCompressedOopsMode) { + tty->print(", zero based Compressed Oops"); + } +#ifdef _WIN64 + if (!Universe::narrow_oop_use_implicit_null_checks()) { + // Don't need guard page for implicit checks in indexed addressing + // mode with zero based Compressed Oops. + Universe::set_narrow_oop_use_implicit_null_checks(true); + } +#endif // _WIN64 + if((uint64_t)Universe::heap()->reserved_region().end() > NarrowOopHeapMax) { + // Can't reserve heap below 4Gb. + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); + } else { + assert(Universe::narrow_oop_shift() == 0, "use unscaled narrow oop"); + if (PrintCompressedOopsMode) { + tty->print(", 32-bits Oops"); + } + } + } + if (PrintCompressedOopsMode) { + tty->cr(); + tty->cr(); + } } + assert(Universe::narrow_oop_base() == (Universe::heap()->base() - os::vm_page_size()) || + Universe::narrow_oop_base() == NULL, "invalid value"); + assert(Universe::narrow_oop_shift() == LogMinObjAlignmentInBytes || + Universe::narrow_oop_shift() == 0, "invalid value"); +#endif // We will never reach the CATCH below since Exceptions::_throw will cause // the VM to exit if an exception is thrown during initialization diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 45c9f96d21f..9e17a184450 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,19 @@ class LatestMethodOopCache : public CommonMethodOopCache { methodOop get_methodOop(); }; +// For UseCompressedOops. +struct NarrowOopStruct { + // Base address for oop-within-java-object materialization. + // NULL if using wide oops or zero based narrow oops. + address _base; + // Number of shift bits for encoding/decoding narrow oops. + // 0 if using wide oops or zero based unscaled narrow oops, + // LogMinObjAlignmentInBytes otherwise. + int _shift; + // Generate code with implicit null checks for narrow oops. + bool _use_implicit_null_checks; +}; + class Universe: AllStatic { // Ugh. Universe is much too friendly. @@ -181,9 +194,9 @@ class Universe: AllStatic { // The particular choice of collected heap. static CollectedHeap* _collectedHeap; - // Base address for oop-within-java-object materialization. - // NULL if using wide oops. Doubles as heap oop null value. - static address _heap_base; + + // For UseCompressedOops. + static struct NarrowOopStruct _narrow_oop; // array of dummy objects used with +FullGCAlot debug_only(static objArrayOop _fullgc_alot_dummy_array;) @@ -328,8 +341,25 @@ class Universe: AllStatic { static CollectedHeap* heap() { return _collectedHeap; } // For UseCompressedOops - static address heap_base() { return _heap_base; } - static address* heap_base_addr() { return &_heap_base; } + static address* narrow_oop_base_addr() { return &_narrow_oop._base; } + static address narrow_oop_base() { return _narrow_oop._base; } + static int narrow_oop_shift() { return _narrow_oop._shift; } + static void set_narrow_oop_base(address base) { _narrow_oop._base = base; } + static void set_narrow_oop_shift(int shift) { _narrow_oop._shift = shift; } + static bool narrow_oop_use_implicit_null_checks() { return _narrow_oop._use_implicit_null_checks; } + static void set_narrow_oop_use_implicit_null_checks(bool use) { _narrow_oop._use_implicit_null_checks = use; } + // Narrow Oop encoding mode: + // 0 - Use 32-bits oops without encoding when + // NarrowOopHeapBaseMin + heap_size < 4Gb + // 1 - Use zero based compressed oops with encoding when + // NarrowOopHeapBaseMin + heap_size < 32Gb + // 2 - Use compressed oops with heap base + encoding. + enum NARROW_OOP_MODE { + UnscaledNarrowOop = 0, + ZeroBasedNarrowOop = 1, + HeapBasedNarrowOop = 2 + }; + static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode); // Historic gc information static size_t get_heap_capacity_at_last_gc() { return _heap_capacity_at_last_gc; } diff --git a/hotspot/src/share/vm/oops/arrayOop.hpp b/hotspot/src/share/vm/oops/arrayOop.hpp index 364d1dbfe40..659002f28b9 100644 --- a/hotspot/src/share/vm/oops/arrayOop.hpp +++ b/hotspot/src/share/vm/oops/arrayOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/constMethodKlass.cpp b/hotspot/src/share/vm/oops/constMethodKlass.cpp index f2fe1706a16..c1ad90c1d57 100644 --- a/hotspot/src/share/vm/oops/constMethodKlass.cpp +++ b/hotspot/src/share/vm/oops/constMethodKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/constMethodKlass.hpp b/hotspot/src/share/vm/oops/constMethodKlass.hpp index a3f7d9710f7..2387d0210a6 100644 --- a/hotspot/src/share/vm/oops/constMethodKlass.hpp +++ b/hotspot/src/share/vm/oops/constMethodKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/constMethodOop.hpp b/hotspot/src/share/vm/oops/constMethodOop.hpp index 4669e6a852f..c6d373946e1 100644 --- a/hotspot/src/share/vm/oops/constMethodOop.hpp +++ b/hotspot/src/share/vm/oops/constMethodOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/constantPoolKlass.cpp b/hotspot/src/share/vm/oops/constantPoolKlass.cpp index 2a17c00e1ce..ab2dac81cad 100644 --- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp +++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/constantPoolKlass.hpp b/hotspot/src/share/vm/oops/constantPoolKlass.hpp index 2f9efc285ef..a01edbab42c 100644 --- a/hotspot/src/share/vm/oops/constantPoolKlass.hpp +++ b/hotspot/src/share/vm/oops/constantPoolKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/constantPoolOop.cpp b/hotspot/src/share/vm/oops/constantPoolOop.cpp index e90bda568e9..d6362e775b0 100644 --- a/hotspot/src/share/vm/oops/constantPoolOop.cpp +++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/constantPoolOop.hpp b/hotspot/src/share/vm/oops/constantPoolOop.hpp index fd2264c1eab..8ccbcd2ba07 100644 --- a/hotspot/src/share/vm/oops/constantPoolOop.hpp +++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/cpCacheKlass.cpp b/hotspot/src/share/vm/oops/cpCacheKlass.cpp index 95fd11ded28..028a9c9c3f3 100644 --- a/hotspot/src/share/vm/oops/cpCacheKlass.cpp +++ b/hotspot/src/share/vm/oops/cpCacheKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/cpCacheKlass.hpp b/hotspot/src/share/vm/oops/cpCacheKlass.hpp index 299910052ae..859f64a46f5 100644 --- a/hotspot/src/share/vm/oops/cpCacheKlass.hpp +++ b/hotspot/src/share/vm/oops/cpCacheKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/cpCacheOop.hpp b/hotspot/src/share/vm/oops/cpCacheOop.hpp index c5ba6052191..c09d7c4da29 100644 --- a/hotspot/src/share/vm/oops/cpCacheOop.hpp +++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/generateOopMap.cpp b/hotspot/src/share/vm/oops/generateOopMap.cpp index 4a9741c0fc8..5828a6d3783 100644 --- a/hotspot/src/share/vm/oops/generateOopMap.cpp +++ b/hotspot/src/share/vm/oops/generateOopMap.cpp @@ -2003,7 +2003,7 @@ void GenerateOopMap::print_time() { // ============ Main Entry Point =========== // GenerateOopMap::GenerateOopMap(methodHandle method) { - // We have to initialize all variables here, that can be queried direcly + // We have to initialize all variables here, that can be queried directly _method = method; _max_locals=0; _init_vars = NULL; diff --git a/hotspot/src/share/vm/oops/generateOopMap.hpp b/hotspot/src/share/vm/oops/generateOopMap.hpp index 432902ef362..00057d574b5 100644 --- a/hotspot/src/share/vm/oops/generateOopMap.hpp +++ b/hotspot/src/share/vm/oops/generateOopMap.hpp @@ -292,7 +292,7 @@ class GenerateOopMap VALUE_OBJ_CLASS_SPEC { int _max_stack; // Cached value of max. stack depth int _max_monitors; // Cached value of max. monitor stack depth int _has_exceptions; // True, if exceptions exist for method - bool _got_error; // True, if an error occured during interpretation. + bool _got_error; // True, if an error occurred during interpretation. Handle _exception; // Exception if got_error is true. bool _did_rewriting; // was bytecodes rewritten bool _did_relocation; // was relocation neccessary @@ -422,7 +422,7 @@ class GenerateOopMap VALUE_OBJ_CLASS_SPEC { void add_to_ref_init_set (int localNo); // Conflicts rewrite logic - bool _conflict; // True, if a conflict occured during interpretation + bool _conflict; // True, if a conflict occurred during interpretation int _nof_refval_conflicts; // No. of conflicts that require rewrites int * _new_var_map; diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 7a2d3408747..b15926b810c 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1813,6 +1813,8 @@ bool instanceKlass::is_same_class_package(oop class_loader1, symbolOop class_nam oop class_loader2, symbolOop class_name2) { if (class_loader1 != class_loader2) { return false; + } else if (class_name1 == class_name2) { + return true; // skip painful bytewise comparison } else { ResourceMark rm; @@ -1859,6 +1861,75 @@ bool instanceKlass::is_same_class_package(oop class_loader1, symbolOop class_nam } } +// Returns true iff super_method can be overridden by a method in targetclassname +// See JSL 3rd edition 8.4.6.1 +// Assumes name-signature match +// "this" is instanceKlass of super_method which must exist +// note that the instanceKlass of the method in the targetclassname has not always been created yet +bool instanceKlass::is_override(methodHandle super_method, Handle targetclassloader, symbolHandle targetclassname, TRAPS) { + // Private methods can not be overridden + if (super_method->is_private()) { + return false; + } + // If super method is accessible, then override + if ((super_method->is_protected()) || + (super_method->is_public())) { + return true; + } + // Package-private methods are not inherited outside of package + assert(super_method->is_package_private(), "must be package private"); + return(is_same_class_package(targetclassloader(), targetclassname())); +} + +/* defined for now in jvm.cpp, for historical reasons *-- +klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle self, + symbolOop& simple_name_result, TRAPS) { + ... +} +*/ + +// tell if two classes have the same enclosing class (at package level) +bool instanceKlass::is_same_package_member_impl(instanceKlassHandle class1, + klassOop class2_oop, TRAPS) { + if (class2_oop == class1->as_klassOop()) return true; + if (!Klass::cast(class2_oop)->oop_is_instance()) return false; + instanceKlassHandle class2(THREAD, class2_oop); + + // must be in same package before we try anything else + if (!class1->is_same_class_package(class2->class_loader(), class2->name())) + return false; + + // As long as there is an outer1.getEnclosingClass, + // shift the search outward. + instanceKlassHandle outer1 = class1; + for (;;) { + // As we walk along, look for equalities between outer1 and class2. + // Eventually, the walks will terminate as outer1 stops + // at the top-level class around the original class. + symbolOop ignore_name; + klassOop next = outer1->compute_enclosing_class(ignore_name, CHECK_false); + if (next == NULL) break; + if (next == class2()) return true; + outer1 = instanceKlassHandle(THREAD, next); + } + + // Now do the same for class2. + instanceKlassHandle outer2 = class2; + for (;;) { + symbolOop ignore_name; + klassOop next = outer2->compute_enclosing_class(ignore_name, CHECK_false); + if (next == NULL) break; + // Might as well check the new outer against all available values. + if (next == class1()) return true; + if (next == outer1()) return true; + outer2 = instanceKlassHandle(THREAD, next); + } + + // If by this point we have not found an equality between the + // two classes, we know they are in separate package members. + return false; +} + jint instanceKlass::compute_modifier_flags(TRAPS) const { klassOop k = as_klassOop(); @@ -1917,7 +1988,7 @@ methodOop instanceKlass::method_at_itable(klassOop holder, int index, TRAPS) { / itableOffsetEntry::size(); for (int cnt = 0 ; ; cnt ++, ioe ++) { - // If the interface isn't implemented by the reciever class, + // If the interface isn't implemented by the receiver class, // the VM should throw IncompatibleClassChangeError. if (cnt >= nof_interfaces) { THROW_OOP_0(vmSymbols::java_lang_IncompatibleClassChangeError()); @@ -1996,9 +2067,11 @@ nmethod* instanceKlass::lookup_osr_nmethod(const methodOop m, int bci) const { // Printing +#define BULLET " - " + void FieldPrinter::do_field(fieldDescriptor* fd) { - if (fd->is_static() == (_obj == NULL)) { - _st->print(" - "); + _st->print(BULLET); + if (fd->is_static() || (_obj == NULL)) { fd->print_on(_st); _st->cr(); } else { @@ -2019,7 +2092,7 @@ void instanceKlass::oop_print_on(oop obj, outputStream* st) { value->is_typeArray() && offset <= (juint) value->length() && offset + length <= (juint) value->length()) { - st->print("string: "); + st->print(BULLET"string: "); Handle h_obj(obj); java_lang_String::print(h_obj, st); st->cr(); @@ -2027,22 +2100,25 @@ void instanceKlass::oop_print_on(oop obj, outputStream* st) { } } - st->print_cr("fields:"); + st->print_cr(BULLET"---- fields (total size %d words):", oop_size(obj)); FieldPrinter print_nonstatic_field(st, obj); do_nonstatic_fields(&print_nonstatic_field); if (as_klassOop() == SystemDictionary::class_klass()) { + st->print(BULLET"signature: "); + java_lang_Class::print_signature(obj, st); + st->cr(); klassOop mirrored_klass = java_lang_Class::as_klassOop(obj); - st->print(" - fake entry for mirror: "); + st->print(BULLET"fake entry for mirror: "); mirrored_klass->print_value_on(st); st->cr(); - st->print(" - fake entry resolved_constructor: "); + st->print(BULLET"fake entry resolved_constructor: "); methodOop ctor = java_lang_Class::resolved_constructor(obj); ctor->print_value_on(st); klassOop array_klass = java_lang_Class::array_klass(obj); - st->print(" - fake entry for array: "); - array_klass->print_value_on(st); st->cr(); + st->print(BULLET"fake entry for array: "); + array_klass->print_value_on(st); st->cr(); } } @@ -2051,6 +2127,28 @@ void instanceKlass::oop_print_value_on(oop obj, outputStream* st) { st->print("a "); name()->print_value_on(st); obj->print_address_on(st); + if (as_klassOop() == SystemDictionary::string_klass() + && java_lang_String::value(obj) != NULL) { + ResourceMark rm; + int len = java_lang_String::length(obj); + int plen = (len < 24 ? len : 12); + char* str = java_lang_String::as_utf8_string(obj, 0, plen); + st->print(" = \"%s\"", str); + if (len > plen) + st->print("...[%d]", len); + } else if (as_klassOop() == SystemDictionary::class_klass()) { + klassOop k = java_lang_Class::as_klassOop(obj); + st->print(" = "); + if (k != NULL) { + k->print_value_on(st); + } else { + const char* tname = type2name(java_lang_Class::primitive_type(obj)); + st->print("%s", tname ? tname : "type?"); + } + } else if (java_lang_boxing_object::is_instance(obj)) { + st->print(" = "); + java_lang_boxing_object::print(obj, st); + } } #endif // ndef PRODUCT diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 8586ecba03b..3081c2a5b77 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -303,11 +303,30 @@ class instanceKlass: public Klass { inner_class_next_offset = 4 }; + // method override check + bool is_override(methodHandle super_method, Handle targetclassloader, symbolHandle targetclassname, TRAPS); + // package bool is_same_class_package(klassOop class2); bool is_same_class_package(oop classloader2, symbolOop classname2); static bool is_same_class_package(oop class_loader1, symbolOop class_name1, oop class_loader2, symbolOop class_name2); + // find an enclosing class (defined where original code was, in jvm.cpp!) + klassOop compute_enclosing_class(symbolOop& simple_name_result, TRAPS) { + instanceKlassHandle self(THREAD, this->as_klassOop()); + return compute_enclosing_class_impl(self, simple_name_result, THREAD); + } + static klassOop compute_enclosing_class_impl(instanceKlassHandle self, + symbolOop& simple_name_result, TRAPS); + + // tell if two classes have the same enclosing class (at package level) + bool is_same_package_member(klassOop class2, TRAPS) { + instanceKlassHandle self(THREAD, this->as_klassOop()); + return is_same_package_member_impl(self, class2, THREAD); + } + static bool is_same_package_member_impl(instanceKlassHandle self, + klassOop class2, TRAPS); + // initialization state bool is_loaded() const { return _init_state >= loaded; } bool is_linked() const { return _init_state >= linked; } diff --git a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp index 94a6bee03ec..23ebfaba967 100644 --- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -487,6 +487,8 @@ klassOop instanceKlassKlass::allocate_instance_klass(int vtable_len, int itable_ // Printing +#define BULLET " - " + static const char* state_names[] = { "unparseable_by_gc", "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error" }; @@ -497,13 +499,13 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) { instanceKlass* ik = instanceKlass::cast(klassOop(obj)); klassKlass::oop_print_on(obj, st); - st->print(" - instance size: %d", ik->size_helper()); st->cr(); - st->print(" - klass size: %d", ik->object_size()); st->cr(); - st->print(" - access: "); ik->access_flags().print_on(st); st->cr(); - st->print(" - state: "); st->print_cr(state_names[ik->_init_state]); - st->print(" - name: "); ik->name()->print_value_on(st); st->cr(); - st->print(" - super: "); ik->super()->print_value_on(st); st->cr(); - st->print(" - sub: "); + st->print(BULLET"instance size: %d", ik->size_helper()); st->cr(); + st->print(BULLET"klass size: %d", ik->object_size()); st->cr(); + st->print(BULLET"access: "); ik->access_flags().print_on(st); st->cr(); + st->print(BULLET"state: "); st->print_cr(state_names[ik->_init_state]); + st->print(BULLET"name: "); ik->name()->print_value_on(st); st->cr(); + st->print(BULLET"super: "); ik->super()->print_value_on(st); st->cr(); + st->print(BULLET"sub: "); Klass* sub = ik->subklass(); int n; for (n = 0; sub != NULL; n++, sub = sub->next_sibling()) { @@ -516,12 +518,12 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) { st->cr(); if (ik->is_interface()) { - st->print_cr(" - nof implementors: %d", ik->nof_implementors()); + st->print_cr(BULLET"nof implementors: %d", ik->nof_implementors()); int print_impl = 0; for (int i = 0; i < instanceKlass::implementors_limit; i++) { if (ik->implementor(i) != NULL) { if (++print_impl == 1) - st->print_cr(" - implementor: "); + st->print_cr(BULLET"implementor: "); st->print(" "); ik->implementor(i)->print_value_on(st); } @@ -529,34 +531,33 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) { if (print_impl > 0) st->cr(); } - st->print(" - arrays: "); ik->array_klasses()->print_value_on(st); st->cr(); - st->print(" - methods: "); ik->methods()->print_value_on(st); st->cr(); + st->print(BULLET"arrays: "); ik->array_klasses()->print_value_on(st); st->cr(); + st->print(BULLET"methods: "); ik->methods()->print_value_on(st); st->cr(); if (Verbose) { objArrayOop methods = ik->methods(); for(int i = 0; i < methods->length(); i++) { tty->print("%d : ", i); methods->obj_at(i)->print_value(); tty->cr(); } } - st->print(" - method ordering: "); ik->method_ordering()->print_value_on(st); st->cr(); - st->print(" - local interfaces: "); ik->local_interfaces()->print_value_on(st); st->cr(); - st->print(" - trans. interfaces: "); ik->transitive_interfaces()->print_value_on(st); st->cr(); - st->print(" - constants: "); ik->constants()->print_value_on(st); st->cr(); - st->print(" - class loader: "); ik->class_loader()->print_value_on(st); st->cr(); - st->print(" - protection domain: "); ik->protection_domain()->print_value_on(st); st->cr(); - st->print(" - host class: "); ik->host_klass()->print_value_on(st); st->cr(); - st->print(" - signers: "); ik->signers()->print_value_on(st); st->cr(); + st->print(BULLET"method ordering: "); ik->method_ordering()->print_value_on(st); st->cr(); + st->print(BULLET"local interfaces: "); ik->local_interfaces()->print_value_on(st); st->cr(); + st->print(BULLET"trans. interfaces: "); ik->transitive_interfaces()->print_value_on(st); st->cr(); + st->print(BULLET"constants: "); ik->constants()->print_value_on(st); st->cr(); + st->print(BULLET"class loader: "); ik->class_loader()->print_value_on(st); st->cr(); + st->print(BULLET"protection domain: "); ik->protection_domain()->print_value_on(st); st->cr(); + st->print(BULLET"host class: "); ik->host_klass()->print_value_on(st); st->cr(); + st->print(BULLET"signers: "); ik->signers()->print_value_on(st); st->cr(); if (ik->source_file_name() != NULL) { - st->print(" - source file: "); + st->print(BULLET"source file: "); ik->source_file_name()->print_value_on(st); st->cr(); } if (ik->source_debug_extension() != NULL) { - st->print(" - source debug extension: "); + st->print(BULLET"source debug extension: "); ik->source_debug_extension()->print_value_on(st); st->cr(); } - st->print_cr(" - previous version: "); { ResourceMark rm; // PreviousVersionInfo objects returned via PreviousVersionWalker @@ -564,38 +565,43 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) { // GrowableArray _after_ the PreviousVersionWalker destructor // has destroyed the handles. { + bool have_pv = false; PreviousVersionWalker pvw(ik); for (PreviousVersionInfo * pv_info = pvw.next_previous_version(); pv_info != NULL; pv_info = pvw.next_previous_version()) { + if (!have_pv) + st->print(BULLET"previous version: "); + have_pv = true; pv_info->prev_constant_pool_handle()()->print_value_on(st); } - st->cr(); + if (have_pv) st->cr(); } // pvw is cleaned up } // rm is cleaned up if (ik->generic_signature() != NULL) { - st->print(" - generic signature: "); + st->print(BULLET"generic signature: "); ik->generic_signature()->print_value_on(st); + st->cr(); } - st->print(" - inner classes: "); ik->inner_classes()->print_value_on(st); st->cr(); - st->print(" - java mirror: "); ik->java_mirror()->print_value_on(st); st->cr(); - st->print(" - vtable length %d (start addr: " INTPTR_FORMAT ")", ik->vtable_length(), ik->start_of_vtable()); st->cr(); - st->print(" - itable length %d (start addr: " INTPTR_FORMAT ")", ik->itable_length(), ik->start_of_itable()); st->cr(); - st->print_cr(" - static fields:"); + st->print(BULLET"inner classes: "); ik->inner_classes()->print_value_on(st); st->cr(); + st->print(BULLET"java mirror: "); ik->java_mirror()->print_value_on(st); st->cr(); + st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", ik->vtable_length(), ik->start_of_vtable()); st->cr(); + st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", ik->itable_length(), ik->start_of_itable()); st->cr(); + st->print_cr(BULLET"---- static fields (%d words):", ik->static_field_size()); FieldPrinter print_static_field(st); ik->do_local_static_fields(&print_static_field); - st->print_cr(" - non-static fields:"); - FieldPrinter print_nonstatic_field(st, obj); + st->print_cr(BULLET"---- non-static fields (%d words):", ik->nonstatic_field_size()); + FieldPrinter print_nonstatic_field(st); ik->do_nonstatic_fields(&print_nonstatic_field); - st->print(" - static oop maps: "); + st->print(BULLET"static oop maps: "); if (ik->static_oop_field_size() > 0) { int first_offset = ik->offset_of_static_fields(); st->print("%d-%d", first_offset, first_offset + ik->static_oop_field_size() - 1); } st->cr(); - st->print(" - non-static oop maps: "); + st->print(BULLET"non-static oop maps: "); OopMapBlock* map = ik->start_of_nonstatic_oop_maps(); OopMapBlock* end_map = map + ik->nonstatic_oop_map_size(); while (map < end_map) { diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index a028f65bb4e..63a342e5b67 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -71,7 +71,7 @@ Klass *Klass::up_cast_abstract() { return r; // Return the 1 concrete class } -// Find LCA in class heirarchy +// Find LCA in class hierarchy Klass *Klass::LCA( Klass *k2 ) { Klass *k1 = this; while( 1 ) { diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 881da970d03..9ed07d2fb81 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -471,7 +471,7 @@ class Klass : public Klass_vtbl { } bool search_secondary_supers(klassOop k) const; - // Find LCA in class heirarchy + // Find LCA in class hierarchy Klass *LCA( Klass *k ); // Check whether reflection/jni/jvm code is allowed to instantiate this class; diff --git a/hotspot/src/share/vm/oops/klassVtable.cpp b/hotspot/src/share/vm/oops/klassVtable.cpp index 27b32d09760..4afcf3e41bf 100644 --- a/hotspot/src/share/vm/oops/klassVtable.cpp +++ b/hotspot/src/share/vm/oops/klassVtable.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,9 +45,10 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length, klassOop super, objArrayOop methods, AccessFlags class_flags, - oop classloader, - symbolOop classname, - objArrayOop local_interfaces + Handle classloader, + symbolHandle classname, + objArrayOop local_interfaces, + TRAPS ) { No_Safepoint_Verifier nsv; @@ -64,9 +65,9 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length, int len = methods->length(); for (int i = 0; i < len; i++) { assert(methods->obj_at(i)->is_method(), "must be a methodOop"); - methodOop m = methodOop(methods->obj_at(i)); + methodHandle mh(THREAD, methodOop(methods->obj_at(i))); - if (needs_new_vtable_entry(m, super, classloader, classname, class_flags)) { + if (needs_new_vtable_entry(mh, super, classloader, classname, class_flags, THREAD)) { vtable_length += vtableEntry::size(); // we need a new entry } } @@ -117,6 +118,7 @@ int klassVtable::initialize_from_super(KlassHandle super) { superVtable->copy_vtable_to(table()); #ifndef PRODUCT if (PrintVtables && Verbose) { + ResourceMark rm; tty->print_cr("copy vtable from %s to %s size %d", sk->internal_name(), klass()->internal_name(), _length); } #endif @@ -159,13 +161,13 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) { int len = methods()->length(); int initialized = super_vtable_len; - // update_super_vtable can stop for gc - ensure using handles + // update_inherited_vtable can stop for gc - ensure using handles for (int i = 0; i < len; i++) { HandleMark hm(THREAD); assert(methods()->obj_at(i)->is_method(), "must be a methodOop"); methodHandle mh(THREAD, (methodOop)methods()->obj_at(i)); - bool needs_new_entry = update_super_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK); + bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK); if (needs_new_entry) { put_method_at(mh(), initialized); @@ -177,7 +179,7 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) { // add miranda methods; it will also update the value of initialized fill_in_mirandas(initialized); - // In class hierachieswhere the accesibility is not increasing (i.e., going from private -> + // In class hierarchies where the accessibility is not increasing (i.e., going from private -> // package_private -> publicprotected), the vtable might actually be smaller than our initial // calculation. assert(initialized <= _length, "vtable initialization failed"); @@ -188,26 +190,49 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) { } } -// Interates through the vtables to find the broadest access level. This -// will always be monotomic for valid Java programs - but not neccesarily -// for incompatible class files. -klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) { - // This vtable is not implementing the specific method - if (i >= length()) return acc_private; +// Called for cases where a method does not override its superclass' vtable entry +// For bytecodes not produced by javac together it is possible that a method does not override +// the superclass's method, but might indirectly override a super-super class's vtable entry +// If none found, return a null superk, else return the superk of the method this does override +instanceKlass* klassVtable::find_transitive_override(instanceKlass* initialsuper, methodHandle target_method, + int vtable_index, Handle target_loader, symbolHandle target_classname, Thread * THREAD) { + instanceKlass* superk = initialsuper; + while (superk != NULL && superk->super() != NULL) { + instanceKlass* supersuperklass = instanceKlass::cast(superk->super()); + klassVtable* ssVtable = supersuperklass->vtable(); + if (vtable_index < ssVtable->length()) { + methodOop super_method = ssVtable->method_at(vtable_index); +#ifndef PRODUCT + symbolHandle name(THREAD,target_method()->name()); + symbolHandle signature(THREAD,target_method()->signature()); + assert(super_method->name() == name() && super_method->signature() == signature(), "vtable entry name/sig mismatch"); +#endif + if (supersuperklass->is_override(super_method, target_loader, target_classname, THREAD)) { +#ifndef PRODUCT + if (PrintVtables && Verbose) { + ResourceMark rm(THREAD); + tty->print("transitive overriding superclass %s with %s::%s index %d, original flags: ", + supersuperklass->internal_name(), + _klass->internal_name(), (target_method() != NULL) ? + target_method()->name()->as_C_string() : "", vtable_index); + super_method->access_flags().print_on(tty); + tty->print("overriders flags: "); + target_method->access_flags().print_on(tty); + tty->cr(); + } +#endif /*PRODUCT*/ + break; // return found superk + } + } else { + // super class has no vtable entry here, stop transitive search + superk = (instanceKlass*)NULL; + break; + } + // if no override found yet, continue to search up + superk = instanceKlass::cast(superk->super()); + } - // Compute AccessType for current method. public or protected we are done. - methodOop m = method_at(i); - if (m->is_protected() || m->is_public()) return acc_publicprotected; - - AccessType acc = m->is_package_private() ? acc_package_private : acc_private; - - // Compute AccessType for method in super classes - klassOop super = klass()->super(); - AccessType super_acc = (super != NULL) ? instanceKlass::cast(klass()->super())->vtable()->vtable_accessibility_at(i) - : acc_private; - - // Merge - return (AccessType)MAX2((int)acc, (int)super_acc); + return superk; } @@ -215,7 +240,8 @@ klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) { // OR return true if a new vtable entry is required // Only called for instanceKlass's, i.e. not for arrays // If that changed, could not use _klass as handle for klass -bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS) { +bool klassVtable::update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, + bool checkconstraints, TRAPS) { ResourceMark rm; bool allocate_new = true; assert(klass->oop_is_instance(), "must be instanceKlass"); @@ -242,58 +268,35 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_ } // private methods always have a new entry in the vtable + // specification interpretation since classic has + // private methods not overriding if (target_method()->is_private()) { return allocate_new; } // search through the vtable and update overridden entries // Since check_signature_loaders acquires SystemDictionary_lock - // which can block for gc, once we are in this loop, use handles, not - // unhandled oops unless they are reinitialized for each loop - // handles for name, signature, klass, target_method - // not for match_method, holder + // which can block for gc, once we are in this loop, use handles + // For classfiles built with >= jdk7, we now look for transitive overrides symbolHandle name(THREAD,target_method()->name()); symbolHandle signature(THREAD,target_method()->signature()); + Handle target_loader(THREAD, _klass->class_loader()); + symbolHandle target_classname(THREAD, _klass->name()); for(int i = 0; i < super_vtable_len; i++) { - methodOop match_method = method_at(i); + methodOop super_method = method_at(i); // Check if method name matches - if (match_method->name() == name() && match_method->signature() == signature()) { + if (super_method->name() == name() && super_method->signature() == signature()) { - instanceKlass* holder = (THREAD, instanceKlass::cast(match_method->method_holder())); + // get super_klass for method_holder for the found method + instanceKlass* super_klass = instanceKlass::cast(super_method->method_holder()); - // Check if the match_method is accessable from current class - - bool same_package_init = false; - bool same_package_flag = false; - bool simple_match = match_method->is_public() || match_method->is_protected(); - if (!simple_match) { - same_package_init = true; - same_package_flag = holder->is_same_class_package(_klass->class_loader(), _klass->name()); - - simple_match = match_method->is_package_private() && same_package_flag; - } - // match_method is the superclass' method. Note we can't override - // and shouldn't access superclass' ACC_PRIVATE methods - // (although they have been copied into our vtable) - // A simple form of this statement is: - // if ( (match_method->is_public() || match_method->is_protected()) || - // (match_method->is_package_private() && holder->is_same_class_package(klass->class_loader(), klass->name()))) { - // - // The complexity is introduced it avoid recomputing 'is_same_class_package' which is expensive. - if (simple_match) { - // Check if target_method and match_method has same level of accessibility. The accesibility of the - // match method is the "most-general" visibility of all entries at it's particular vtable index for - // all superclasses. This check must be done before we override the current entry in the vtable. - AccessType at = vtable_accessibility_at(i); - bool same_access = false; - - if ( (at == acc_publicprotected && (target_method()->is_public() || target_method()->is_protected()) - || (at == acc_package_private && (target_method()->is_package_private() && - (( same_package_init && same_package_flag) || - (!same_package_init && holder->is_same_class_package(_klass->class_loader(), _klass->name()))))))) { - same_access = true; - } + if ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) || + ((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION) + && ((super_klass = find_transitive_override(super_klass, target_method, i, target_loader, + target_classname, THREAD)) != (instanceKlass*)NULL))) { + // overriding, so no new entry + allocate_new = false; if (checkconstraints) { // Override vtable entry if passes loader constraint check @@ -302,15 +305,12 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_ // have already made any needed loader constraints. // Since loader constraints are transitive, it is enough // to link to the first super, and we get all the others. - symbolHandle signature(THREAD, target_method()->signature()); - Handle this_loader(THREAD, _klass->class_loader()); - instanceKlassHandle super_klass(THREAD, _klass->super()); Handle super_loader(THREAD, super_klass->class_loader()); - if (this_loader() != super_loader()) { + if (target_loader() != super_loader()) { ResourceMark rm(THREAD); char* failed_type_name = - SystemDictionary::check_signature_loaders(signature, this_loader, + SystemDictionary::check_signature_loaders(signature, target_loader, super_loader, true, CHECK_(false)); if (failed_type_name != NULL) { @@ -320,7 +320,7 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_ "(instance of %s), have different Class objects for the type " "%s used in the signature"; char* sig = target_method()->name_and_sig_as_C_string(); - const char* loader1 = SystemDictionary::loader_name(this_loader()); + const char* loader1 = SystemDictionary::loader_name(target_loader()); char* current = _klass->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(super_loader()); size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + @@ -331,59 +331,46 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_ THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false); } } - } + } + put_method_at(target_method(), i); - - - if (same_access) { - // target and match has same accessiblity - share entry - allocate_new = false; - target_method()->set_vtable_index(i); + target_method()->set_vtable_index(i); #ifndef PRODUCT - if (PrintVtables && Verbose) { - AccessType targetacc; - if (target_method()->is_protected() || - target_method()->is_public()) { - targetacc = acc_publicprotected; - } else { - targetacc = target_method()->is_package_private() ? acc_package_private : acc_private; - } - tty->print_cr("overriding with %s::%s index %d, original flags: %x overriders flags: %x", - _klass->internal_name(), (target_method() != NULL) ? - target_method()->name()->as_C_string() : "", i, - at, targetacc); - } -#endif /*PRODUCT*/ - } else { -#ifndef PRODUCT - if (PrintVtables && Verbose) { - AccessType targetacc; - if (target_method()->is_protected() || - target_method()->is_public()) { - targetacc = acc_publicprotected; - } else { - targetacc = target_method()->is_package_private() ? acc_package_private : acc_private; - } - tty->print_cr("override %s %s::%s at index %d, original flags: %x overriders flags: %x", - allocate_new ? "+ new" : "only", - _klass->internal_name(), (target_method() != NULL) ? - target_method()->name()->as_C_string() : "", i, - at, targetacc); - } -#endif /*PRODUCT*/ + if (PrintVtables && Verbose) { + tty->print("overriding with %s::%s index %d, original flags: ", + _klass->internal_name(), (target_method() != NULL) ? + target_method()->name()->as_C_string() : "", i); + super_method->access_flags().print_on(tty); + tty->print("overriders flags: "); + target_method->access_flags().print_on(tty); + tty->cr(); } +#endif /*PRODUCT*/ + } else { + // allocate_new = true; default. We might override one entry, + // but not override another. Once we override one, not need new +#ifndef PRODUCT + if (PrintVtables && Verbose) { + tty->print("NOT overriding with %s::%s index %d, original flags: ", + _klass->internal_name(), (target_method() != NULL) ? + target_method()->name()->as_C_string() : "", i); + super_method->access_flags().print_on(tty); + tty->print("overriders flags: "); + target_method->access_flags().print_on(tty); + tty->cr(); + } +#endif /*PRODUCT*/ } } } return allocate_new; } - - void klassVtable::put_method_at(methodOop m, int index) { assert(m->is_oop_or_null(), "Not an oop or null"); #ifndef PRODUCT if (PrintVtables && Verbose) { + ResourceMark rm; tty->print_cr("adding %s::%s at index %d", _klass->internal_name(), (m != NULL) ? m->name()->as_C_string() : "", index); } @@ -397,19 +384,23 @@ void klassVtable::put_method_at(methodOop m, int index) { // by "classloader" and "classname". // NOTE: The logic used here is very similar to the one used for computing // the vtables indices for a method. We cannot directly use that function because, -// when the Universe is boostrapping, a super's vtable might not be initialized. -bool klassVtable::needs_new_vtable_entry(methodOop target_method, +// we allocate the instanceKlass at load time, and that requires that the +// superclass has been loaded. +// However, the vtable entries are filled in at link time, and therefore +// the superclass' vtable may not yet have been filled in. +bool klassVtable::needs_new_vtable_entry(methodHandle target_method, klassOop super, - oop classloader, - symbolOop classname, - AccessFlags class_flags) { - if ((class_flags.is_final() || target_method->is_final()) || + Handle classloader, + symbolHandle classname, + AccessFlags class_flags, + TRAPS) { + if ((class_flags.is_final() || target_method()->is_final()) || // a final method never needs a new entry; final methods can be statically // resolved and they have to be present in the vtable only if they override // a super's method, in which case they re-use its entry - (target_method->is_static()) || + (target_method()->is_static()) || // static methods don't need to be in vtable - (target_method->name() == vmSymbols::object_initializer_name()) + (target_method()->name() == vmSymbols::object_initializer_name()) // is never called dynamically-bound ) { return false; @@ -421,55 +412,58 @@ bool klassVtable::needs_new_vtable_entry(methodOop target_method, } // private methods always have a new entry in the vtable - if (target_method->is_private()) { + // specification interpretation since classic has + // private methods not overriding + if (target_method()->is_private()) { return true; } // search through the super class hierarchy to see if we need // a new entry - symbolOop name = target_method->name(); - symbolOop signature = target_method->signature(); + ResourceMark rm; + symbolOop name = target_method()->name(); + symbolOop signature = target_method()->signature(); klassOop k = super; - methodOop match_method = NULL; + methodOop super_method = NULL; instanceKlass *holder = NULL; + methodOop recheck_method = NULL; while (k != NULL) { // lookup through the hierarchy for a method with matching name and sign. - match_method = instanceKlass::cast(k)->lookup_method(name, signature); - if (match_method == NULL) { + super_method = instanceKlass::cast(k)->lookup_method(name, signature); + if (super_method == NULL) { break; // we still have to search for a matching miranda method } // get the class holding the matching method - holder = instanceKlass::cast(match_method->method_holder()); - - if (!match_method->is_static()) { // we want only instance method matches - if ((target_method->is_public() || target_method->is_protected()) && - (match_method->is_public() || match_method->is_protected())) { - // target and match are public/protected; we do not need a new entry - return false; - } - - if (target_method->is_package_private() && - match_method->is_package_private() && - holder->is_same_class_package(classloader, classname)) { - // target and match are P private; we do not need a new entry + // make sure you use that class for is_override + instanceKlass* superk = instanceKlass::cast(super_method->method_holder()); + // we want only instance method matches + // pretend private methods are not in the super vtable + // since we do override around them: e.g. a.m pub/b.m private/c.m pub, + // ignore private, c.m pub does override a.m pub + // For classes that were not javac'd together, we also do transitive overriding around + // methods that have less accessibility + if ((!super_method->is_static()) && + (!super_method->is_private())) { + if (superk->is_override(super_method, classloader, classname, THREAD)) { return false; + // else keep looking for transitive overrides } } - k = holder->super(); // haven't found a match yet; continue to look + // Start with lookup result and continue to search up + k = superk->super(); // haven't found an override match yet; continue to look } // if the target method is public or protected it may have a matching // miranda method in the super, whose entry it should re-use. - if (target_method->is_public() || target_method->is_protected()) { - instanceKlass *sk = instanceKlass::cast(super); - if (sk->has_miranda_methods()) { - if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) { - return false; // found a matching miranda; we do not need a new entry - } + // Actually, to handle cases that javac would not generate, we need + // this check for all access permissions. + instanceKlass *sk = instanceKlass::cast(super); + if (sk->has_miranda_methods()) { + if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) { + return false; // found a matching miranda; we do not need a new entry } } - return true; // found no match; we need a new entry } @@ -884,7 +878,7 @@ void klassItable::initialize_itable(bool checkconstraints, TRAPS) { _klass->name()->as_C_string()); - // Interate through all interfaces + // Iterate through all interfaces int i; for(i = 0; i < num_interfaces; i++) { itableOffsetEntry* ioe = offset_entry(i); @@ -992,6 +986,10 @@ void klassItable::adjust_method_entries(methodOop* old_methods, methodOop* new_m methodOop new_method = new_methods[j]; itableMethodEntry* ime = method_entry(0); + // The itable can describe more than one interface and the same + // method signature can be specified by more than one interface. + // This means we have to do an exhaustive search to find all the + // old_method references. for (int i = 0; i < _size_method_table; i++) { if (ime->method() == old_method) { ime->initialize(new_method); @@ -1150,6 +1148,27 @@ int klassItable::compute_itable_index(methodOop m) { return index; } + +// inverse to compute_itable_index +methodOop klassItable::method_for_itable_index(klassOop intf, int itable_index) { + assert(instanceKlass::cast(intf)->is_interface(), "sanity check"); + objArrayOop methods = instanceKlass::cast(intf)->methods(); + + int index = itable_index; + // Adjust for , which is left out of table if first method + if (methods->length() > 0 && ((methodOop)methods->obj_at(0))->name() == vmSymbols::class_initializer_name()) { + index++; + } + + if (itable_index < 0 || index >= methods->length()) + return NULL; // help caller defend against bad indexes + + methodOop m = (methodOop)methods->obj_at(index); + assert(compute_itable_index(m) == itable_index, "correct inverse"); + + return m; +} + void klassVtable::verify(outputStream* st, bool forced) { // make sure table is initialized if (!Universe::is_fully_initialized()) return; diff --git a/hotspot/src/share/vm/oops/klassVtable.hpp b/hotspot/src/share/vm/oops/klassVtable.hpp index 2ef1848f59e..7f664fec46d 100644 --- a/hotspot/src/share/vm/oops/klassVtable.hpp +++ b/hotspot/src/share/vm/oops/klassVtable.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,8 +70,9 @@ class klassVtable : public ResourceObj { // conputes vtable length (in words) and the number of miranda methods static void compute_vtable_size_and_num_mirandas(int &vtable_length, int &num_miranda_methods, klassOop super, objArrayOop methods, - AccessFlags class_flags, oop classloader, - symbolOop classname, objArrayOop local_interfaces); + AccessFlags class_flags, Handle classloader, + symbolHandle classname, objArrayOop local_interfaces, + TRAPS); // RedefineClasses() API support: // If any entry of this vtable points to any of old_methods, @@ -111,14 +112,16 @@ class klassVtable : public ResourceObj { protected: friend class vtableEntry; private: + enum { VTABLE_TRANSITIVE_OVERRIDE_VERSION = 51 } ; void copy_vtable_to(vtableEntry* start); int initialize_from_super(KlassHandle super); int index_of(methodOop m, int len) const; // same as index_of, but search only up to len void put_method_at(methodOop m, int index); - static bool needs_new_vtable_entry(methodOop m, klassOop super, oop classloader, symbolOop classname, AccessFlags access_flags); - AccessType vtable_accessibility_at(int i); + static bool needs_new_vtable_entry(methodHandle m, klassOop super, Handle classloader, symbolHandle classname, AccessFlags access_flags, TRAPS); - bool update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS); + bool update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS); + instanceKlass* find_transitive_override(instanceKlass* initialsuper, methodHandle target_method, int vtable_index, + Handle target_loader, symbolHandle target_classname, Thread* THREAD); // support for miranda methods bool is_miranda_entry_at(int i); @@ -298,6 +301,8 @@ class klassItable : public ResourceObj { // Resolving of method to index static int compute_itable_index(methodOop m); + // ...and back again: + static methodOop method_for_itable_index(klassOop klass, int itable_index); // Debugging/Statistics static void print_statistics() PRODUCT_RETURN; diff --git a/hotspot/src/share/vm/oops/methodKlass.cpp b/hotspot/src/share/vm/oops/methodKlass.cpp index bcc9afb4f31..3144312ef6c 100644 --- a/hotspot/src/share/vm/oops/methodKlass.cpp +++ b/hotspot/src/share/vm/oops/methodKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -247,9 +247,14 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) { st->print_cr(" - size of params: %d", m->size_of_parameters()); st->print_cr(" - method size: %d", m->method_size()); st->print_cr(" - vtable index: %d", m->_vtable_index); + st->print_cr(" - i2i entry: " INTPTR_FORMAT, m->interpreter_entry()); + st->print_cr(" - adapter: " INTPTR_FORMAT, m->adapter()); + st->print_cr(" - compiled entry " INTPTR_FORMAT, m->from_compiled_entry()); st->print_cr(" - code size: %d", m->code_size()); - st->print_cr(" - code start: " INTPTR_FORMAT, m->code_base()); - st->print_cr(" - code end (excl): " INTPTR_FORMAT, m->code_base() + m->code_size()); + if (m->code_size() != 0) { + st->print_cr(" - code start: " INTPTR_FORMAT, m->code_base()); + st->print_cr(" - code end (excl): " INTPTR_FORMAT, m->code_base() + m->code_size()); + } if (m->method_data() != NULL) { st->print_cr(" - method data: " INTPTR_FORMAT, (address)m->method_data()); } @@ -293,6 +298,10 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) { m->code()->print_value_on(st); st->cr(); } + if (m->is_native()) { + st->print_cr(" - native function: " INTPTR_FORMAT, m->native_function()); + st->print_cr(" - signature handler: " INTPTR_FORMAT, m->signature_handler()); + } } diff --git a/hotspot/src/share/vm/oops/methodOop.cpp b/hotspot/src/share/vm/oops/methodOop.cpp index c239ccf1a2c..ddef9043a68 100644 --- a/hotspot/src/share/vm/oops/methodOop.cpp +++ b/hotspot/src/share/vm/oops/methodOop.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/methodOop.hpp b/hotspot/src/share/vm/oops/methodOop.hpp index 8b03a68380a..e87944b7929 100644 --- a/hotspot/src/share/vm/oops/methodOop.hpp +++ b/hotspot/src/share/vm/oops/methodOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -296,7 +296,7 @@ class methodOopDesc : public oopDesc { void set_compiled_invocation_count(int count) { _compiled_invocation_count = count; } #endif // not PRODUCT - // Clear (non-shared space) pointers which could not be relevent + // Clear (non-shared space) pointers which could not be relevant // if this (shared) method were mapped into another JVM. void remove_unshareable_info(); diff --git a/hotspot/src/share/vm/oops/objArrayKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlass.cpp index 1f2574b9c43..3f56d9c1ff6 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -502,12 +502,25 @@ void objArrayKlass::oop_print_on(oop obj, outputStream* st) { } } +static int max_objArray_print_length = 4; void objArrayKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_objArray(), "must be objArray"); + st->print("a "); element_klass()->print_value_on(st); - st->print("a [%d] ", objArrayOop(obj)->length()); - as_klassOop()->klass()->print_value_on(st); + int len = objArrayOop(obj)->length(); + st->print("[%d] ", len); + obj->print_address_on(st); + if (PrintOopAddress || PrintMiscellaneous && (WizardMode || Verbose)) { + st->print("{"); + for (int i = 0; i < len; i++) { + if (i > max_objArray_print_length) { + st->print("..."); break; + } + st->print(" "INTPTR_FORMAT, (intptr_t)(void*)objArrayOop(obj)->obj_at(i)); + } + st->print(" }"); + } } #endif // PRODUCT diff --git a/hotspot/src/share/vm/oops/oop.cpp b/hotspot/src/share/vm/oops/oop.cpp index 505a81f263e..da787bed038 100644 --- a/hotspot/src/share/vm/oops/oop.cpp +++ b/hotspot/src/share/vm/oops/oop.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,11 +65,7 @@ void oopDesc::print_value_on(outputStream* st) const { void oopDesc::print_address_on(outputStream* st) const { if (PrintOopAddress) { - st->print("{"); - if (PrintOopAddress) { - st->print(INTPTR_FORMAT, this); - } - st->print("}"); + st->print("{"INTPTR_FORMAT"}", this); } } diff --git a/hotspot/src/share/vm/oops/oop.hpp b/hotspot/src/share/vm/oops/oop.hpp index ba13ca63c44..16c52d21901 100644 --- a/hotspot/src/share/vm/oops/oop.hpp +++ b/hotspot/src/share/vm/oops/oop.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/oop.inline.hpp b/hotspot/src/share/vm/oops/oop.inline.hpp index 9161310de60..eb74793bd24 100644 --- a/hotspot/src/share/vm/oops/oop.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,10 +148,11 @@ inline bool oopDesc::is_null(narrowOop obj) { return obj == 0; } inline narrowOop oopDesc::encode_heap_oop_not_null(oop v) { assert(!is_null(v), "oop value can never be zero"); - address heap_base = Universe::heap_base(); - uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)heap_base, 1)); + address base = Universe::narrow_oop_base(); + int shift = Universe::narrow_oop_shift(); + uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)base, 1)); assert(OopEncodingHeapMax > pd, "change encoding max if new encoding"); - uint64_t result = pd >> LogMinObjAlignmentInBytes; + uint64_t result = pd >> shift; assert((result & CONST64(0xffffffff00000000)) == 0, "narrow oop overflow"); return (narrowOop)result; } @@ -162,8 +163,9 @@ inline narrowOop oopDesc::encode_heap_oop(oop v) { inline oop oopDesc::decode_heap_oop_not_null(narrowOop v) { assert(!is_null(v), "narrow oop value can never be zero"); - address heap_base = Universe::heap_base(); - return (oop)(void*)((uintptr_t)heap_base + ((uintptr_t)v << LogMinObjAlignmentInBytes)); + address base = Universe::narrow_oop_base(); + int shift = Universe::narrow_oop_shift(); + return (oop)(void*)((uintptr_t)base + ((uintptr_t)v << shift)); } inline oop oopDesc::decode_heap_oop(narrowOop v) { diff --git a/hotspot/src/share/vm/oops/oopsHierarchy.hpp b/hotspot/src/share/vm/oops/oopsHierarchy.hpp index 06c64d0e46f..1e864522d97 100644 --- a/hotspot/src/share/vm/oops/oopsHierarchy.hpp +++ b/hotspot/src/share/vm/oops/oopsHierarchy.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/typeArrayKlass.cpp b/hotspot/src/share/vm/oops/typeArrayKlass.cpp index 2e0ffbcba26..f5d53faa853 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/oops/typeArrayKlass.hpp b/hotspot/src/share/vm/oops/typeArrayKlass.hpp index dac77f6b9bf..99ac60a55b8 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlass.hpp +++ b/hotspot/src/share/vm/oops/typeArrayKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/opto/addnode.cpp b/hotspot/src/share/vm/opto/addnode.cpp index 2ff10cd083d..63932df349d 100644 --- a/hotspot/src/share/vm/opto/addnode.cpp +++ b/hotspot/src/share/vm/opto/addnode.cpp @@ -756,7 +756,13 @@ const Type *AddPNode::mach_bottom_type( const MachNode* n) { if ( eti == NULL ) { // there must be one pointer among the operands guarantee(tptr == NULL, "must be only one pointer operand"); - tptr = et->isa_oopptr(); + if (UseCompressedOops && Universe::narrow_oop_shift() == 0) { + // 32-bits narrow oop can be the base of address expressions + tptr = et->make_ptr()->isa_oopptr(); + } else { + // only regular oops are expected here + tptr = et->isa_oopptr(); + } guarantee(tptr != NULL, "non-int operand must be pointer"); if (tptr->higher_equal(tp->add_offset(tptr->offset()))) tp = tptr; // Set more precise type for bailout diff --git a/hotspot/src/share/vm/opto/block.cpp b/hotspot/src/share/vm/opto/block.cpp index cf15fa7c4fb..10ceec302f9 100644 --- a/hotspot/src/share/vm/opto/block.cpp +++ b/hotspot/src/share/vm/opto/block.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -181,7 +181,7 @@ int Block::is_Empty() const { } //------------------------------has_uncommon_code------------------------------ -// Return true if the block's code implies that it is not likely to be +// Return true if the block's code implies that it is likely to be // executed infrequently. Check to see if the block ends in a Halt or // a low probability call. bool Block::has_uncommon_code() const { @@ -909,6 +909,10 @@ void PhaseCFG::verify( ) const { !(n->jvms() != NULL && n->jvms()->is_monitor_use(k)) ) { assert( b->find_node(def) < j, "uses must follow definitions" ); } + if( def->is_SafePointScalarObject() ) { + assert(_bbs[def->_idx] == b, "SafePointScalarObject Node should be at the same block as its SafePoint node"); + assert(_bbs[def->_idx] == _bbs[def->in(0)->_idx], "SafePointScalarObject Node should be at the same block as its control edge"); + } } } } @@ -1307,7 +1311,7 @@ void PhaseBlockLayout::merge_traces(bool fall_thru_only) } } else if (e->state() == CFGEdge::open) { // Append traces, even without a fall-thru connection. - // But leave root entry at the begining of the block list. + // But leave root entry at the beginning of the block list. if (targ_trace != trace(_cfg._broot)) { e->set_state(CFGEdge::connected); src_trace->append(targ_trace); @@ -1430,7 +1434,7 @@ bool Trace::backedge(CFGEdge *e) { } // Backbranch to the top of a trace - // Scroll foward through the trace from the targ_block. If we find + // Scroll forward through the trace from the targ_block. If we find // a loop head before another loop top, use the the loop head alignment. for (Block *b = targ_block; b != NULL; b = next(b)) { if (b->has_loop_alignment()) { diff --git a/hotspot/src/share/vm/opto/block.hpp b/hotspot/src/share/vm/opto/block.hpp index 43ce09fe9ad..aac5105d66a 100644 --- a/hotspot/src/share/vm/opto/block.hpp +++ b/hotspot/src/share/vm/opto/block.hpp @@ -347,6 +347,8 @@ class PhaseCFG : public Phase { // Helper function to insert a node into a block void schedule_node_into_block( Node *n, Block *b ); + void replace_block_proj_ctrl( Node *n ); + // Set the basic block for pinned Nodes void schedule_pinned_nodes( VectorSet &visited ); @@ -369,6 +371,7 @@ class PhaseCFG : public Phase { Block *_broot; // Basic block of root uint _rpo_ctr; CFGLoop* _root_loop; + float _outer_loop_freq; // Outmost loop frequency // Per node latency estimation, valid only during GCM GrowableArray _node_latency; @@ -535,6 +538,7 @@ class CFGLoop : public CFGElement { void compute_loop_depth(int depth); void compute_freq(); // compute frequency with loop assuming head freq 1.0f void scale_freq(); // scale frequency by loop trip count (including outer loops) + float outer_loop_freq() const; // frequency of outer loop bool in_loop_nest(Block* b); float trip_count() const { return 1.0f / _exit_prob; } virtual bool is_loop() { return true; } @@ -607,7 +611,7 @@ class Trace : public ResourceObj { Block * next(Block *b) const { return _next_list[b->_pre_order]; } void set_next(Block *b, Block *n) const { _next_list[b->_pre_order] = n; } - // Return the block that preceeds "b" in the trace. + // Return the block that precedes "b" in the trace. Block * prev(Block *b) const { return _prev_list[b->_pre_order]; } void set_prev(Block *b, Block *p) const { _prev_list[b->_pre_order] = p; } diff --git a/hotspot/src/share/vm/opto/buildOopMap.cpp b/hotspot/src/share/vm/opto/buildOopMap.cpp index 30a9d2684d0..4a8612687f0 100644 --- a/hotspot/src/share/vm/opto/buildOopMap.cpp +++ b/hotspot/src/share/vm/opto/buildOopMap.cpp @@ -55,7 +55,7 @@ // breadth-first approach but it was worse (showed O(n^2) in the // pick-next-block code). // -// The relevent data is kept in a struct of arrays (it could just as well be +// The relevant data is kept in a struct of arrays (it could just as well be // an array of structs, but the struct-of-arrays is generally a little more // efficient). The arrays are indexed by register number (including // stack-slots as registers) and so is bounded by 200 to 300 elements in diff --git a/hotspot/src/share/vm/opto/bytecodeInfo.cpp b/hotspot/src/share/vm/opto/bytecodeInfo.cpp index 38623fd5f76..a66c873e282 100644 --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp @@ -232,6 +232,14 @@ const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* calle return "disallowed by CompilerOracle"; } + if (UseStringCache) { + // Do not inline StringCache::profile() method used only at the beginning. + if (callee_method->name() == ciSymbol::profile_name() && + callee_method->holder()->name() == ciSymbol::java_lang_StringCache()) { + return "profiling method"; + } + } + return NULL; } diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 3a516ab98bd..425a66a42c2 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -391,7 +391,7 @@ product(intx, EliminateAllocationArraySizeLimit, 64, \ "Array size (number of elements) limit for scalar replacement") \ \ - product(bool, UseOptoBiasInlining, true, \ + product(bool, UseOptoBiasInlining, true, \ "Generate biased locking code in C2 ideal graph") \ \ product(intx, ValueSearchLimit, 1000, \ @@ -410,7 +410,7 @@ "Miniumum %% of a successor (predecessor) for which block layout "\ "a will allow a fork (join) in a single chain") \ \ - product(bool, BlockLayoutRotateLoops, false, \ + product(bool, BlockLayoutRotateLoops, true, \ "Allow back branches to be fall throughs in the block layour") \ C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG) diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index 7dff291fc1c..811693cce7b 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -975,6 +975,7 @@ SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp, } bool SafePointScalarObjectNode::pinned() const { return true; } +bool SafePointScalarObjectNode::depends_only_on_test() const { return false; } uint SafePointScalarObjectNode::ideal_reg() const { return 0; // No matching to machine instruction diff --git a/hotspot/src/share/vm/opto/callnode.hpp b/hotspot/src/share/vm/opto/callnode.hpp index 06c783364c0..40a4abeae1d 100644 --- a/hotspot/src/share/vm/opto/callnode.hpp +++ b/hotspot/src/share/vm/opto/callnode.hpp @@ -437,6 +437,10 @@ public: // of the SafePoint node for which it was generated. virtual bool pinned() const; // { return true; } + // SafePointScalarObject depends on the SafePoint node + // for which it was generated. + virtual bool depends_only_on_test() const; // { return false; } + virtual uint size_of() const { return sizeof(*this); } // Assumes that "this" is an argument to a safepoint node "s", and that diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp index e29cc0d58e3..e48c15e7914 100644 --- a/hotspot/src/share/vm/opto/cfgnode.cpp +++ b/hotspot/src/share/vm/opto/cfgnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1350,7 +1350,7 @@ static void split_once(PhaseIterGVN *igvn, Node *phi, Node *val, Node *n, Node * } // Register the new node but do not transform it. Cannot transform until the - // entire Region/Phi conglerate has been hacked as a single huge transform. + // entire Region/Phi conglomerate has been hacked as a single huge transform. igvn->register_new_node_with_optimizer( newn ); // Now I can point to the new node. n->add_req(newn); @@ -1381,7 +1381,7 @@ static Node* split_flow_path(PhaseGVN *phase, PhiNode *phi) { Node *val = phi->in(i); // Constant to split for uint hit = 0; // Number of times it occurs - for( ; i < phi->req(); i++ ){ // Count occurances of constant + for( ; i < phi->req(); i++ ){ // Count occurrences of constant Node *n = phi->in(i); if( !n ) return NULL; if( phase->type(n) == Type::TOP ) return NULL; @@ -1423,7 +1423,7 @@ static Node* split_flow_path(PhaseGVN *phase, PhiNode *phi) { //============================================================================= //------------------------------simple_data_loop_check------------------------- -// Try to determing if the phi node in a simple safe/unsafe data loop. +// Try to determining if the phi node in a simple safe/unsafe data loop. // Returns: // enum LoopSafety { Safe = 0, Unsafe, UnsafeLoop }; // Safe - safe case when the phi and it's inputs reference only safe data @@ -1687,7 +1687,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { progress = phase->C->top(); break; } - // If tranformed to a MergeMem, get the desired slice + // If transformed to a MergeMem, get the desired slice // Otherwise the returned node represents memory for every slice Node *new_mem = (m->is_MergeMem()) ? m->as_MergeMem()->memory_at(alias_idx) : m; @@ -1962,7 +1962,7 @@ const Type *CatchNode::Value( PhaseTransform *phase ) const { f[CatchProjNode::fall_through_index] = Type::TOP; } else if( call->req() > TypeFunc::Parms ) { const Type *arg0 = phase->type( call->in(TypeFunc::Parms) ); - // Check for null reciever to virtual or interface calls + // Check for null receiver to virtual or interface calls if( call->is_CallDynamicJava() && arg0->higher_equal(TypePtr::NULL_PTR) ) { f[CatchProjNode::fall_through_index] = Type::TOP; @@ -1995,7 +1995,7 @@ Node *CatchProjNode::Identity( PhaseTransform *phase ) { // also remove any exception table entry. Thus we must know the call // feeding the Catch will not really throw an exception. This is ok for // the main fall-thru control (happens when we know a call can never throw - // an exception) or for "rethrow", because a further optimnization will + // an exception) or for "rethrow", because a further optimization will // yank the rethrow (happens when we inline a function that can throw an // exception and the caller has no handler). Not legal, e.g., for passing // a NULL receiver to a v-call, or passing bad types to a slow-check-cast. diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index 82558d8f577..4ad220d41f5 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -149,6 +149,9 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher) #endif { NOT_PRODUCT( Compile::TracePhase t3("ctorChaitin", &_t_ctorChaitin, TimeCompiler); ) + + _high_frequency_lrg = MIN2(float(OPTO_LRG_HIGH_FREQ), _cfg._outer_loop_freq); + uint i,j; // Build a list of basic blocks, sorted by frequency _blks = NEW_RESOURCE_ARRAY( Block *, _cfg._num_blocks ); @@ -1246,7 +1249,7 @@ uint PhaseChaitin::Select( ) { // If the live range is not bound, then we actually had some choices // to make. In this case, the mask has more bits in it than the colors - // choosen. Restrict the mask to just what was picked. + // chosen. Restrict the mask to just what was picked. if( lrg->num_regs() == 1 ) { // Size 1 live range lrg->Clear(); // Clear the mask lrg->Insert(reg); // Set regmask to match selected reg diff --git a/hotspot/src/share/vm/opto/chaitin.hpp b/hotspot/src/share/vm/opto/chaitin.hpp index 307d6110c04..1cea37e34d1 100644 --- a/hotspot/src/share/vm/opto/chaitin.hpp +++ b/hotspot/src/share/vm/opto/chaitin.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -327,7 +327,7 @@ class PhaseChaitin : public PhaseRegAlloc { // True if lidx is used before any real register is def'd in the block bool prompt_use( Block *b, uint lidx ); Node *get_spillcopy_wide( Node *def, Node *use, uint uidx ); - // Insert the spill at chosen location. Skip over any interveneing Proj's or + // Insert the spill at chosen location. Skip over any intervening Proj's or // Phis. Skip over a CatchNode and projs, inserting in the fall-through block // instead. Update high-pressure indices. Create a new live range. void insert_proj( Block *b, uint i, Node *spill, uint maxlrg ); @@ -338,6 +338,8 @@ class PhaseChaitin : public PhaseRegAlloc { Block **_blks; // Array of blocks sorted by frequency for coalescing + float _high_frequency_lrg; // Frequency at which LRG will be spilled for debug info + #ifndef PRODUCT bool _trace_spilling; #endif @@ -360,6 +362,8 @@ public: uint n2lidx( const Node *n ) const { return _names[n->_idx]; } + float high_frequency_lrg() const { return _high_frequency_lrg; } + #ifndef PRODUCT bool trace_spilling() const { return _trace_spilling; } #endif @@ -431,7 +435,7 @@ private: void Simplify(); // Select colors by re-inserting edges into the IFG. - // Return TRUE if any spills occured. + // Return TRUE if any spills occurred. uint Select( ); // Helper function for select which allows biased coloring OptoReg::Name choose_color( LRG &lrg, int chunk ); diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index bbb3e79990e..b854447d75d 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,11 +129,13 @@ macro(JumpProj) macro(LShiftI) macro(LShiftL) macro(LoadB) +macro(LoadUB) macro(LoadUS) macro(LoadD) macro(LoadD_unaligned) macro(LoadF) macro(LoadI) +macro(LoadUI2L) macro(LoadKlass) macro(LoadNKlass) macro(LoadL) @@ -182,6 +184,8 @@ macro(PCTable) macro(Parm) macro(PartialSubtypeCheck) macro(Phi) +macro(PopCountI) +macro(PopCountL) macro(PowD) macro(PrefetchRead) macro(PrefetchWrite) @@ -214,6 +218,8 @@ macro(StoreL) macro(StoreP) macro(StoreN) macro(StrComp) +macro(StrEquals) +macro(StrIndexOf) macro(SubD) macro(SubF) macro(SubI) diff --git a/hotspot/src/share/vm/opto/coalesce.cpp b/hotspot/src/share/vm/opto/coalesce.cpp index 7d9ab008398..99584ca165c 100644 --- a/hotspot/src/share/vm/opto/coalesce.cpp +++ b/hotspot/src/share/vm/opto/coalesce.cpp @@ -123,7 +123,7 @@ void PhaseChaitin::new_lrg( const Node *x, uint lrg ) { } //------------------------------clone_projs------------------------------------ -// After cloning some rematierialized instruction, clone any MachProj's that +// After cloning some rematerialized instruction, clone any MachProj's that // follow it. Example: Intel zero is XOR, kills flags. Sparc FP constants // use G3 as an address temp. int PhaseChaitin::clone_projs( Block *b, uint idx, Node *con, Node *copy, uint &maxlrg ) { @@ -473,7 +473,7 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { } // End of is two-adr // Insert a copy at a debug use for a lrg which has high frequency - if( (b->_freq < OPTO_DEBUG_SPLIT_FREQ) && n->is_MachSafePoint() ) { + if( b->_freq < OPTO_DEBUG_SPLIT_FREQ || b->is_uncommon(_phc._cfg._bbs) ) { // Walk the debug inputs to the node and check for lrg freq JVMState* jvms = n->jvms(); uint debug_start = jvms ? jvms->debug_start() : 999999; @@ -487,7 +487,7 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { LRG &lrg = lrgs(nidx); // If this lrg has a high frequency use/def - if( lrg._maxfreq >= OPTO_LRG_HIGH_FREQ ) { + if( lrg._maxfreq >= _phc.high_frequency_lrg() ) { // If the live range is also live out of this block (like it // would be for a fast/slow idiom), the normal spill mechanism // does an excellent job. If it is not live out of this block @@ -694,8 +694,8 @@ uint PhaseConservativeCoalesce::compute_separating_interferences(Node *dst_copy, } // End of if not infinite-stack neighbor } // End of if actually inserted } // End of if live range overlaps - } // End of else collect intereferences for 1 node - } // End of while forever, scan back for intereferences + } // End of else collect interferences for 1 node + } // End of while forever, scan back for interferences return reg_degree; } @@ -786,7 +786,7 @@ bool PhaseConservativeCoalesce::copy_copy( Node *dst_copy, Node *src_copy, Block if( rm_size == 0 ) return false; // Another early bail-out test is when we are double-coalescing and the - // 2 copies are seperated by some control flow. + // 2 copies are separated by some control flow. if( dst_copy != src_copy ) { Block *src_b = _phc._cfg._bbs[src_copy->_idx]; Block *b2 = b; diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 7c6f751f8ff..f3197152194 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -337,7 +337,7 @@ void Compile::print_compile_messages() { tty->print_cr("*********************************************************"); } if (env()->break_at_compile()) { - // Open the debugger when compiing this method. + // Open the debugger when compiling this method. tty->print("### Breaking when compiling: "); method()->print_short_name(); tty->cr(); @@ -1191,8 +1191,8 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const { default: ShouldNotReachHere(); } break; - case 2: // No collasping at level 2; keep all splits - case 3: // No collasping at level 3; keep all splits + case 2: // No collapsing at level 2; keep all splits + case 3: // No collapsing at level 3; keep all splits break; default: Unimplemented(); @@ -2005,8 +2005,10 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) { case Op_StoreP: case Op_StoreN: case Op_LoadB: + case Op_LoadUB: case Op_LoadUS: case Op_LoadI: + case Op_LoadUI2L: case Op_LoadKlass: case Op_LoadNKlass: case Op_LoadL: @@ -2079,7 +2081,7 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) { #ifdef _LP64 case Op_CastPP: - if (n->in(1)->is_DecodeN() && UseImplicitNullCheckForNarrowOop) { + if (n->in(1)->is_DecodeN() && Universe::narrow_oop_use_implicit_null_checks()) { Compile* C = Compile::current(); Node* in1 = n->in(1); const Type* t = n->bottom_type(); @@ -2102,7 +2104,7 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) { // [base_reg + offset] // NullCheck base_reg // - // Pin the new DecodeN node to non-null path on these patforms (Sparc) + // Pin the new DecodeN node to non-null path on these platform (Sparc) // to keep the information to which NULL check the new DecodeN node // corresponds to use it as value in implicit_null_check(). // @@ -2134,7 +2136,7 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) { new_in2 = in2->in(1); } else if (in2->Opcode() == Op_ConP) { const Type* t = in2->bottom_type(); - if (t == TypePtr::NULL_PTR && UseImplicitNullCheckForNarrowOop) { + if (t == TypePtr::NULL_PTR && Universe::narrow_oop_use_implicit_null_checks()) { new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); // // This transformation together with CastPP transformation above diff --git a/hotspot/src/share/vm/opto/connode.cpp b/hotspot/src/share/vm/opto/connode.cpp index 7e1cafefa57..46f13c652b6 100644 --- a/hotspot/src/share/vm/opto/connode.cpp +++ b/hotspot/src/share/vm/opto/connode.cpp @@ -71,7 +71,7 @@ testing. to figure out which test post-dominates. The real problem is that it doesn't matter which one you pick. After you pick up, the dominating-test elider in IGVN can remove the test and allow you to hoist up to the dominating test on -the choosen oop bypassing the test on the not-choosen oop. Seen in testing. +the chosen oop bypassing the test on the not-chosen oop. Seen in testing. Oops. (3) Leave the CastPP's in. This makes the graph more accurate in some sense; @@ -433,7 +433,7 @@ Node *ConstraintCastNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { // If not converting int->oop, throw away cast after constant propagation Node *CastPPNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { const Type *t = ccp->type(in(1)); - if (!t->isa_oop_ptr() || in(1)->is_DecodeN()) { + if (!t->isa_oop_ptr() || (in(1)->is_DecodeN() && Universe::narrow_oop_use_implicit_null_checks())) { return NULL; // do not transform raw pointers or narrow oops } return ConstraintCastNode::Ideal_DU_postCCP(ccp); diff --git a/hotspot/src/share/vm/opto/connode.hpp b/hotspot/src/share/vm/opto/connode.hpp index a16d7f2ee84..4c078d1b091 100644 --- a/hotspot/src/share/vm/opto/connode.hpp +++ b/hotspot/src/share/vm/opto/connode.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -635,3 +635,23 @@ class MoveD2LNode : public Node { virtual uint ideal_reg() const { return Op_RegL; } virtual const Type* Value( PhaseTransform *phase ) const; }; + +//---------- PopCountINode ----------------------------------------------------- +// Population count (bit count) of an integer. +class PopCountINode : public Node { +public: + PopCountINode(Node* in1) : Node(0, in1) {} + virtual int Opcode() const; + const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//---------- PopCountLNode ----------------------------------------------------- +// Population count (bit count) of a long. +class PopCountLNode : public Node { +public: + PopCountLNode(Node* in1) : Node(0, in1) {} + virtual int Opcode() const; + const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; diff --git a/hotspot/src/share/vm/opto/divnode.cpp b/hotspot/src/share/vm/opto/divnode.cpp index 67cad067960..55350e11f66 100644 --- a/hotspot/src/share/vm/opto/divnode.cpp +++ b/hotspot/src/share/vm/opto/divnode.cpp @@ -35,7 +35,7 @@ // by constant into a multiply/shift/add series. Return false if calculations // fail. // -// Borrowed almost verbatum from Hacker's Delight by Henry S. Warren, Jr. with +// Borrowed almost verbatim from Hacker's Delight by Henry S. Warren, Jr. with // minor type name and parameter changes. static bool magic_int_divide_constants(jint d, jint &M, jint &s) { int32_t p; @@ -202,7 +202,7 @@ static Node *transform_int_divide( PhaseGVN *phase, Node *dividend, jint divisor // by constant into a multiply/shift/add series. Return false if calculations // fail. // -// Borrowed almost verbatum from Hacker's Delight by Henry S. Warren, Jr. with +// Borrowed almost verbatim from Hacker's Delight by Henry S. Warren, Jr. with // minor type name and parameter changes. Adjusted to 64 bit word width. static bool magic_long_divide_constants(jlong d, jlong &M, jint &s) { int64_t p; @@ -1069,7 +1069,7 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) { int log2_con = -1; - // If this is a power of two, they maybe we can mask it + // If this is a power of two, then maybe we can mask it if( is_power_of_2_long(pos_con) ) { log2_con = log2_long(pos_con); diff --git a/hotspot/src/share/vm/opto/domgraph.cpp b/hotspot/src/share/vm/opto/domgraph.cpp index 2ef02fd0cec..af198e3c71f 100644 --- a/hotspot/src/share/vm/opto/domgraph.cpp +++ b/hotspot/src/share/vm/opto/domgraph.cpp @@ -183,7 +183,7 @@ class Block_Stack { if (pre_order == 1) t->_parent = NULL; // first block doesn't have parent else { - // Save parent (currernt top block on stack) in DFS + // Save parent (current top block on stack) in DFS t->_parent = &_tarjan[_stack_top->block->_pre_order]; } // Now put this block on stack diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index bccfb9c64ba..c9ddc95dcfb 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -515,7 +515,7 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base, PhaseGVN *igvn) { // cause the failure in add_offset() with narrow oops since TypeOopPtr() // constructor verifies correctness of the offset. // - // It could happend on subclass's branch (from the type profiling + // It could happened on subclass's branch (from the type profiling // inlining) which was not eliminated during parsing since the exactness // of the allocation type was not propagated to the subclass type check. // @@ -703,7 +703,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra while (prev != result) { prev = result; if (result == start_mem) - break; // hit one of our sentinals + break; // hit one of our sentinels if (result->is_Mem()) { const Type *at = phase->type(result->in(MemNode::Address)); if (at != Type::TOP) { @@ -720,7 +720,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) { Node *proj_in = result->in(0); if (proj_in->is_Allocate() && proj_in->_idx == (uint)tinst->instance_id()) { - break; // hit one of our sentinals + break; // hit one of our sentinels } else if (proj_in->is_Call()) { CallNode *call = proj_in->as_Call(); if (!call->may_modify(tinst, phase)) { @@ -756,6 +756,16 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra } else { break; } + } else if (result->Opcode() == Op_SCMemProj) { + assert(result->in(0)->is_LoadStore(), "sanity"); + const Type *at = phase->type(result->in(0)->in(MemNode::Address)); + if (at != Type::TOP) { + assert (at->isa_ptr() != NULL, "pointer type required."); + int idx = C->get_alias_index(at->is_ptr()); + assert(idx != alias_idx, "Object is not scalar replaceable if a LoadStore node access its field"); + break; + } + result = result->in(0)->in(MemNode::Memory); } } if (result->is_Phi()) { @@ -794,7 +804,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra // Phase 2: Process MemNode's from memnode_worklist. compute new address type and // search the Memory chain for a store with the appropriate type // address type. If a Phi is found, create a new version with -// the approriate memory slices from each of the Phi inputs. +// the appropriate memory slices from each of the Phi inputs. // For stores, process the users as follows: // MemNode: push on memnode_worklist // MergeMem: push on mergemem_worklist @@ -1548,7 +1558,7 @@ bool ConnectionGraph::compute_escape() { has_non_escaping_obj = true; // Non GlobalEscape Node* n = ptn->_node; if (n->is_Allocate() && ptn->_scalar_replaceable ) { - // Push scalar replaceable alocations on alloc_worklist + // Push scalar replaceable allocations on alloc_worklist // for processing in split_unique_types(). alloc_worklist.append(n); } diff --git a/hotspot/src/share/vm/opto/gcm.cpp b/hotspot/src/share/vm/opto/gcm.cpp index b56fb157119..92d5371153d 100644 --- a/hotspot/src/share/vm/opto/gcm.cpp +++ b/hotspot/src/share/vm/opto/gcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,6 +57,37 @@ void PhaseCFG::schedule_node_into_block( Node *n, Block *b ) { } } +//----------------------------replace_block_proj_ctrl------------------------- +// Nodes that have is_block_proj() nodes as their control need to use +// the appropriate Region for their actual block as their control since +// the projection will be in a predecessor block. +void PhaseCFG::replace_block_proj_ctrl( Node *n ) { + const Node *in0 = n->in(0); + assert(in0 != NULL, "Only control-dependent"); + const Node *p = in0->is_block_proj(); + if (p != NULL && p != n) { // Control from a block projection? + assert(!n->pinned() || n->is_SafePointScalarObject(), "only SafePointScalarObject pinned node is expected here"); + // Find trailing Region + Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block + uint j = 0; + if (pb->_num_succs != 1) { // More then 1 successor? + // Search for successor + uint max = pb->_nodes.size(); + assert( max > 1, "" ); + uint start = max - pb->_num_succs; + // Find which output path belongs to projection + for (j = start; j < max; j++) { + if( pb->_nodes[j] == in0 ) + break; + } + assert( j < max, "must find" ); + // Change control to match head of successor basic block + j -= start; + } + n->set_req(0, pb->_succs[j]->head()); + } +} + //------------------------------schedule_pinned_nodes-------------------------- // Set the basic block for Nodes pinned into blocks @@ -68,8 +99,10 @@ void PhaseCFG::schedule_pinned_nodes( VectorSet &visited ) { Node *n = spstack.pop(); if( !visited.test_set(n->_idx) ) { // Test node and flag it as visited if( n->pinned() && !_bbs.lookup(n->_idx) ) { // Pinned? Nail it down! + assert( n->in(0), "pinned Node must have Control" ); + // Before setting block replace block_proj control edge + replace_block_proj_ctrl(n); Node *input = n->in(0); - assert( input, "pinned Node must have Control" ); while( !input->is_block_start() ) input = input->in(0); Block *b = _bbs[input->_idx]; // Basic block of controlling input @@ -158,34 +191,12 @@ bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) { uint i = nstack_top_i; if (i == 0) { - // Special control input processing. - // While I am here, go ahead and look for Nodes which are taking control - // from a is_block_proj Node. After I inserted RegionNodes to make proper - // blocks, the control at a is_block_proj more properly comes from the - // Region being controlled by the block_proj Node. + // Fixup some control. Constants without control get attached + // to root and nodes that use is_block_proj() nodes should be attached + // to the region that starts their block. const Node *in0 = n->in(0); if (in0 != NULL) { // Control-dependent? - const Node *p = in0->is_block_proj(); - if (p != NULL && p != n) { // Control from a block projection? - // Find trailing Region - Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block - uint j = 0; - if (pb->_num_succs != 1) { // More then 1 successor? - // Search for successor - uint max = pb->_nodes.size(); - assert( max > 1, "" ); - uint start = max - pb->_num_succs; - // Find which output path belongs to projection - for (j = start; j < max; j++) { - if( pb->_nodes[j] == in0 ) - break; - } - assert( j < max, "must find" ); - // Change control to match head of successor basic block - j -= start; - } - n->set_req(0, pb->_succs[j]->head()); - } + replace_block_proj_ctrl(n); } else { // n->in(0) == NULL if (n->req() == 1) { // This guy is a constant with NO inputs? n->set_req(0, _root); @@ -226,6 +237,8 @@ bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) { if (!n->pinned()) { // Set earliest legal block. _bbs.map(n->_idx, find_deepest_input(n, _bbs)); + } else { + assert(_bbs[n->_idx] == _bbs[n->in(0)->_idx], "Pinned Node should be at the same block as its control edge"); } if (nstack.is_empty()) { @@ -425,6 +438,12 @@ Block* PhaseCFG::insert_anti_dependences(Block* LCA, Node* load, bool verify) { #endif assert(load_alias_idx || (load->is_Mach() && load->as_Mach()->ideal_Opcode() == Op_StrComp), "String compare is only known 'load' that does not conflict with any stores"); + assert(load_alias_idx || (load->is_Mach() && load->as_Mach()->ideal_Opcode() == Op_StrEquals), + "String equals is a 'load' that does not conflict with any stores"); + assert(load_alias_idx || (load->is_Mach() && load->as_Mach()->ideal_Opcode() == Op_StrIndexOf), + "String indexOf is a 'load' that does not conflict with any stores"); + assert(load_alias_idx || (load->is_Mach() && load->as_Mach()->ideal_Opcode() == Op_AryEq), + "Arrays equals is a 'load' that do not conflict with any stores"); if (!C->alias_type(load_alias_idx)->is_rewritable()) { // It is impossible to spoil this load by putting stores before it, @@ -593,7 +612,7 @@ Block* PhaseCFG::insert_anti_dependences(Block* LCA, Node* load, bool verify) { if (pred_block != early) { // If any predecessor of the Phi matches the load's "early block", // we do not need a precedence edge between the Phi and 'load' - // since the load will be forced into a block preceeding the Phi. + // since the load will be forced into a block preceding the Phi. pred_block->set_raise_LCA_mark(load_index); assert(!LCA_orig->dominates(pred_block) || early->dominates(pred_block), "early is high enough"); @@ -1361,6 +1380,9 @@ void PhaseCFG::Estimate_Block_Frequency() { _root_loop->_freq = 1.0; _root_loop->scale_freq(); + // Save outmost loop frequency for LRG frequency threshold + _outer_loop_freq = _root_loop->outer_loop_freq(); + // force paths ending at uncommon traps to be infrequent if (!C->do_freq_based_layout()) { Block_List worklist; @@ -1386,7 +1408,7 @@ void PhaseCFG::Estimate_Block_Frequency() { #ifdef ASSERT for (uint i = 0; i < _num_blocks; i++ ) { Block *b = _blocks[i]; - assert(b->_freq >= MIN_BLOCK_FREQUENCY, "Register Allocator requiers meaningful block frequency"); + assert(b->_freq >= MIN_BLOCK_FREQUENCY, "Register Allocator requires meaningful block frequency"); } #endif @@ -1639,7 +1661,7 @@ float Block::succ_prob(uint i) { // successor blocks. assert(_num_succs == 2, "expecting 2 successors of a null check"); // If either successor has only one predecessor, then the - // probabiltity estimate can be derived using the + // probability estimate can be derived using the // relative frequency of the successor and this block. if (_succs[i]->num_preds() == 2) { return _succs[i]->_freq / _freq; @@ -1841,7 +1863,7 @@ void Block::update_uncommon_branch(Block* ub) { } //------------------------------update_succ_freq------------------------------- -// Update the appropriate frequency associated with block 'b', a succesor of +// Update the appropriate frequency associated with block 'b', a successor of // a block in this loop. void CFGLoop::update_succ_freq(Block* b, float freq) { if (b->_loop == this) { @@ -1885,10 +1907,12 @@ bool CFGLoop::in_loop_nest(Block* b) { // Do a top down traversal of loop tree (visit outer loops first.) void CFGLoop::scale_freq() { float loop_freq = _freq * trip_count(); + _freq = loop_freq; for (int i = 0; i < _members.length(); i++) { CFGElement* s = _members.at(i); float block_freq = s->_freq * loop_freq; - if (block_freq < MIN_BLOCK_FREQUENCY) block_freq = MIN_BLOCK_FREQUENCY; + if (g_isnan(block_freq) || block_freq < MIN_BLOCK_FREQUENCY) + block_freq = MIN_BLOCK_FREQUENCY; s->_freq = block_freq; } CFGLoop* ch = _child; @@ -1898,6 +1922,14 @@ void CFGLoop::scale_freq() { } } +// Frequency of outer loop +float CFGLoop::outer_loop_freq() const { + if (_child != NULL) { + return _child->_freq; + } + return _freq; +} + #ifndef PRODUCT //------------------------------dump_tree-------------------------------------- void CFGLoop::dump_tree() const { diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index c0cb4ba0132..e28730d27f1 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1148,7 +1148,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, Node *tst = _gvn.transform( btst ); //----------- - // if peephole optimizations occured, a prior test existed. + // if peephole optimizations occurred, a prior test existed. // If a prior test existed, maybe it dominates as we can avoid this test. if (tst != btst && type == T_OBJECT) { // At this point we want to scan up the CFG to see if we can @@ -1196,7 +1196,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // Consider using 'Reason_class_check' instead? // To cause an implicit null check, we set the not-null probability - // to the maximum (PROB_MAX). For an explicit check the probablity + // to the maximum (PROB_MAX). For an explicit check the probability // is set to a smaller value. if (null_control != NULL || too_many_traps(reason)) { // probability is less likely @@ -2277,7 +2277,7 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { r_not_subtype->init_req(1, _gvn.transform( new (C, 1) IfTrueNode (iff2) ) ); set_control( _gvn.transform( new (C, 1) IfFalseNode(iff2) ) ); - // Check for self. Very rare to get here, but its taken 1/3 the time. + // Check for self. Very rare to get here, but it is taken 1/3 the time. // No performance impact (too rare) but allows sharing of secondary arrays // which has some footprint reduction. Node *cmp3 = _gvn.transform( new (C, 3) CmpPNode( subklass, superklass ) ); @@ -2286,11 +2286,27 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { r_ok_subtype->init_req(2, _gvn.transform( new (C, 1) IfTrueNode ( iff3 ) ) ); set_control( _gvn.transform( new (C, 1) IfFalseNode( iff3 ) ) ); + // -- Roads not taken here: -- + // We could also have chosen to perform the self-check at the beginning + // of this code sequence, as the assembler does. This would not pay off + // the same way, since the optimizer, unlike the assembler, can perform + // static type analysis to fold away many successful self-checks. + // Non-foldable self checks work better here in second position, because + // the initial primary superclass check subsumes a self-check for most + // types. An exception would be a secondary type like array-of-interface, + // which does not appear in its own primary supertype display. + // Finally, we could have chosen to move the self-check into the + // PartialSubtypeCheckNode, and from there out-of-line in a platform + // dependent manner. But it is worthwhile to have the check here, + // where it can be perhaps be optimized. The cost in code space is + // small (register compare, branch). + // Now do a linear scan of the secondary super-klass array. Again, no real // performance impact (too rare) but it's gotta be done. - // (The stub also contains the self-check of subklass == superklass. // Since the code is rarely used, there is no penalty for moving it - // out of line, and it can only improve I-cache density.) + // out of line, and it can only improve I-cache density. + // The decision to inline or out-of-line this final check is platform + // dependent, and is found in the AD file definition of PartialSubtypeCheck. Node* psc = _gvn.transform( new (C, 3) PartialSubtypeCheckNode(control(), subklass, superklass) ); diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index 160e3376c95..7445aa277b7 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp index ad45b566eda..a375b92a93b 100644 --- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp +++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/opto/ifg.cpp b/hotspot/src/share/vm/opto/ifg.cpp index b3250513d7a..9d260cbec67 100644 --- a/hotspot/src/share/vm/opto/ifg.cpp +++ b/hotspot/src/share/vm/opto/ifg.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -292,7 +292,7 @@ void PhaseIFG::verify( const PhaseChaitin *pc ) const { //------------------------------interfere_with_live---------------------------- // Interfere this register with everything currently live. Use the RegMasks // to trim the set of possible interferences. Return a count of register-only -// inteferences as an estimate of register pressure. +// interferences as an estimate of register pressure. void PhaseChaitin::interfere_with_live( uint r, IndexSet *liveout ) { uint retval = 0; // Interfere with everything live. diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index 4f230765ab8..38fab34a50d 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -81,7 +81,7 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { uint i4; for( i4 = 1; i4 < phi->req(); i4++ ) { con1 = phi->in(i4); - if( !con1 ) return NULL; // Do not optimize partially collaped merges + if( !con1 ) return NULL; // Do not optimize partially collapsed merges if( con1->is_Con() ) break; // Found a constant // Also allow null-vs-not-null checks const TypePtr *tp = igvn->type(con1)->isa_ptr(); @@ -204,7 +204,7 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { // T F T F T F // ..s.. ..t .. ..s.. ..t.. ..s.. ..t.. // - // Split the paths coming into the merge point into 2 seperate groups of + // Split the paths coming into the merge point into 2 separate groups of // merges. On the left will be all the paths feeding constants into the // Cmp's Phi. On the right will be the remaining paths. The Cmp's Phi // will fold up into a constant; this will let the Cmp fold up as well as @@ -236,7 +236,7 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { } // Register the new RegionNodes but do not transform them. Cannot - // transform until the entire Region/Phi conglerate has been hacked + // transform until the entire Region/Phi conglomerate has been hacked // as a single huge transform. igvn->register_new_node_with_optimizer( region_c ); igvn->register_new_node_with_optimizer( region_x ); @@ -599,7 +599,7 @@ const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node *val, Node* if_proj //------------------------------fold_compares---------------------------- // See if a pair of CmpIs can be converted into a CmpU. In some cases -// the direction of this if is determined by the preciding if so it +// the direction of this if is determined by the preceding if so it // can be eliminate entirely. Given an if testing (CmpI n c) check // for an immediately control dependent if that is testing (CmpI n c2) // and has one projection leading to this if and the other projection @@ -811,7 +811,7 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Try to remove extra range checks. All 'up_one_dom' gives up at merges // so all checks we inspect post-dominate the top-most check we find. // If we are going to fail the current check and we reach the top check - // then we are guarenteed to fail, so just start interpreting there. + // then we are guaranteed to fail, so just start interpreting there. // We 'expand' the top 2 range checks to include all post-dominating // checks. diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index dcedbd61f83..31de55a5435 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,6 +137,8 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe if( mach->in(2) != val ) continue; break; // Found a memory op? case Op_StrComp: + case Op_StrEquals: + case Op_StrIndexOf: case Op_AryEq: // Not a legit memory op for implicit null check regardless of // embedded loads @@ -158,7 +160,14 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe continue; // Give up if offset is beyond page size // cannot reason about it; is probably not implicit null exception } else { - const TypePtr* tptr = base->bottom_type()->is_ptr(); + const TypePtr* tptr; + if (UseCompressedOops && Universe::narrow_oop_shift() == 0) { + // 32-bits narrow oop can be the base of address expressions + tptr = base->bottom_type()->make_ptr(); + } else { + // only regular oops are expected here + tptr = base->bottom_type()->is_ptr(); + } // Give up if offset is not a compile-time constant if( offset == Type::OffsetBot || tptr->_offset == Type::OffsetBot ) continue; diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 17a5c1f79d1..a57333fd5a0 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,6 +136,7 @@ class LibraryCallKit : public GraphKit { bool inline_string_compareTo(); bool inline_string_indexOf(); Node* string_indexOf(Node* string_object, ciTypeArray* target_array, jint offset, jint cache_i, jint md2_i); + bool inline_string_equals(); Node* pop_math_arg(); bool runtime_math(const TypeFunc* call_type, address funcAddr, const char* funcName); bool inline_math_native(vmIntrinsics::ID id); @@ -221,6 +222,7 @@ class LibraryCallKit : public GraphKit { bool inline_unsafe_CAS(BasicType type); bool inline_unsafe_ordered_store(BasicType type); bool inline_fp_conversions(vmIntrinsics::ID id); + bool inline_bitCount(vmIntrinsics::ID id); bool inline_reverseBytes(vmIntrinsics::ID id); }; @@ -260,6 +262,7 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { switch (id) { case vmIntrinsics::_indexOf: case vmIntrinsics::_compareTo: + case vmIntrinsics::_equals: case vmIntrinsics::_equalsC: break; // InlineNatives does not control String.compareTo default: @@ -274,6 +277,9 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { case vmIntrinsics::_indexOf: if (!SpecialStringIndexOf) return NULL; break; + case vmIntrinsics::_equals: + if (!SpecialStringEquals) return NULL; + break; case vmIntrinsics::_equalsC: if (!SpecialArraysEquals) return NULL; break; @@ -314,6 +320,11 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { if (!JDK_Version::is_gte_jdk14x_version()) return NULL; break; + case vmIntrinsics::_bitCount_i: + case vmIntrinsics::_bitCount_l: + if (!UsePopCountInstruction) return NULL; + break; + default: break; } @@ -436,6 +447,8 @@ bool LibraryCallKit::try_to_inline() { return inline_string_compareTo(); case vmIntrinsics::_indexOf: return inline_string_indexOf(); + case vmIntrinsics::_equals: + return inline_string_equals(); case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, false); @@ -617,6 +630,10 @@ bool LibraryCallKit::try_to_inline() { case vmIntrinsics::_longBitsToDouble: return inline_fp_conversions(intrinsic_id()); + case vmIntrinsics::_bitCount_i: + case vmIntrinsics::_bitCount_l: + return inline_bitCount(intrinsic_id()); + case vmIntrinsics::_reverseBytes_i: case vmIntrinsics::_reverseBytes_l: return inline_reverseBytes((vmIntrinsics::ID) intrinsic_id()); @@ -783,6 +800,8 @@ Node* LibraryCallKit::generate_current_thread(Node* &tls_output) { //------------------------------inline_string_compareTo------------------------ bool LibraryCallKit::inline_string_compareTo() { + if (!Matcher::has_match_rule(Op_StrComp)) return false; + const int value_offset = java_lang_String::value_offset_in_bytes(); const int count_offset = java_lang_String::count_offset_in_bytes(); const int offset_offset = java_lang_String::offset_offset_in_bytes(); @@ -820,6 +839,82 @@ bool LibraryCallKit::inline_string_compareTo() { return true; } +//------------------------------inline_string_equals------------------------ +bool LibraryCallKit::inline_string_equals() { + + if (!Matcher::has_match_rule(Op_StrEquals)) return false; + + const int value_offset = java_lang_String::value_offset_in_bytes(); + const int count_offset = java_lang_String::count_offset_in_bytes(); + const int offset_offset = java_lang_String::offset_offset_in_bytes(); + + _sp += 2; + Node* argument = pop(); // pop non-receiver first: it was pushed second + Node* receiver = pop(); + + // Null check on self without removing any arguments. The argument + // null check technically happens in the wrong place, which can lead to + // invalid stack traces when string compare is inlined into a method + // which handles NullPointerExceptions. + _sp += 2; + receiver = do_null_check(receiver, T_OBJECT); + //should not do null check for argument for String.equals(), because spec + //allows to specify NULL as argument. + _sp -= 2; + + if (stopped()) { + return true; + } + + // get String klass for instanceOf + ciInstanceKlass* klass = env()->String_klass(); + + // two paths (plus control) merge + RegionNode* region = new (C, 3) RegionNode(3); + Node* phi = new (C, 3) PhiNode(region, TypeInt::BOOL); + + Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass))); + Node* cmp = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1))); + Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq)); + + IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); + + Node* if_true = _gvn.transform(new (C, 1) IfTrueNode(iff)); + set_control(if_true); + + const TypeInstPtr* string_type = + TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); + + // instanceOf == true + Node* equals = + _gvn.transform(new (C, 7) StrEqualsNode( + control(), + memory(TypeAryPtr::CHARS), + memory(string_type->add_offset(value_offset)), + memory(string_type->add_offset(count_offset)), + memory(string_type->add_offset(offset_offset)), + receiver, + argument)); + + phi->init_req(1, _gvn.transform(equals)); + region->init_req(1, if_true); + + //instanceOf == false, fallthrough + Node* if_false = _gvn.transform(new (C, 1) IfFalseNode(iff)); + set_control(if_false); + + phi->init_req(2, _gvn.transform(intcon(0))); + region->init_req(2, if_false); + + // post merge + set_control(_gvn.transform(region)); + record_for_igvn(region); + + push(_gvn.transform(phi)); + + return true; +} + //------------------------------inline_array_equals---------------------------- bool LibraryCallKit::inline_array_equals() { @@ -984,80 +1079,115 @@ Node* LibraryCallKit::string_indexOf(Node* string_object, ciTypeArray* target_ar return result; } - //------------------------------inline_string_indexOf------------------------ bool LibraryCallKit::inline_string_indexOf() { - _sp += 2; - Node *argument = pop(); // pop non-receiver first: it was pushed second - Node *receiver = pop(); - - // don't intrinsify is argument isn't a constant string. - if (!argument->is_Con()) { - return false; - } - const TypeOopPtr* str_type = _gvn.type(argument)->isa_oopptr(); - if (str_type == NULL) { - return false; - } - ciInstanceKlass* klass = env()->String_klass(); - ciObject* str_const = str_type->const_oop(); - if (str_const == NULL || str_const->klass() != klass) { - return false; - } - ciInstance* str = str_const->as_instance(); - assert(str != NULL, "must be instance"); - const int value_offset = java_lang_String::value_offset_in_bytes(); const int count_offset = java_lang_String::count_offset_in_bytes(); const int offset_offset = java_lang_String::offset_offset_in_bytes(); - ciObject* v = str->field_value_by_offset(value_offset).as_object(); - int o = str->field_value_by_offset(offset_offset).as_int(); - int c = str->field_value_by_offset(count_offset).as_int(); - ciTypeArray* pat = v->as_type_array(); // pattern (argument) character array - - // constant strings have no offset and count == length which - // simplifies the resulting code somewhat so lets optimize for that. - if (o != 0 || c != pat->length()) { - return false; - } - - // Null check on self without removing any arguments. The argument - // null check technically happens in the wrong place, which can lead to - // invalid stack traces when string compare is inlined into a method - // which handles NullPointerExceptions. _sp += 2; - receiver = do_null_check(receiver, T_OBJECT); - // No null check on the argument is needed since it's a constant String oop. - _sp -= 2; - if (stopped()) { - return true; - } + Node *argument = pop(); // pop non-receiver first: it was pushed second + Node *receiver = pop(); - // The null string as a pattern always returns 0 (match at beginning of string) - if (c == 0) { - push(intcon(0)); - return true; - } + Node* result; + if (Matcher::has_match_rule(Op_StrIndexOf) && + UseSSE42Intrinsics) { + // Generate SSE4.2 version of indexOf + // We currently only have match rules that use SSE4.2 - jchar lastChar = pat->char_at(o + (c - 1)); - int cache = 0; - int i; - for (i = 0; i < c - 1; i++) { - assert(i < pat->length(), "out of range"); - cache |= (1 << (pat->char_at(o + i) & (sizeof(cache) * BitsPerByte - 1))); - } + // Null check on self without removing any arguments. The argument + // null check technically happens in the wrong place, which can lead to + // invalid stack traces when string compare is inlined into a method + // which handles NullPointerExceptions. + _sp += 2; + receiver = do_null_check(receiver, T_OBJECT); + argument = do_null_check(argument, T_OBJECT); + _sp -= 2; - int md2 = c; - for (i = 0; i < c - 1; i++) { - assert(i < pat->length(), "out of range"); - if (pat->char_at(o + i) == lastChar) { - md2 = (c - 1) - i; + if (stopped()) { + return true; } + + ciInstanceKlass* klass = env()->String_klass(); + const TypeInstPtr* string_type = + TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); + + result = + _gvn.transform(new (C, 7) + StrIndexOfNode(control(), + memory(TypeAryPtr::CHARS), + memory(string_type->add_offset(value_offset)), + memory(string_type->add_offset(count_offset)), + memory(string_type->add_offset(offset_offset)), + receiver, + argument)); + } else { //Use LibraryCallKit::string_indexOf + // don't intrinsify is argument isn't a constant string. + if (!argument->is_Con()) { + return false; + } + const TypeOopPtr* str_type = _gvn.type(argument)->isa_oopptr(); + if (str_type == NULL) { + return false; + } + ciInstanceKlass* klass = env()->String_klass(); + ciObject* str_const = str_type->const_oop(); + if (str_const == NULL || str_const->klass() != klass) { + return false; + } + ciInstance* str = str_const->as_instance(); + assert(str != NULL, "must be instance"); + + ciObject* v = str->field_value_by_offset(value_offset).as_object(); + int o = str->field_value_by_offset(offset_offset).as_int(); + int c = str->field_value_by_offset(count_offset).as_int(); + ciTypeArray* pat = v->as_type_array(); // pattern (argument) character array + + // constant strings have no offset and count == length which + // simplifies the resulting code somewhat so lets optimize for that. + if (o != 0 || c != pat->length()) { + return false; + } + + // Null check on self without removing any arguments. The argument + // null check technically happens in the wrong place, which can lead to + // invalid stack traces when string compare is inlined into a method + // which handles NullPointerExceptions. + _sp += 2; + receiver = do_null_check(receiver, T_OBJECT); + // No null check on the argument is needed since it's a constant String oop. + _sp -= 2; + if (stopped()) { + return true; + } + + // The null string as a pattern always returns 0 (match at beginning of string) + if (c == 0) { + push(intcon(0)); + return true; + } + + // Generate default indexOf + jchar lastChar = pat->char_at(o + (c - 1)); + int cache = 0; + int i; + for (i = 0; i < c - 1; i++) { + assert(i < pat->length(), "out of range"); + cache |= (1 << (pat->char_at(o + i) & (sizeof(cache) * BitsPerByte - 1))); + } + + int md2 = c; + for (i = 0; i < c - 1; i++) { + assert(i < pat->length(), "out of range"); + if (pat->char_at(o + i) == lastChar) { + md2 = (c - 1) - i; + } + } + + result = string_indexOf(receiver, pat, o, cache, md2); } - Node* result = string_indexOf(receiver, pat, o, cache, md2); push(result); return true; } @@ -1267,7 +1397,7 @@ bool LibraryCallKit::inline_pow(vmIntrinsics::ID id) { // result = DPow(x,y); // } // if (result != result)? { - // ucommon_trap(); + // uncommon_trap(); // } // return result; @@ -1324,7 +1454,7 @@ bool LibraryCallKit::inline_pow(vmIntrinsics::ID id) { // Check if (y isn't int) then go to slow path Node *bol2 = _gvn.transform( new (C, 2) BoolNode( cmpinty, BoolTest::ne ) ); - // Branch eith way + // Branch either way IfNode *if2 = create_and_xform_if(complex_path,bol2, PROB_STATIC_INFREQUENT, COUNT_UNKNOWN); Node *slow_path = opt_iff(r,if2); // Set region path 2 @@ -1714,9 +1844,30 @@ inline Node* LibraryCallKit::make_unsafe_address(Node* base, Node* offset) { } } +//----------------------------inline_bitCount_int/long----------------------- +// inline int Integer.bitCount(int) +// inline int Long.bitCount(long) +bool LibraryCallKit::inline_bitCount(vmIntrinsics::ID id) { + assert(id == vmIntrinsics::_bitCount_i || id == vmIntrinsics::_bitCount_l, "not bitCount"); + if (id == vmIntrinsics::_bitCount_i && !Matcher::has_match_rule(Op_PopCountI)) return false; + if (id == vmIntrinsics::_bitCount_l && !Matcher::has_match_rule(Op_PopCountL)) return false; + _sp += arg_size(); // restore stack pointer + switch (id) { + case vmIntrinsics::_bitCount_i: + push(_gvn.transform(new (C, 2) PopCountINode(pop()))); + break; + case vmIntrinsics::_bitCount_l: + push(_gvn.transform(new (C, 2) PopCountLNode(pop_pair()))); + break; + default: + ShouldNotReachHere(); + } + return true; +} + //----------------------------inline_reverseBytes_int/long------------------- -// inline Int.reverseBytes(int) -// inline Long.reverseByes(long) +// inline Integer.reverseBytes(int) +// inline Long.reverseBytes(long) bool LibraryCallKit::inline_reverseBytes(vmIntrinsics::ID id) { assert(id == vmIntrinsics::_reverseBytes_i || id == vmIntrinsics::_reverseBytes_l, "not reverse Bytes"); if (id == vmIntrinsics::_reverseBytes_i && !Matcher::has_match_rule(Op_ReverseBytesI)) return false; @@ -1915,7 +2066,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // addition to memory membars when is_volatile. This is a little // too strong, but avoids the need to insert per-alias-type // volatile membars (for stores; compare Parse::do_put_xxx), which - // we cannot do effctively here because we probably only have a + // we cannot do effectively here because we probably only have a // rough approximation of type. need_mem_bar = true; // For Stores, place a memory ordering barrier now. @@ -2099,7 +2250,7 @@ bool LibraryCallKit::inline_unsafe_CAS(BasicType type) { // overly confusing. (This is a true fact! I originally combined // them, but even I was confused by it!) As much code/comments as // possible are retained from inline_unsafe_access though to make - // the correspondances clearer. - dl + // the correspondences clearer. - dl if (callee()->is_static()) return false; // caller must have the capability! @@ -2166,7 +2317,7 @@ bool LibraryCallKit::inline_unsafe_CAS(BasicType type) { int alias_idx = C->get_alias_index(adr_type); // Memory-model-wise, a CAS acts like a little synchronized block, - // so needs barriers on each side. These don't't translate into + // so needs barriers on each side. These don't translate into // actual barriers on most machines, but we still need rest of // compiler to respect ordering. @@ -3208,7 +3359,7 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { Node *hash_shift = _gvn.intcon(markOopDesc::hash_shift); Node *hshifted_header= _gvn.transform( new (C, 3) URShiftXNode(header, hash_shift) ); // This hack lets the hash bits live anywhere in the mark object now, as long - // as the shift drops the relevent bits into the low 32 bits. Note that + // as the shift drops the relevant bits into the low 32 bits. Note that // Java spec says that HashCode is an int so there's no point in capturing // an 'X'-sized hashcode (32 in 32-bit build or 64 in 64-bit build). hshifted_header = ConvX2I(hshifted_header); @@ -3255,7 +3406,7 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { } //---------------------------inline_native_getClass---------------------------- -// Build special case code for calls to hashCode on an object. +// Build special case code for calls to getClass on an object. bool LibraryCallKit::inline_native_getClass() { Node* obj = null_check_receiver(callee()); if (stopped()) return true; @@ -4594,7 +4745,7 @@ LibraryCallKit::generate_arraycopy(const TypePtr* adr_type, } // The memory edges above are precise in order to model effects around - // array copyies accurately to allow value numbering of field loads around + // array copies accurately to allow value numbering of field loads around // arraycopy. Such field loads, both before and after, are common in Java // collections and similar classes involving header/array data structures. // diff --git a/hotspot/src/share/vm/opto/live.cpp b/hotspot/src/share/vm/opto/live.cpp index d2ff515058c..6f034faa8e1 100644 --- a/hotspot/src/share/vm/opto/live.cpp +++ b/hotspot/src/share/vm/opto/live.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ // Leftover bits become the new live-in for the predecessor block, and the pred // block is put on the worklist. // The locally live-in stuff is computed once and added to predecessor -// live-out sets. This seperate compilation is done in the outer loop below. +// live-out sets. This separate compilation is done in the outer loop below. PhaseLive::PhaseLive( const PhaseCFG &cfg, LRG_List &names, Arena *arena ) : Phase(LIVE), _cfg(cfg), _names(names), _arena(arena), _live(0) { } diff --git a/hotspot/src/share/vm/opto/locknode.cpp b/hotspot/src/share/vm/opto/locknode.cpp index 0099284a701..f6a01222117 100644 --- a/hotspot/src/share/vm/opto/locknode.cpp +++ b/hotspot/src/share/vm/opto/locknode.cpp @@ -121,7 +121,7 @@ void Parse::do_monitor_exit() { kill_dead_locals(); pop(); // Pop oop to unlock - // Because monitors are guarenteed paired (else we bail out), we know + // Because monitors are guaranteed paired (else we bail out), we know // the matching Lock for this Unlock. Hence we know there is no need // for a null check on Unlock. shared_unlock(map()->peek_monitor_box(), map()->peek_monitor_obj()); diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index caa676f6ffd..4ff59d9d46e 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -119,7 +119,7 @@ void IdealLoopTree::compute_profile_trip_cnt( PhaseIdealLoop *phase ) { //---------------------is_invariant_addition----------------------------- // Return nonzero index of invariant operand for an Add or Sub -// of (nonconstant) invariant and variant values. Helper for reassoicate_invariants. +// of (nonconstant) invariant and variant values. Helper for reassociate_invariants. int IdealLoopTree::is_invariant_addition(Node* n, PhaseIdealLoop *phase) { int op = n->Opcode(); if (op == Op_AddI || op == Op_SubI) { @@ -520,7 +520,7 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const { //------------------------------policy_align----------------------------------- // Return TRUE or FALSE if the loop should be cache-line aligned. Gather the // expression that does the alignment. Note that only one array base can be -// aligned in a loop (unless the VM guarentees mutual alignment). Note that +// aligned in a loop (unless the VM guarantees mutual alignment). Note that // if we vectorize short memory ops into longer memory ops, we may want to // increase alignment. bool IdealLoopTree::policy_align( PhaseIdealLoop *phase ) const { diff --git a/hotspot/src/share/vm/opto/loopUnswitch.cpp b/hotspot/src/share/vm/opto/loopUnswitch.cpp index 2a385e76846..4bb67ad0f8a 100644 --- a/hotspot/src/share/vm/opto/loopUnswitch.cpp +++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp @@ -131,7 +131,7 @@ void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) { ProjNode* proj_false = invar_iff->proj_out(0)->as_Proj(); - // Hoist invariant casts out of each loop to the appropiate + // Hoist invariant casts out of each loop to the appropriate // control projection. Node_List worklist; diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index fba4a350bbb..a36d0a534fc 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -274,7 +274,7 @@ Node *PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { // // Canonicalize the condition on the test. If we can exactly determine // the trip-counter exit value, then set limit to that value and use - // a '!=' test. Otherwise use conditon '<' for count-up loops and + // a '!=' test. Otherwise use condition '<' for count-up loops and // '>' for count-down loops. If the condition is inverted and we will // be rolling through MININT to MAXINT, then bail out. @@ -290,7 +290,7 @@ Node *PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { // If compare points to incr, we are ok. Otherwise the compare // can directly point to the phi; in this case adjust the compare so that - // it points to the incr by adusting the limit. + // it points to the incr by adjusting the limit. if( cmp->in(1) == phi || cmp->in(2) == phi ) limit = gvn->transform(new (C, 3) AddINode(limit,stride)); @@ -471,7 +471,7 @@ Node *PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { lazy_replace( x, l ); set_idom(l, init_control, dom_depth(x)); - // Check for immediately preceeding SafePoint and remove + // Check for immediately preceding SafePoint and remove Node *sfpt2 = le->in(0); if( sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); @@ -1506,7 +1506,7 @@ PhaseIdealLoop::PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify // Build Dominators for elision of NULL checks & loop finding. // Since nodes do not have a slot for immediate dominator, make - // a persistant side array for that info indexed on node->_idx. + // a persistent side array for that info indexed on node->_idx. _idom_size = C->unique(); _idom = NEW_RESOURCE_ARRAY( Node*, _idom_size ); _dom_depth = NEW_RESOURCE_ARRAY( uint, _idom_size ); @@ -1529,7 +1529,7 @@ PhaseIdealLoop::PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify // Given dominators, try to find inner loops with calls that must // always be executed (call dominates loop tail). These loops do - // not need a seperate safepoint. + // not need a separate safepoint. Node_List cisstack(a); _ltree_root->check_safepts(visited, cisstack); @@ -2332,7 +2332,7 @@ void PhaseIdealLoop::build_loop_early( VectorSet &visited, Node_List &worklist, if (done) { // All of n's inputs have been processed, complete post-processing. - // Compute earilest point this Node can go. + // Compute earliest point this Node can go. // CFG, Phi, pinned nodes already know their controlling input. if (!has_node(n)) { // Record earliest legal location @@ -2668,13 +2668,15 @@ void PhaseIdealLoop::build_loop_late_post( Node *n, const PhaseIdealLoop *verify case Op_LoadD_unaligned: case Op_LoadL_unaligned: case Op_StrComp: // Does a bunch of load-like effects + case Op_StrEquals: + case Op_StrIndexOf: case Op_AryEq: pinned = false; } if( pinned ) { - IdealLoopTree *choosen_loop = get_loop(n->is_CFG() ? n : get_ctrl(n)); - if( !choosen_loop->_child ) // Inner loop? - choosen_loop->_body.push(n); // Collect inner loops + IdealLoopTree *chosen_loop = get_loop(n->is_CFG() ? n : get_ctrl(n)); + if( !chosen_loop->_child ) // Inner loop? + chosen_loop->_body.push(n); // Collect inner loops return; } } else { // No slot zero @@ -2746,9 +2748,9 @@ void PhaseIdealLoop::build_loop_late_post( Node *n, const PhaseIdealLoop *verify set_ctrl(n, least); // Collect inner loop bodies - IdealLoopTree *choosen_loop = get_loop(least); - if( !choosen_loop->_child ) // Inner loop? - choosen_loop->_body.push(n);// Collect inner loops + IdealLoopTree *chosen_loop = get_loop(least); + if( !chosen_loop->_child ) // Inner loop? + chosen_loop->_body.push(n);// Collect inner loops } #ifndef PRODUCT diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index 53775646696..ab172a3eb43 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -390,7 +390,7 @@ public: // Return TRUE or FALSE if the loop should be cache-line aligned. // Gather the expression that does the alignment. Note that only - // one array base can be aligned in a loop (unless the VM guarentees + // one array base can be aligned in a loop (unless the VM guarantees // mutual alignment). Note that if we vectorize short memory ops // into longer memory ops, we may want to increase alignment. bool policy_align( PhaseIdealLoop *phase ) const; @@ -403,7 +403,7 @@ public: // Reassociate invariant add and subtract expressions. Node* reassociate_add_sub(Node* n1, PhaseIdealLoop *phase); // Return nonzero index of invariant operand if invariant and variant - // are combined with an Add or Sub. Helper for reassoicate_invariants. + // are combined with an Add or Sub. Helper for reassociate_invariants. int is_invariant_addition(Node* n, PhaseIdealLoop *phase); // Return true if n is invariant diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index 41048cbcbe9..454c207fd81 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -97,7 +97,7 @@ Node *PhaseIdealLoop::split_thru_phi( Node *n, Node *region, int policy ) { // (Note: This tweaking with igvn only works because x is a new node.) _igvn.set_type(x, t); // If x is a TypeNode, capture any more-precise type permanently into Node - // othewise it will be not updated during igvn->transform since + // otherwise it will be not updated during igvn->transform since // igvn->type(x) is set to x->Value() already. x->raise_bottom_type(t); Node *y = x->Identity(&_igvn); @@ -879,7 +879,7 @@ void PhaseIdealLoop::split_if_with_blocks_post( Node *n ) { Node *x_ctrl = NULL; if( u->is_Phi() ) { // Replace all uses of normal nodes. Replace Phi uses - // individually, so the seperate Nodes can sink down + // individually, so the separate Nodes can sink down // different paths. uint k = 1; while( u->in(k) != n ) k++; diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp index eadd0da5fff..b7357f86ab6 100644 --- a/hotspot/src/share/vm/opto/machnode.cpp +++ b/hotspot/src/share/vm/opto/machnode.cpp @@ -136,7 +136,7 @@ void MachNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { // Size of instruction in bytes uint MachNode::size(PhaseRegAlloc *ra_) const { // If a virtual was not defined for this specific instruction, - // Call the helper which finds the size by emiting the bits. + // Call the helper which finds the size by emitting the bits. return MachNode::emit_size(ra_); } @@ -340,6 +340,10 @@ const class TypePtr *MachNode::adr_type() const { if (base == NodeSentinel) return TypePtr::BOTTOM; const Type* t = base->bottom_type(); + if (UseCompressedOops && Universe::narrow_oop_shift() == 0) { + // 32-bit unscaled narrow oop can be the base of any address expression + t = t->make_ptr(); + } if (t->isa_intptr_t() && offset != 0 && offset != Type::OffsetBot) { // We cannot assert that the offset does not look oop-ish here. // Depending on the heap layout the cardmark base could land @@ -353,6 +357,7 @@ const class TypePtr *MachNode::adr_type() const { // be conservative if we do not recognize the type if (tp == NULL) { + assert(false, "this path may produce not optimal code"); return TypePtr::BOTTOM; } assert(tp->base() != Type::AnyPtr, "not a bare pointer"); diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index f77b14ada56..239bc05af6d 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,7 @@ void PhaseMacroExpand::copy_call_debug_info(CallNode *oldcall, CallNode * newcal uint old_unique = C->unique(); Node* new_in = old_sosn->clone(jvms_adj, sosn_map); if (old_unique != C->unique()) { + new_in->set_req(0, newcall->in(0)); // reset control edge new_in = transform_later(new_in); // Register new node. } old_in = new_in; @@ -215,7 +216,7 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me const TypeOopPtr *tinst = phase->C->get_adr_type(alias_idx)->isa_oopptr(); while (true) { if (mem == alloc_mem || mem == start_mem ) { - return mem; // hit one of our sentinals + return mem; // hit one of our sentinels } else if (mem->is_MergeMem()) { mem = mem->as_MergeMem()->memory_at(alias_idx); } else if (mem->is_Proj() && mem->as_Proj()->_con == TypeFunc::Memory) { @@ -250,6 +251,15 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me assert(adr_idx == Compile::AliasIdxRaw, "address must match or be raw"); } mem = mem->in(MemNode::Memory); + } else if (mem->Opcode() == Op_SCMemProj) { + assert(mem->in(0)->is_LoadStore(), "sanity"); + const TypePtr* atype = mem->in(0)->in(MemNode::Address)->bottom_type()->is_ptr(); + int adr_idx = Compile::current()->get_alias_index(atype); + if (adr_idx == alias_idx) { + assert(false, "Object is not scalar replaceable if a LoadStore node access its field"); + return NULL; + } + mem = mem->in(0)->in(MemNode::Memory); } else { return mem; } @@ -329,8 +339,15 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type * return NULL; } values.at_put(j, val); + } else if (val->Opcode() == Op_SCMemProj) { + assert(val->in(0)->is_LoadStore(), "sanity"); + assert(false, "Object is not scalar replaceable if a LoadStore node access its field"); + return NULL; } else { +#ifdef ASSERT + val->dump(); assert(false, "unknown node on this path"); +#endif return NULL; // unknown node on this path } } @@ -1651,7 +1668,7 @@ void PhaseMacroExpand::expand_lock_node(LockNode *lock) { if (UseOptoBiasInlining) { /* - * See the full descrition in MacroAssembler::biased_locking_enter(). + * See the full description in MacroAssembler::biased_locking_enter(). * * if( (mark_word & biased_lock_mask) == biased_lock_pattern ) { * // The object is biased. @@ -1887,7 +1904,7 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) { if (UseOptoBiasInlining) { // Check for biased locking unlock case, which is a no-op. - // See the full descrition in MacroAssembler::biased_locking_exit(). + // See the full description in MacroAssembler::biased_locking_exit(). region = new (C, 4) RegionNode(4); // create a Phi for the memory state mem_phi = new (C, 4) PhiNode( region, Type::MEMORY, TypeRawPtr::BOTTOM); diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index e911c065ccd..e230480b22a 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -746,6 +746,8 @@ static void match_alias_type(Compile* C, Node* n, Node* m) { if (nidx == Compile::AliasIdxBot && midx == Compile::AliasIdxTop) { switch (n->Opcode()) { case Op_StrComp: + case Op_StrEquals: + case Op_StrIndexOf: case Op_AryEq: case Op_MemBarVolatile: case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type? @@ -897,7 +899,7 @@ Node *Matcher::xform( Node *n, int max_stack ) { #ifdef ASSERT _new2old_map.map(m->_idx, n); #endif - mstack.push(m, Post_Visit, n, i); // Don't neet to visit + mstack.push(m, Post_Visit, n, i); // Don't need to visit mstack.push(m->in(0), Visit, m, 0); } else { mstack.push(m, Visit, n, i); @@ -1267,7 +1269,7 @@ static bool match_into_reg( const Node *n, Node *m, Node *control, int i, bool s } } - // Not forceably cloning. If shared, put it into a register. + // Not forceable cloning. If shared, put it into a register. return shared; } @@ -1481,8 +1483,13 @@ MachNode *Matcher::ReduceInst( State *s, int rule, Node *&mem ) { const Type* mach_at = mach->adr_type(); // DecodeN node consumed by an address may have different type // then its input. Don't compare types for such case. - if (m->adr_type() != mach_at && m->in(MemNode::Address)->is_AddP() && - m->in(MemNode::Address)->in(AddPNode::Address)->is_DecodeN()) { + if (m->adr_type() != mach_at && + (m->in(MemNode::Address)->is_DecodeN() || + m->in(MemNode::Address)->is_AddP() && + m->in(MemNode::Address)->in(AddPNode::Address)->is_DecodeN() || + m->in(MemNode::Address)->is_AddP() && + m->in(MemNode::Address)->in(AddPNode::Address)->is_AddP() && + m->in(MemNode::Address)->in(AddPNode::Address)->in(AddPNode::Address)->is_DecodeN())) { mach_at = m->adr_type(); } if (m->adr_type() != mach_at) { @@ -1542,7 +1549,7 @@ void Matcher::ReduceInst_Chain_Rule( State *s, int rule, Node *&mem, MachNode *m // This is what my child will give me. int opnd_class_instance = s->_rule[op]; // Choose between operand class or not. - // This is what I will recieve. + // This is what I will receive. int catch_op = (FIRST_OPERAND_CLASS <= op && op < NUM_OPERANDS) ? opnd_class_instance : op; // New rule for child. Chase operand classes to get the actual rule. int newrule = s->_rule[catch_op]; @@ -1707,11 +1714,18 @@ OptoReg::Name Matcher::find_receiver( bool is_outgoing ) { void Matcher::find_shared( Node *n ) { // Allocate stack of size C->unique() * 2 to avoid frequent realloc MStack mstack(C->unique() * 2); + // Mark nodes as address_visited if they are inputs to an address expression + VectorSet address_visited(Thread::current()->resource_area()); mstack.push(n, Visit); // Don't need to pre-visit root node while (mstack.is_nonempty()) { n = mstack.node(); // Leave node on stack Node_State nstate = mstack.state(); + uint nop = n->Opcode(); if (nstate == Pre_Visit) { + if (address_visited.test(n->_idx)) { // Visited in address already? + // Flag as visited and shared now. + set_visited(n); + } if (is_visited(n)) { // Visited already? // Node is shared and has no reason to clone. Flag it as shared. // This causes it to match into a register for the sharing. @@ -1726,7 +1740,7 @@ void Matcher::find_shared( Node *n ) { set_visited(n); // Flag as visited now bool mem_op = false; - switch( n->Opcode() ) { // Handle some opcodes special + switch( nop ) { // Handle some opcodes special case Op_Phi: // Treat Phis as shared roots case Op_Parm: case Op_Proj: // All handled specially during matching @@ -1776,6 +1790,8 @@ void Matcher::find_shared( Node *n ) { mstack.push(n->in(0), Pre_Visit); // Visit Control input continue; // while (mstack.is_nonempty()) case Op_StrComp: + case Op_StrEquals: + case Op_StrIndexOf: case Op_AryEq: set_shared(n); // Force result into register (it will be anyways) break; @@ -1887,34 +1903,51 @@ void Matcher::find_shared( Node *n ) { // to have a single use so force sharing here. set_shared(m->in(AddPNode::Base)->in(1)); } + + // Some inputs for address expression are not put on stack + // to avoid marking them as shared and forcing them into register + // if they are used only in address expressions. + // But they should be marked as shared if there are other uses + // besides address expressions. + Node *off = m->in(AddPNode::Offset); - if( off->is_Con() ) { - set_visited(m); // Flag as visited now + if( off->is_Con() && + // When there are other uses besides address expressions + // put it on stack and mark as shared. + !is_visited(m) ) { + address_visited.test_set(m->_idx); // Flag as address_visited Node *adr = m->in(AddPNode::Address); // Intel, ARM and friends can handle 2 adds in addressing mode if( clone_shift_expressions && adr->is_AddP() && // AtomicAdd is not an addressing expression. // Cheap to find it by looking for screwy base. - !adr->in(AddPNode::Base)->is_top() ) { - set_visited(adr); // Flag as visited now + !adr->in(AddPNode::Base)->is_top() && + // Are there other uses besides address expressions? + !is_visited(adr) ) { + address_visited.set(adr->_idx); // Flag as address_visited Node *shift = adr->in(AddPNode::Offset); // Check for shift by small constant as well if( shift->Opcode() == Op_LShiftX && shift->in(2)->is_Con() && - shift->in(2)->get_int() <= 3 ) { - set_visited(shift); // Flag as visited now + shift->in(2)->get_int() <= 3 && + // Are there other uses besides address expressions? + !is_visited(shift) ) { + address_visited.set(shift->_idx); // Flag as address_visited mstack.push(shift->in(2), Visit); + Node *conv = shift->in(1); #ifdef _LP64 // Allow Matcher to match the rule which bypass // ConvI2L operation for an array index on LP64 // if the index value is positive. - if( shift->in(1)->Opcode() == Op_ConvI2L && - shift->in(1)->as_Type()->type()->is_long()->_lo >= 0 ) { - set_visited(shift->in(1)); // Flag as visited now - mstack.push(shift->in(1)->in(1), Pre_Visit); + if( conv->Opcode() == Op_ConvI2L && + conv->as_Type()->type()->is_long()->_lo >= 0 && + // Are there other uses besides address expressions? + !is_visited(conv) ) { + address_visited.set(conv->_idx); // Flag as address_visited + mstack.push(conv->in(1), Pre_Visit); } else #endif - mstack.push(shift->in(1), Pre_Visit); + mstack.push(conv, Pre_Visit); } else { mstack.push(shift, Pre_Visit); } @@ -1942,7 +1975,7 @@ void Matcher::find_shared( Node *n ) { // BoolNode::match_edge always returns a zero. // We reorder the Op_If in a pre-order manner, so we can visit without - // accidently sharing the Cmp (the Bool and the If make 2 users). + // accidentally sharing the Cmp (the Bool and the If make 2 users). n->add_req( n->in(1)->in(1) ); // Add the Cmp next to the Bool } else if (nstate == Post_Visit) { diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 9c79f2ec936..b2af60d27dc 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,12 +100,12 @@ Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr, while (prev != result) { prev = result; if (result == start_mem) - break; // hit one of our sentinals + break; // hit one of our sentinels // skip over a call which does not affect this memory slice if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) { Node *proj_in = result->in(0); if (proj_in->is_Allocate() && proj_in->_idx == instance_id) { - break; // hit one of our sentinals + break; // hit one of our sentinels } else if (proj_in->is_Call()) { CallNode *call = proj_in->as_Call(); if (!call->may_modify(t_adr, phase)) { @@ -198,7 +198,7 @@ static Node *step_through_mergemem(PhaseGVN *phase, MergeMemNode *mmem, const T // If not, we can update the input infinitely along a MergeMem cycle // Equivalent code in PhiNode::Ideal Node* m = phase->transform(mmem); - // If tranformed to a MergeMem, get the desired slice + // If transformed to a MergeMem, get the desired slice // Otherwise the returned node represents memory for every slice mem = (m->is_MergeMem())? m->as_MergeMem()->memory_at(alias_idx) : m; // Update input if it is progress over what we have now @@ -778,7 +778,7 @@ Node *LoadNode::make( PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const Type adr_type->offset() == arrayOopDesc::length_offset_in_bytes()), "use LoadRangeNode instead"); switch (bt) { - case T_BOOLEAN: + case T_BOOLEAN: return new (C, 3) LoadUBNode(ctl, mem, adr, adr_type, rt->is_int() ); case T_BYTE: return new (C, 3) LoadBNode (ctl, mem, adr, adr_type, rt->is_int() ); case T_INT: return new (C, 3) LoadINode (ctl, mem, adr, adr_type, rt->is_int() ); case T_CHAR: return new (C, 3) LoadUSNode(ctl, mem, adr, adr_type, rt->is_int() ); @@ -970,7 +970,7 @@ Node *LoadNode::Identity( PhaseTransform *phase ) { } // Search for an existing data phi which was generated before for the same - // instance's field to avoid infinite genertion of phis in a loop. + // instance's field to avoid infinite generation of phis in a loop. Node *region = mem->in(0); if (is_instance_field_load_with_local_phi(region)) { const TypePtr *addr_t = in(MemNode::Address)->bottom_type()->isa_ptr(); @@ -1066,11 +1066,11 @@ Node* LoadNode::eliminate_autobox(PhaseGVN* phase) { break; } } - LoadNode* load = NULL; - if (allocation != NULL && base->in(load_index)->is_Load()) { - load = base->in(load_index)->as_Load(); - } - if (load != NULL && in(Memory)->is_Phi() && in(Memory)->in(0) == base->in(0)) { + bool has_load = ( allocation != NULL && + (base->in(load_index)->is_Load() || + base->in(load_index)->is_DecodeN() && + base->in(load_index)->in(1)->is_Load()) ); + if (has_load && in(Memory)->is_Phi() && in(Memory)->in(0) == base->in(0)) { // Push the loads from the phi that comes from valueOf up // through it to allow elimination of the loads and the recovery // of the original value. @@ -1106,11 +1106,20 @@ Node* LoadNode::eliminate_autobox(PhaseGVN* phase) { result->set_req(load_index, in2); return result; } - } else if (base->is_Load()) { + } else if (base->is_Load() || + base->is_DecodeN() && base->in(1)->is_Load()) { + if (base->is_DecodeN()) { + // Get LoadN node which loads cached Integer object + base = base->in(1); + } // Eliminate the load of Integer.value for integers from the cache // array by deriving the value from the index into the array. // Capture the offset of the load and then reverse the computation. Node* load_base = base->in(Address)->in(AddPNode::Base); + if (load_base->is_DecodeN()) { + // Get LoadN node which loads IntegerCache.cache field + load_base = load_base->in(1); + } if (load_base != NULL) { Compile::AliasType* atp = phase->C->alias_type(load_base->adr_type()); intptr_t cache_offset; @@ -1245,7 +1254,7 @@ Node *LoadNode::split_through_phi(PhaseGVN *phase) { // (This tweaking with igvn only works because x is a new node.) igvn->set_type(x, t); // If x is a TypeNode, capture any more-precise type permanently into Node - // othewise it will be not updated during igvn->transform since + // otherwise it will be not updated during igvn->transform since // igvn->type(x) is set to x->Value() already. x->raise_bottom_type(t); Node *y = x->Identity(igvn); @@ -1607,6 +1616,22 @@ Node *LoadBNode::Ideal(PhaseGVN *phase, bool can_reshape) { return LoadNode::Ideal(phase, can_reshape); } +//--------------------------LoadUBNode::Ideal------------------------------------- +// +// If the previous store is to the same address as this load, +// and the value stored was larger than a byte, replace this load +// with the value stored truncated to a byte. If no truncation is +// needed, the replacement is done in LoadNode::Identity(). +// +Node* LoadUBNode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node* mem = in(MemNode::Memory); + Node* value = can_see_stored_value(mem, phase); + if (value && !phase->type(value)->higher_equal(_type)) + return new (phase->C, 3) AndINode(value, phase->intcon(0xFF)); + // Identity call will handle the case where truncation is not needed. + return LoadNode::Ideal(phase, can_reshape); +} + //--------------------------LoadUSNode::Ideal------------------------------------- // // If the previous store is to the same address as this load, @@ -2456,6 +2481,31 @@ Node *StrCompNode::Ideal(PhaseGVN *phase, bool can_reshape){ return remove_dead_region(phase, can_reshape) ? this : NULL; } +// Do we match on this edge? No memory edges +uint StrEqualsNode::match_edge(uint idx) const { + return idx == 5 || idx == 6; +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *StrEqualsNode::Ideal(PhaseGVN *phase, bool can_reshape){ + return remove_dead_region(phase, can_reshape) ? this : NULL; +} + +//============================================================================= +// Do we match on this edge? No memory edges +uint StrIndexOfNode::match_edge(uint idx) const { + return idx == 5 || idx == 6; +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *StrIndexOfNode::Ideal(PhaseGVN *phase, bool can_reshape){ + return remove_dead_region(phase, can_reshape) ? this : NULL; +} + //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Strip out // control copies @@ -2463,7 +2513,6 @@ Node *AryEqNode::Ideal(PhaseGVN *phase, bool can_reshape){ return remove_dead_region(phase, can_reshape) ? this : NULL; } - //============================================================================= MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent) : MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)), @@ -2582,7 +2631,7 @@ Node *MemBarNode::match( const ProjNode *proj, const Matcher *m ) { // capturing of nearby memory operations. // // During macro-expansion, all captured initializations which store -// constant values of 32 bits or smaller are coalesced (if advantagous) +// constant values of 32 bits or smaller are coalesced (if advantageous) // into larger 'tiles' 32 or 64 bits. This allows an object to be // initialized in fewer memory operations. Memory words which are // covered by neither tiles nor non-constant stores are pre-zeroed @@ -3669,7 +3718,7 @@ Node *MergeMemNode::Ideal(PhaseGVN *phase, bool can_reshape) { else if (old_mmem != NULL) { new_mem = old_mmem->memory_at(i); } - // else preceeding memory was not a MergeMem + // else preceding memory was not a MergeMem // replace equivalent phis (unfortunately, they do not GVN together) if (new_mem != NULL && new_mem != new_base && diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index 63cb0d653f7..1d4f499da13 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,6 +207,19 @@ public: virtual BasicType memory_type() const { return T_BYTE; } }; +//------------------------------LoadUBNode------------------------------------- +// Load a unsigned byte (8bits unsigned) from memory +class LoadUBNode : public LoadNode { +public: + LoadUBNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeInt* ti = TypeInt::UBYTE ) + : LoadNode(c, mem, adr, at, ti) {} + virtual int Opcode() const; + virtual uint ideal_reg() const { return Op_RegI; } + virtual Node* Ideal(PhaseGVN *phase, bool can_reshape); + virtual int store_Opcode() const { return Op_StoreB; } + virtual BasicType memory_type() const { return T_BYTE; } +}; + //------------------------------LoadUSNode------------------------------------- // Load an unsigned short/char (16bits unsigned) from memory class LoadUSNode : public LoadNode { @@ -232,6 +245,18 @@ public: virtual BasicType memory_type() const { return T_INT; } }; +//------------------------------LoadUI2LNode----------------------------------- +// Load an unsigned integer into long from memory +class LoadUI2LNode : public LoadNode { +public: + LoadUI2LNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeLong* t = TypeLong::UINT) + : LoadNode(c, mem, adr, at, t) {} + virtual int Opcode() const; + virtual uint ideal_reg() const { return Op_RegL; } + virtual int store_Opcode() const { return Op_StoreL; } + virtual BasicType memory_type() const { return T_LONG; } +}; + //------------------------------LoadRangeNode---------------------------------- // Load an array length from the array class LoadRangeNode : public LoadINode { @@ -740,6 +765,54 @@ public: virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); }; +//------------------------------StrEquals------------------------------------- +class StrEqualsNode: public Node { +public: + StrEqualsNode(Node *control, + Node* char_array_mem, + Node* value_mem, + Node* count_mem, + Node* offset_mem, + Node* s1, Node* s2): Node(control, + char_array_mem, + value_mem, + count_mem, + offset_mem, + s1, s2) {}; + virtual int Opcode() const; + virtual bool depends_only_on_test() const { return false; } + virtual const Type* bottom_type() const { return TypeInt::BOOL; } + // a StrEqualsNode (conservatively) aliases with everything: + virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } + virtual uint match_edge(uint idx) const; + virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +//------------------------------StrIndexOf------------------------------------- +class StrIndexOfNode: public Node { +public: + StrIndexOfNode(Node *control, + Node* char_array_mem, + Node* value_mem, + Node* count_mem, + Node* offset_mem, + Node* s1, Node* s2): Node(control, + char_array_mem, + value_mem, + count_mem, + offset_mem, + s1, s2) {}; + virtual int Opcode() const; + virtual bool depends_only_on_test() const { return false; } + virtual const Type* bottom_type() const { return TypeInt::INT; } + // a StrIndexOfNode (conservatively) aliases with everything: + virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } + virtual uint match_edge(uint idx) const; + virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + //------------------------------AryEq--------------------------------------- class AryEqNode: public Node { public: @@ -757,10 +830,10 @@ public: // Model. Monitor-enter and volatile-load act as Aquires: no following ref // can be moved to before them. We insert a MemBar-Acquire after a FastLock or // volatile-load. Monitor-exit and volatile-store act as Release: no -// preceeding ref can be moved to after them. We insert a MemBar-Release +// preceding ref can be moved to after them. We insert a MemBar-Release // before a FastUnlock or volatile-store. All volatiles need to be // serialized, so we follow all volatile-stores with a MemBar-Volatile to -// seperate it from any following volatile-load. +// separate it from any following volatile-load. class MemBarNode: public MultiNode { virtual uint hash() const ; // { return NO_HASH; } virtual uint cmp( const Node &n ) const ; // Always fail, except on self diff --git a/hotspot/src/share/vm/opto/mulnode.cpp b/hotspot/src/share/vm/opto/mulnode.cpp index 081dce647bb..7700272f6d9 100644 --- a/hotspot/src/share/vm/opto/mulnode.cpp +++ b/hotspot/src/share/vm/opto/mulnode.cpp @@ -486,20 +486,23 @@ Node *AndINode::Ideal(PhaseGVN *phase, bool can_reshape) { return new (phase->C, 3) AndINode(ldus, phase->intcon(mask&0xFFFF)); } - // Masking sign bits off of a Byte? Let the matcher use an unsigned load - if( lop == Op_LoadB && - (!in(0) && load->in(0)) && - (mask == 0x000000FF) ) { - // Associate this node with the LoadB, so the matcher can see them together. - // If we don't do this, it is common for the LoadB to have one control - // edge, and the store or call containing this AndI to have a different - // control edge. This will cause Label_Root to group the AndI with - // the encoding store or call, so the matcher has no chance to match - // this AndI together with the LoadB. Setting the control edge here - // prevents Label_Root from grouping the AndI with the store or call, - // if it has a control edge that is inconsistent with the LoadB. - set_req(0, load->in(0)); - return this; + // Masking sign bits off of a Byte? Do an unsigned byte load. + if (lop == Op_LoadB && mask == 0x000000FF) { + return new (phase->C, 3) LoadUBNode(load->in(MemNode::Control), + load->in(MemNode::Memory), + load->in(MemNode::Address), + load->adr_type()); + } + + // Masking sign bits off of a Byte plus additional lower bits? Do + // an unsigned byte load plus an and. + if (lop == Op_LoadB && (mask & 0xFFFFFF00) == 0) { + Node* ldub = new (phase->C, 3) LoadUBNode(load->in(MemNode::Control), + load->in(MemNode::Memory), + load->in(MemNode::Address), + load->adr_type()); + ldub = phase->transform(ldub); + return new (phase->C, 3) AndINode(ldub, phase->intcon(mask)); } // Masking off sign bits? Dont make them! @@ -599,12 +602,21 @@ Node *AndLNode::Ideal(PhaseGVN *phase, bool can_reshape) { if( !t2 || !t2->is_con() ) return MulNode::Ideal(phase, can_reshape); const jlong mask = t2->get_con(); - Node *rsh = in(1); - uint rop = rsh->Opcode(); + Node* in1 = in(1); + uint op = in1->Opcode(); + + // Masking sign bits off of an integer? Do an unsigned integer to long load. + if (op == Op_ConvI2L && in1->in(1)->Opcode() == Op_LoadI && mask == 0x00000000FFFFFFFFL) { + Node* load = in1->in(1); + return new (phase->C, 3) LoadUI2LNode(load->in(MemNode::Control), + load->in(MemNode::Memory), + load->in(MemNode::Address), + load->adr_type()); + } // Masking off sign bits? Dont make them! - if( rop == Op_RShiftL ) { - const TypeInt *t12 = phase->type(rsh->in(2))->isa_int(); + if (op == Op_RShiftL) { + const TypeInt *t12 = phase->type(in1->in(2))->isa_int(); if( t12 && t12->is_con() ) { // Shift is by a constant int shift = t12->get_con(); shift &= BitsPerJavaLong - 1; // semantics of Java shifts @@ -613,7 +625,7 @@ Node *AndLNode::Ideal(PhaseGVN *phase, bool can_reshape) { // bits survive. NO sign-extension bits survive the maskings. if( (sign_bits_mask & mask) == 0 ) { // Use zero-fill shift instead - Node *zshift = phase->transform(new (phase->C, 3) URShiftLNode(rsh->in(1),rsh->in(2))); + Node *zshift = phase->transform(new (phase->C, 3) URShiftLNode(in1->in(1), in1->in(2))); return new (phase->C, 3) AndLNode( zshift, in(2) ); } } diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index 9130403ed9d..f7d71d17234 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -968,22 +968,23 @@ const Type *Node::Value( PhaseTransform * ) const { // Example: when reshape "(X+3)+4" into "X+7" you must leave the Node for // "X+3" unchanged in case it is shared. // -// If you modify the 'this' pointer's inputs, you must use 'set_req' with -// def-use info. If you are making a new Node (either as the new root or -// some new internal piece) you must NOT use set_req with def-use info. -// You can make a new Node with either 'new' or 'clone'. In either case, -// def-use info is (correctly) not generated. +// If you modify the 'this' pointer's inputs, you should use +// 'set_req'. If you are making a new Node (either as the new root or +// some new internal piece) you may use 'init_req' to set the initial +// value. You can make a new Node with either 'new' or 'clone'. In +// either case, def-use info is correctly maintained. +// // Example: reshape "(X+3)+4" into "X+7": -// set_req(1,in(1)->in(1) /* grab X */, du /* must use DU on 'this' */); -// set_req(2,phase->intcon(7),du); +// set_req(1, in(1)->in(1)); +// set_req(2, phase->intcon(7)); // return this; -// Example: reshape "X*4" into "X<<1" -// return new (C,3) LShiftINode( in(1), phase->intcon(1) ); +// Example: reshape "X*4" into "X<<2" +// return new (C,3) LShiftINode(in(1), phase->intcon(2)); // // You must call 'phase->transform(X)' on any new Nodes X you make, except -// for the returned root node. Example: reshape "X*31" with "(X<<5)-1". +// for the returned root node. Example: reshape "X*31" with "(X<<5)-X". // Node *shift=phase->transform(new(C,3)LShiftINode(in(1),phase->intcon(5))); -// return new (C,3) AddINode(shift, phase->intcon(-1)); +// return new (C,3) AddINode(shift, in(1)); // // When making a Node for a constant use 'phase->makecon' or 'phase->intcon'. // These forms are faster than 'phase->transform(new (C,1) ConNode())' and Do @@ -1679,7 +1680,7 @@ void Node::verify_edges(Unique_Node_List &visited) { if (visited.member(this)) return; visited.push(this); - // Walk over all input edges, checking for correspondance + // Walk over all input edges, checking for correspondence for( i = 0; i < len(); i++ ) { n = in(i); if (n != NULL && !n->is_top()) { @@ -1723,7 +1724,7 @@ void Node::verify_recur(const Node *n, int verify_depth, // Contained in new_space or old_space? VectorSet *v = C->node_arena()->contains(n) ? &new_space : &old_space; // Check for visited in the proper space. Numberings are not unique - // across spaces so we need a seperate VectorSet for each space. + // across spaces so we need a separate VectorSet for each space. if( v->test_set(n->_idx) ) return; if (n->is_Con() && n->bottom_type() == Type::TOP) { diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index f55a403099a..bad1607058e 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -257,7 +257,7 @@ protected: Node **_in; // Array of use-def references to Nodes Node **_out; // Array of def-use references to Nodes - // Input edges are split into two catagories. Required edges are required + // Input edges are split into two categories. Required edges are required // for semantic correctness; order is important and NULLs are allowed. // Precedence edges are used to help determine execution order and are // added, e.g., for scheduling purposes. They are unordered and not @@ -854,7 +854,7 @@ public: // If the hash function returns the special sentinel value NO_HASH, // the node is guaranteed never to compare equal to any other node. - // If we accidently generate a hash with value NO_HASH the node + // If we accidentally generate a hash with value NO_HASH the node // won't go into the table and we'll lose a little optimization. enum { NO_HASH = 0 }; virtual uint hash() const; diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 7d6482ccd3c..c29274174e0 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -1171,7 +1171,7 @@ void Compile::Fill_buffer() { cb->flush_bundle(false); // The following logic is duplicated in the code ifdeffed for - // ENABLE_ZAP_DEAD_LOCALS which apppears above in this file. It + // ENABLE_ZAP_DEAD_LOCALS which appears above in this file. It // should be factored out. Or maybe dispersed to the nodes? // Special handling for SafePoint/Call Nodes @@ -1275,7 +1275,7 @@ void Compile::Fill_buffer() { } #ifdef ASSERT - // Check that oop-store preceeds the card-mark + // Check that oop-store precedes the card-mark else if( mach->ideal_Opcode() == Op_StoreCM ) { uint storeCM_idx = j; Node *oop_store = mach->in(mach->_cnt); // First precedence edge @@ -1291,7 +1291,7 @@ void Compile::Fill_buffer() { #endif else if( !n->is_Proj() ) { - // Remember the begining of the previous instruction, in case + // Remember the beginning of the previous instruction, in case // it's followed by a flag-kill and a null-check. Happens on // Intel all the time, with add-to-memory kind of opcodes. previous_offset = current_offset; @@ -1567,7 +1567,7 @@ Scheduling::Scheduling(Arena *arena, Compile &compile) compile.set_node_bundling_limit(_node_bundling_limit); - // This one is persistant within the Compile class + // This one is persistent within the Compile class _node_bundling_base = NEW_ARENA_ARRAY(compile.comp_arena(), Bundle, node_max); // Allocate space for fixed-size arrays @@ -1666,7 +1666,7 @@ void Compile::ScheduleAndBundle() { // Compute the latency of all the instructions. This is fairly simple, // because we already have a legal ordering. Walk over the instructions // from first to last, and compute the latency of the instruction based -// on the latency of the preceeding instruction(s). +// on the latency of the preceding instruction(s). void Scheduling::ComputeLocalLatenciesForward(const Block *bb) { #ifndef PRODUCT if (_cfg->C->trace_opto_output()) @@ -1931,7 +1931,7 @@ void Scheduling::AddNodeToBundle(Node *n, const Block *bb) { uint siz = _available.size(); // Conditional branches can support an instruction that - // is unconditionally executed and not dependant by the + // is unconditionally executed and not dependent by the // branch, OR a conditionally executed instruction if // the branch is taken. In practice, this means that // the first instruction at the branch target is @@ -1947,7 +1947,7 @@ void Scheduling::AddNodeToBundle(Node *n, const Block *bb) { #endif // At least 1 instruction is on the available list - // that is not dependant on the branch + // that is not dependent on the branch for (uint i = 0; i < siz; i++) { Node *d = _available[i]; const Pipeline *avail_pipeline = d->pipeline(); diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index d33acba3e7a..e00dfca6a7a 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -78,7 +78,7 @@ public: }; // See if it is OK to inline. - // The reciever is the inline tree for the caller. + // The receiver is the inline tree for the caller. // // The result is a temperature indication. If it is hot or cold, // inlining is immediate or undesirable. Otherwise, the info block diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index b896faca492..da9537eb3c4 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -95,7 +95,7 @@ Node *Parse::fetch_interpreter_state(int index, switch( bt ) { // Signature is flattened case T_INT: l = new (C, 3) LoadINode( 0, mem, adr, TypeRawPtr::BOTTOM ); break; case T_FLOAT: l = new (C, 3) LoadFNode( 0, mem, adr, TypeRawPtr::BOTTOM ); break; - case T_ADDRESS: + case T_ADDRESS: l = new (C, 3) LoadPNode( 0, mem, adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM ); break; case T_OBJECT: l = new (C, 3) LoadPNode( 0, mem, adr, TypeRawPtr::BOTTOM, TypeInstPtr::BOTTOM ); break; case T_LONG: case T_DOUBLE: { @@ -607,7 +607,7 @@ void Parse::do_all_blocks() { if (control()->is_Region() && !block->is_loop_head() && !has_irreducible && !block->is_handler()) { // In the absence of irreducible loops, the Region and Phis // associated with a merge that doesn't involve a backedge can - // be simplfied now since the RPO parsing order guarantees + // be simplified now since the RPO parsing order guarantees // that any path which was supposed to reach here has already // been parsed or must be dead. Node* c = control(); diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index 0f40fdd962e..201ffad99c0 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -32,7 +32,7 @@ extern int explicit_null_checks_inserted, void Parse::array_load(BasicType elem_type) { const Type* elem = Type::TOP; Node* adr = array_addressing(elem_type, 0, &elem); - if (stopped()) return; // guarenteed null or range check + if (stopped()) return; // guaranteed null or range check _sp -= 2; // Pop array and index const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(elem_type); Node* ld = make_load(control(), adr, elem, elem_type, adr_type); @@ -43,7 +43,7 @@ void Parse::array_load(BasicType elem_type) { //--------------------------------array_store---------------------------------- void Parse::array_store(BasicType elem_type) { Node* adr = array_addressing(elem_type, 1); - if (stopped()) return; // guarenteed null or range check + if (stopped()) return; // guaranteed null or range check Node* val = pop(); _sp -= 2; // Pop array and index const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(elem_type); @@ -1541,14 +1541,14 @@ void Parse::do_one_bytecode() { case Bytecodes::_aaload: array_load(T_OBJECT); break; case Bytecodes::_laload: { a = array_addressing(T_LONG, 0); - if (stopped()) return; // guarenteed null or range check + if (stopped()) return; // guaranteed null or range check _sp -= 2; // Pop array and index push_pair( make_load(control(), a, TypeLong::LONG, T_LONG, TypeAryPtr::LONGS)); break; } case Bytecodes::_daload: { a = array_addressing(T_DOUBLE, 0); - if (stopped()) return; // guarenteed null or range check + if (stopped()) return; // guaranteed null or range check _sp -= 2; // Pop array and index push_pair( make_load(control(), a, Type::DOUBLE, T_DOUBLE, TypeAryPtr::DOUBLES)); break; @@ -1560,7 +1560,7 @@ void Parse::do_one_bytecode() { case Bytecodes::_fastore: array_store(T_FLOAT); break; case Bytecodes::_aastore: { d = array_addressing(T_OBJECT, 1); - if (stopped()) return; // guarenteed null or range check + if (stopped()) return; // guaranteed null or range check array_store_check(); c = pop(); // Oop to store b = pop(); // index (already used) @@ -1572,7 +1572,7 @@ void Parse::do_one_bytecode() { } case Bytecodes::_lastore: { a = array_addressing(T_LONG, 2); - if (stopped()) return; // guarenteed null or range check + if (stopped()) return; // guaranteed null or range check c = pop_pair(); _sp -= 2; // Pop array and index store_to_memory(control(), a, c, T_LONG, TypeAryPtr::LONGS); @@ -1580,7 +1580,7 @@ void Parse::do_one_bytecode() { } case Bytecodes::_dastore: { a = array_addressing(T_DOUBLE, 2); - if (stopped()) return; // guarenteed null or range check + if (stopped()) return; // guaranteed null or range check c = pop_pair(); _sp -= 2; // Pop array and index c = dstore_rounding(c); diff --git a/hotspot/src/share/vm/opto/phase.cpp b/hotspot/src/share/vm/opto/phase.cpp index 904214a330f..b0ea80a8242 100644 --- a/hotspot/src/share/vm/opto/phase.cpp +++ b/hotspot/src/share/vm/opto/phase.cpp @@ -73,7 +73,7 @@ elapsedTimer Phase::_t_buildOopMaps; //------------------------------Phase------------------------------------------ Phase::Phase( PhaseNumber pnum ) : _pnum(pnum), C( pnum == Compiler ? NULL : Compile::current()) { - // Poll for requests from shutdown mechanism to quiesce comiler (4448539, 4448544). + // Poll for requests from shutdown mechanism to quiesce compiler (4448539, 4448544). // This is an effective place to poll, since the compiler is full of phases. // In particular, every inlining site uses a recursively created Parse phase. CompileBroker::maybe_block(); diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index 484629a90ce..78c48452244 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -196,7 +196,7 @@ void NodeHash::hash_insert( Node *n ) { } //------------------------------hash_delete------------------------------------ -// Replace in hash table with sentinal +// Replace in hash table with sentinel bool NodeHash::hash_delete( const Node *n ) { Node *k; uint hash = n->hash(); @@ -207,7 +207,7 @@ bool NodeHash::hash_delete( const Node *n ) { uint key = hash & (_max-1); uint stride = key | 0x01; debug_only( uint counter = 0; ); - for( ; /* (k != NULL) && (k != _sentinal) */; ) { + for( ; /* (k != NULL) && (k != _sentinel) */; ) { debug_only( counter++ ); debug_only( _delete_probes++ ); k = _table[key]; // Get hashed value @@ -715,7 +715,7 @@ Node *PhaseGVN::transform_no_reclaim( Node *n ) { #ifdef ASSERT //------------------------------dead_loop_check-------------------------------- -// Check for a simple dead loop when a data node references itself direcly +// Check for a simple dead loop when a data node references itself directly // or through an other data node excluding cons and phis. void PhaseGVN::dead_loop_check( Node *n ) { // Phi may reference itself in a loop @@ -1359,7 +1359,7 @@ void PhaseCCP::analyze() { worklist.push(p); // Propagate change to user } } - // If we changed the reciever type to a call, we need to revisit + // If we changed the receiver type to a call, we need to revisit // the Catch following the call. It's looking for a non-NULL // receiver to know when to enable the regular fall-through path // in addition to the NullPtrException path diff --git a/hotspot/src/share/vm/opto/postaloc.cpp b/hotspot/src/share/vm/opto/postaloc.cpp index cd881065f32..fa28c6aa1cc 100644 --- a/hotspot/src/share/vm/opto/postaloc.cpp +++ b/hotspot/src/share/vm/opto/postaloc.cpp @@ -46,7 +46,7 @@ bool PhaseChaitin::may_be_copy_of_callee( Node *def ) const { // be splitting live ranges for callee save registers to such // an extent that in large methods the chains can be very long // (50+). The conservative answer is to return true if we don't - // know as this prevents optimizations from occuring. + // know as this prevents optimizations from occurring. const int limit = 60; int i; @@ -286,7 +286,7 @@ bool PhaseChaitin::eliminate_copy_of_constant(Node* val, Node* n, // // n will be replaced with the old value but n might have // kills projections associated with it so remove them now so that - // yank_if_dead will be able to elminate the copy once the uses + // yank_if_dead will be able to eliminate the copy once the uses // have been transferred to the old[value]. for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* use = n->fast_out(i); diff --git a/hotspot/src/share/vm/opto/reg_split.cpp b/hotspot/src/share/vm/opto/reg_split.cpp index 003df4c48b7..62636023f70 100644 --- a/hotspot/src/share/vm/opto/reg_split.cpp +++ b/hotspot/src/share/vm/opto/reg_split.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,8 @@ #include "incls/_reg_split.cpp.incl" //------------------------------Split-------------------------------------- -// Walk the graph in RPO and for each lrg which spills, propogate reaching -// definitions. During propogation, split the live range around regions of +// Walk the graph in RPO and for each lrg which spills, propagate reaching +// definitions. During propagation, split the live range around regions of // High Register Pressure (HRP). If a Def is in a region of Low Register // Pressure (LRP), it will not get spilled until we encounter a region of // HRP between it and one of its uses. We will spill at the transition @@ -88,7 +88,7 @@ Node *PhaseChaitin::get_spillcopy_wide( Node *def, Node *use, uint uidx ) { } //------------------------------insert_proj------------------------------------ -// Insert the spill at chosen location. Skip over any interveneing Proj's or +// Insert the spill at chosen location. Skip over any intervening Proj's or // Phis. Skip over a CatchNode and projs, inserting in the fall-through block // instead. Update high-pressure indices. Create a new live range. void PhaseChaitin::insert_proj( Block *b, uint i, Node *spill, uint maxlrg ) { @@ -125,7 +125,7 @@ void PhaseChaitin::insert_proj( Block *b, uint i, Node *spill, uint maxlrg ) { } //------------------------------split_DEF-------------------------------------- -// There are four catagories of Split; UP/DOWN x DEF/USE +// There are four categories of Split; UP/DOWN x DEF/USE // Only three of these really occur as DOWN/USE will always color // Any Split with a DEF cannot CISC-Spill now. Thus we need // two helper routines, one for Split DEFS (insert after instruction), @@ -726,7 +726,7 @@ uint PhaseChaitin::Split( uint maxlrg ) { // ********** Handle Crossing HRP Boundry ********** if( (insidx == b->_ihrp_index) || (insidx == b->_fhrp_index) ) { for( slidx = 0; slidx < spill_cnt; slidx++ ) { - // Check for need to split at HRP boundry - split if UP + // Check for need to split at HRP boundary - split if UP n1 = Reachblock[slidx]; // bail out if no reaching DEF if( n1 == NULL ) continue; diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 7b5effc8182..cbbbfacfcb5 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -1196,7 +1196,7 @@ JRT_END // The following does not work because for one thing, the // thread state is wrong; it expects java, but it is native. -// Also, the invarients in a native stub are different and +// Also, the invariants in a native stub are different and // I'm not sure it is safe to have a MachCalRuntimeDirectNode // in there. // So for now, we do not zap in native stubs. diff --git a/hotspot/src/share/vm/opto/split_if.cpp b/hotspot/src/share/vm/opto/split_if.cpp index 130b2667513..a7a6baaa925 100644 --- a/hotspot/src/share/vm/opto/split_if.cpp +++ b/hotspot/src/share/vm/opto/split_if.cpp @@ -318,7 +318,7 @@ Node *PhaseIdealLoop::find_use_block( Node *use, Node *def, Node *old_false, Nod if( use->is_Phi() ) { // Phi uses in prior block // Grab the first Phi use; there may be many. - // Each will be handled as a seperate iteration of + // Each will be handled as a separate iteration of // the "while( phi->outcnt() )" loop. uint j; for( j = 1; j < use->req(); j++ ) diff --git a/hotspot/src/share/vm/opto/subnode.cpp b/hotspot/src/share/vm/opto/subnode.cpp index 260b5dc8af8..d7c3cc87e2a 100644 --- a/hotspot/src/share/vm/opto/subnode.cpp +++ b/hotspot/src/share/vm/opto/subnode.cpp @@ -639,8 +639,8 @@ const Type *CmpPNode::sub( const Type *t1, const Type *t2 ) const { int kps = (p0->isa_klassptr()?1:0) + (p1->isa_klassptr()?1:0); if (klass0 && klass1 && kps != 1 && // both or neither are klass pointers - !klass0->is_interface() && // do not trust interfaces - !klass1->is_interface()) { + klass0->is_loaded() && !klass0->is_interface() && // do not trust interfaces + klass1->is_loaded() && !klass1->is_interface()) { bool unrelated_classes = false; // See if neither subclasses the other, or if the class on top // is precise. In either of these cases, the compare is known diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 4551162bff3..c8198392c33 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -454,9 +454,13 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray &p // or need to run igvn.optimize() again before SLP } else if (out->is_Phi() && out->bottom_type() == Type::MEMORY && !in_bb(out)) { // Ditto. Not sure what else to check further. - } else if (out->Opcode() == Op_StoreCM && out->in(4) == n) { + } else if (out->Opcode() == Op_StoreCM && out->in(MemNode::OopStore) == n) { // StoreCM has an input edge used as a precedence edge. // Maybe an issue when oop stores are vectorized. + } else if( out->is_MergeMem() && prev && + prev->Opcode() == Op_StoreCM && out == prev->in(MemNode::OopStore)) { + // Oop store is a MergeMem! This should not happen. Temporarily remove the assertion + // for this case because it could not be superwordized anyway. } else { assert(out == prev || prev == NULL, "no branches off of store slice"); } @@ -470,7 +474,7 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray &p } //------------------------------stmts_can_pack--------------------------- -// Can s1 and s2 be in a pack with s1 immediately preceeding s2 and +// Can s1 and s2 be in a pack with s1 immediately preceding s2 and // s1 aligned at "align" bool SuperWord::stmts_can_pack(Node* s1, Node* s2, int align) { if (isomorphic(s1, s2)) { @@ -869,7 +873,7 @@ bool SuperWord::profitable(Node_List* p) { for (uint i = start; i < end; i++) { if (!is_vector_use(p0, i)) { // For now, return false if not scalar promotion case (inputs are the same.) - // Later, implement PackNode and allow differring, non-vector inputs + // Later, implement PackNode and allow differing, non-vector inputs // (maybe just the ones from outside the block.) Node* p0_def = p0->in(i); for (uint j = 1; j < p->size(); j++) { @@ -912,54 +916,175 @@ void SuperWord::schedule() { } } -//------------------------------co_locate_pack--------------------------- -// Within a pack, move stores down to the last executed store, -// and move loads up to the first executed load. +//-------------------------------remove_and_insert------------------- +//remove "current" from its current position in the memory graph and insert +//it after the appropriate insertion point (lip or uip) +void SuperWord::remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip, + Node *uip, Unique_Node_List &sched_before) { + Node* my_mem = current->in(MemNode::Memory); + _igvn.hash_delete(current); + _igvn.hash_delete(my_mem); + + //remove current_store from its current position in the memmory graph + for (DUIterator i = current->outs(); current->has_out(i); i++) { + Node* use = current->out(i); + if (use->is_Mem()) { + assert(use->in(MemNode::Memory) == current, "must be"); + _igvn.hash_delete(use); + if (use == prev) { // connect prev to my_mem + use->set_req(MemNode::Memory, my_mem); + } else if (sched_before.member(use)) { + _igvn.hash_delete(uip); + use->set_req(MemNode::Memory, uip); + } else { + _igvn.hash_delete(lip); + use->set_req(MemNode::Memory, lip); + } + _igvn._worklist.push(use); + --i; //deleted this edge; rescan position + } + } + + bool sched_up = sched_before.member(current); + Node *insert_pt = sched_up ? uip : lip; + _igvn.hash_delete(insert_pt); + + // all uses of insert_pt's memory state should use current's instead + for (DUIterator i = insert_pt->outs(); insert_pt->has_out(i); i++) { + Node* use = insert_pt->out(i); + if (use->is_Mem()) { + assert(use->in(MemNode::Memory) == insert_pt, "must be"); + _igvn.hash_delete(use); + use->set_req(MemNode::Memory, current); + _igvn._worklist.push(use); + --i; //deleted this edge; rescan position + } else if (!sched_up && use->is_Phi() && use->bottom_type() == Type::MEMORY) { + uint pos; //lip (lower insert point) must be the last one in the memory slice + _igvn.hash_delete(use); + for (pos=1; pos < use->req(); pos++) { + if (use->in(pos) == insert_pt) break; + } + use->set_req(pos, current); + _igvn._worklist.push(use); + --i; + } + } + + //connect current to insert_pt + current->set_req(MemNode::Memory, insert_pt); + _igvn._worklist.push(current); +} + +//------------------------------co_locate_pack---------------------------------- +// To schedule a store pack, we need to move any sandwiched memory ops either before +// or after the pack, based upon dependence information: +// (1) If any store in the pack depends on the sandwiched memory op, the +// sandwiched memory op must be scheduled BEFORE the pack; +// (2) If a sandwiched memory op depends on any store in the pack, the +// sandwiched memory op must be scheduled AFTER the pack; +// (3) If a sandwiched memory op (say, memA) depends on another sandwiched +// memory op (say memB), memB must be scheduled before memA. So, if memA is +// scheduled before the pack, memB must also be scheduled before the pack; +// (4) If there is no dependence restriction for a sandwiched memory op, we simply +// schedule this store AFTER the pack +// (5) We know there is no dependence cycle, so there in no other case; +// (6) Finally, all memory ops in another single pack should be moved in the same direction. +// +// To schedule a load pack: the memory edge of every loads in the pack must be +// the same as the memory edge of the last executed load in the pack void SuperWord::co_locate_pack(Node_List* pk) { if (pk->at(0)->is_Store()) { - // Push Stores down towards last executed pack member MemNode* first = executed_first(pk)->as_Mem(); MemNode* last = executed_last(pk)->as_Mem(); - MemNode* insert_pt = last; + Unique_Node_List schedule_before_pack; + Unique_Node_List memops; + MemNode* current = last->in(MemNode::Memory)->as_Mem(); + MemNode* previous = last; while (true) { assert(in_bb(current), "stay in block"); + memops.push(previous); + for (DUIterator i = current->outs(); current->has_out(i); i++) { + Node* use = current->out(i); + if (use->is_Mem() && use != previous) + memops.push(use); + } + if(current == first) break; + previous = current; + current = current->in(MemNode::Memory)->as_Mem(); + } + + // determine which memory operations should be scheduled before the pack + for (uint i = 1; i < memops.size(); i++) { + Node *s1 = memops.at(i); + if (!in_pack(s1, pk) && !schedule_before_pack.member(s1)) { + for (uint j = 0; j< i; j++) { + Node *s2 = memops.at(j); + if (!independent(s1, s2)) { + if (in_pack(s2, pk) || schedule_before_pack.member(s2)) { + schedule_before_pack.push(s1); //s1 must be scheduled before + Node_List* mem_pk = my_pack(s1); + if (mem_pk != NULL) { + for (uint ii = 0; ii < mem_pk->size(); ii++) { + Node* s = mem_pk->at(ii); // follow partner + if (memops.member(s) && !schedule_before_pack.member(s)) + schedule_before_pack.push(s); + } + } + } + } + } + } + } + + MemNode* lower_insert_pt = last; + Node* upper_insert_pt = first->in(MemNode::Memory); + previous = last; //previous store in pk + current = last->in(MemNode::Memory)->as_Mem(); + + //start scheduling from "last" to "first" + while (true) { + assert(in_bb(current), "stay in block"); + assert(in_pack(previous, pk), "previous stays in pack"); Node* my_mem = current->in(MemNode::Memory); + if (in_pack(current, pk)) { - // Forward users of my memory state to my input memory state + // Forward users of my memory state (except "previous) to my input memory state _igvn.hash_delete(current); - _igvn.hash_delete(my_mem); for (DUIterator i = current->outs(); current->has_out(i); i++) { Node* use = current->out(i); - if (use->is_Mem()) { + if (use->is_Mem() && use != previous) { assert(use->in(MemNode::Memory) == current, "must be"); _igvn.hash_delete(use); - use->set_req(MemNode::Memory, my_mem); + if (schedule_before_pack.member(use)) { + _igvn.hash_delete(upper_insert_pt); + use->set_req(MemNode::Memory, upper_insert_pt); + } else { + _igvn.hash_delete(lower_insert_pt); + use->set_req(MemNode::Memory, lower_insert_pt); + } _igvn._worklist.push(use); --i; // deleted this edge; rescan position } } - // put current immediately before insert_pt - current->set_req(MemNode::Memory, insert_pt->in(MemNode::Memory)); - _igvn.hash_delete(insert_pt); - insert_pt->set_req(MemNode::Memory, current); - _igvn._worklist.push(insert_pt); - _igvn._worklist.push(current); - insert_pt = current; + previous = current; + } else { // !in_pack(current, pk) ==> a sandwiched store + remove_and_insert(current, previous, lower_insert_pt, upper_insert_pt, schedule_before_pack); } + if (current == first) break; current = my_mem->as_Mem(); - } - } else if (pk->at(0)->is_Load()) { - // Pull Loads up towards first executed pack member - LoadNode* first = executed_first(pk)->as_Load(); - Node* first_mem = first->in(MemNode::Memory); - _igvn.hash_delete(first_mem); - // Give each load same memory state as first + } // end while + } else if (pk->at(0)->is_Load()) { //load + // all use the memory state that the last executed load uses + LoadNode* last_load = executed_last(pk)->as_Load(); + Node* last_mem = last_load->in(MemNode::Memory); + _igvn.hash_delete(last_mem); + // Give each load same memory state as last for (uint i = 0; i < pk->size(); i++) { LoadNode* ld = pk->at(i)->as_Load(); _igvn.hash_delete(ld); - ld->set_req(MemNode::Memory, first_mem); + ld->set_req(MemNode::Memory, last_mem); _igvn._worklist.push(ld); } } diff --git a/hotspot/src/share/vm/opto/superword.hpp b/hotspot/src/share/vm/opto/superword.hpp index b60cc83c1f0..4c11ff639b8 100644 --- a/hotspot/src/share/vm/opto/superword.hpp +++ b/hotspot/src/share/vm/opto/superword.hpp @@ -308,7 +308,7 @@ class SuperWord : public ResourceObj { void dependence_graph(); // Return a memory slice (node list) in predecessor order starting at "start" void mem_slice_preds(Node* start, Node* stop, GrowableArray &preds); - // Can s1 and s2 be in a pack with s1 immediately preceeding s2 and s1 aligned at "align" + // Can s1 and s2 be in a pack with s1 immediately preceding s2 and s1 aligned at "align" bool stmts_can_pack(Node* s1, Node* s2, int align); // Does s exist in a pack at position pos? bool exists_at(Node* s, uint pos); @@ -341,8 +341,11 @@ class SuperWord : public ResourceObj { void filter_packs(); // Adjust the memory graph for the packed operations void schedule(); - // Within a pack, move stores down to the last executed store, - // and move loads up to the first executed load. + // Remove "current" from its current position in the memory graph and insert + // it after the appropriate insert points (lip or uip); + void remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip, Node *uip, Unique_Node_List &schd_before); + // Within a store pack, schedule stores together by moving out the sandwiched memory ops according + // to dependence info; and within a load pack, move loads down to the last executed load. void co_locate_pack(Node_List* p); // Convert packs into vector node operations void output(); diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index 6830277ea3f..e831a2ad6f7 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -226,6 +226,7 @@ void Type::Initialize_shared(Compile* current) { TypeInt::CC_LE = TypeInt::make(-1, 0, WidenMin); TypeInt::CC_GE = TypeInt::make( 0, 1, WidenMin); // == TypeInt::BOOL TypeInt::BYTE = TypeInt::make(-128,127, WidenMin); // Bytes + TypeInt::UBYTE = TypeInt::make(0, 255, WidenMin); // Unsigned Bytes TypeInt::CHAR = TypeInt::make(0,65535, WidenMin); // Java chars TypeInt::SHORT = TypeInt::make(-32768,32767, WidenMin); // Java shorts TypeInt::POS = TypeInt::make(0,max_jint, WidenMin); // Non-neg values @@ -1022,6 +1023,7 @@ const TypeInt *TypeInt::CC_EQ; // [0] == ZERO const TypeInt *TypeInt::CC_LE; // [-1,0] const TypeInt *TypeInt::CC_GE; // [0,1] == BOOL (!) const TypeInt *TypeInt::BYTE; // Bytes, -128 to 127 +const TypeInt *TypeInt::UBYTE; // Unsigned Bytes, 0 to 255 const TypeInt *TypeInt::CHAR; // Java chars, 0-65535 const TypeInt *TypeInt::SHORT; // Java shorts, -32768-32767 const TypeInt *TypeInt::POS; // Positive 32-bit integers or zero @@ -2455,7 +2457,7 @@ intptr_t TypeOopPtr::get_con() const { // code and dereferenced at the time the nmethod is made. Until that time, // it is not reasonable to do arithmetic with the addresses of oops (we don't // have access to the addresses!). This does not seem to currently happen, - // but this assertion here is to help prevent its occurrance. + // but this assertion here is to help prevent its occurence. tty->print_cr("Found oop constant with non-zero offset"); ShouldNotReachHere(); } @@ -2761,7 +2763,7 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const { // LCA is object_klass, but if we subclass from the top we can do better if( above_centerline(_ptr) ) { // if( _ptr == TopPTR || _ptr == AnyNull ) // If 'this' (InstPtr) is above the centerline and it is Object class - // then we can subclass in the Java class heirarchy. + // then we can subclass in the Java class hierarchy. if (klass()->equals(ciEnv::current()->Object_klass())) { // that is, tp's array type is a subtype of my klass return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id); @@ -3022,7 +3024,7 @@ ciType* TypeInstPtr::java_mirror_type() const { //------------------------------xdual------------------------------------------ // Dual: do NOT dual on klasses. This means I do NOT understand the Java -// inheritence mechanism. +// inheritance mechanism. const Type *TypeInstPtr::xdual() const { return new TypeInstPtr( dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id() ); } @@ -3176,7 +3178,7 @@ const TypeInt* TypeAryPtr::narrow_size_type(const TypeInt* size) const { bool chg = false; if (lo < min_lo) { lo = min_lo; chg = true; } if (hi > max_hi) { hi = max_hi; chg = true; } - // Negative length arrays will produce weird intermediate dead fath-path code + // Negative length arrays will produce weird intermediate dead fast-path code if (lo > hi) return TypeInt::ZERO; if (!chg) @@ -3358,7 +3360,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const { // LCA is object_klass, but if we subclass from the top we can do better if (above_centerline(tp->ptr())) { // If 'tp' is above the centerline and it is Object class - // then we can subclass in the Java class heirarchy. + // then we can subclass in the Java class hierarchy. if( tp->klass()->equals(ciEnv::current()->Object_klass()) ) { // that is, my array type is a subtype of 'tp' klass return make( ptr, _ary, _klass, _klass_is_exact, offset, instance_id ); diff --git a/hotspot/src/share/vm/opto/type.hpp b/hotspot/src/share/vm/opto/type.hpp index 493b622a28e..917c271cce0 100644 --- a/hotspot/src/share/vm/opto/type.hpp +++ b/hotspot/src/share/vm/opto/type.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -415,6 +415,7 @@ public: static const TypeInt *CC_LE; // [-1,0] static const TypeInt *CC_GE; // [0,1] == BOOL (!) static const TypeInt *BYTE; + static const TypeInt *UBYTE; static const TypeInt *CHAR; static const TypeInt *SHORT; static const TypeInt *POS; diff --git a/hotspot/src/share/vm/opto/vectornode.cpp b/hotspot/src/share/vm/opto/vectornode.cpp index 7b6fef64bdf..cd1fcdf42cf 100644 --- a/hotspot/src/share/vm/opto/vectornode.cpp +++ b/hotspot/src/share/vm/opto/vectornode.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index e3f715dd23e..bde5dba7771 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -301,6 +301,10 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR klassOop k = SystemDictionary::resolve_from_stream(class_name, class_loader, Handle(), &st, CHECK_NULL); + if (TraceClassResolution && k != NULL) { + trace_class_resolution(k); + } + cls = (jclass)JNIHandles::make_local( env, Klass::cast(k)->java_mirror()); return cls; @@ -365,6 +369,10 @@ JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name)) result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, thread); + if (TraceClassResolution && result != NULL) { + trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result))); + } + // If we were the first invocation of jni_FindClass, we enable compilation again // rather than just allowing invocation counter to overflow and decay. // Controlled by flag DelayCompilationDuringStartup. @@ -2646,7 +2654,12 @@ static jclass lookupOne(JNIEnv* env, const char* name, TRAPS) { Handle protection_domain; // null protection domain symbolHandle sym = oopFactory::new_symbol_handle(name, CHECK_NULL); - return find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL); + jclass result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL); + + if (TraceClassResolution && result != NULL) { + trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result))); + } + return result; } // These lookups are done with the NULL (bootstrap) ClassLoader to diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 1835594ba0b..8180a850d74 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,7 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) { ResourceMark rm; int line_number = -1; const char * source_file = NULL; + const char * trace = "explicit"; klassOop caller = NULL; JavaThread* jthread = JavaThread::current(); if (jthread->has_last_Java_frame()) { @@ -107,12 +108,21 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) { (last_caller->name() == vmSymbols::loadClassInternal_name() || last_caller->name() == vmSymbols::loadClass_name())) { found_it = true; + } else if (!vfst.at_end()) { + if (vfst.method()->is_native()) { + // JNI call + found_it = true; + } } if (found_it && !vfst.at_end()) { // found the caller caller = vfst.method()->method_holder(); line_number = vfst.method()->line_number_from_bci(vfst.bci()); - symbolOop s = instanceKlass::cast(vfst.method()->method_holder())->source_file_name(); + if (line_number == -1) { + // show method name if it's a native method + trace = vfst.method()->name_and_sig_as_C_string(); + } + symbolOop s = instanceKlass::cast(caller)->source_file_name(); if (s != NULL) { source_file = s->as_C_string(); } @@ -124,15 +134,15 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) { const char * to = Klass::cast(to_class)->external_name(); // print in a single call to reduce interleaving between threads if (source_file != NULL) { - tty->print("RESOLVE %s %s %s:%d (explicit)\n", from, to, source_file, line_number); + tty->print("RESOLVE %s %s %s:%d (%s)\n", from, to, source_file, line_number, trace); } else { - tty->print("RESOLVE %s %s (explicit)\n", from, to); + tty->print("RESOLVE %s %s (%s)\n", from, to, trace); } } } } -static void trace_class_resolution(klassOop to_class) { +void trace_class_resolution(klassOop to_class) { EXCEPTION_MARK; trace_class_resolution_impl(to_class, THREAD); if (HAS_PENDING_EXCEPTION) { @@ -1242,7 +1252,7 @@ JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass)) // Throws an exception if outer klass has not declared k as // an inner klass - Reflection::check_for_inner_class(k, inner_klass, CHECK_NULL); + Reflection::check_for_inner_class(k, inner_klass, true, CHECK_NULL); result->obj_at_put(members, inner_klass->java_mirror()); members++; @@ -1265,16 +1275,29 @@ JVM_END JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass)) - const int inner_class_info_index = 0; - const int outer_class_info_index = 1; - +{ // ofClass is a reference to a java_lang_Class object. if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) || ! Klass::cast(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass)))->oop_is_instance()) { return NULL; } - instanceKlassHandle k(thread, java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass))); + symbolOop simple_name = NULL; + klassOop outer_klass + = instanceKlass::cast(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass)) + )->compute_enclosing_class(simple_name, CHECK_NULL); + if (outer_klass == NULL) return NULL; // already a top-level class + if (simple_name == NULL) return NULL; // an anonymous class (inside a method) + return (jclass) JNIHandles::make_local(env, Klass::cast(outer_klass)->java_mirror()); +} +JVM_END + +// should be in instanceKlass.cpp, but is here for historical reasons +klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, + symbolOop& simple_name_result, TRAPS) { + Thread* thread = THREAD; + const int inner_class_info_index = inner_class_inner_class_info_offset; + const int outer_class_info_index = inner_class_outer_class_info_offset; if (k->inner_classes()->length() == 0) { // No inner class info => no declaring class @@ -1288,35 +1311,51 @@ JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass)) bool found = false; klassOop ok; instanceKlassHandle outer_klass; + bool inner_is_member = false; + int simple_name_index = 0; // Find inner_klass attribute - for(int i = 0; i < i_length && !found; i+= 4) { + for (int i = 0; i < i_length && !found; i += inner_class_next_offset) { int ioff = i_icls->ushort_at(i + inner_class_info_index); int ooff = i_icls->ushort_at(i + outer_class_info_index); - - if (ioff != 0 && ooff != 0) { + int noff = i_icls->ushort_at(i + inner_class_inner_name_offset); + if (ioff != 0) { // Check to see if the name matches the class we're looking for // before attempting to find the class. if (i_cp->klass_name_at_matches(k, ioff)) { klassOop inner_klass = i_cp->klass_at(ioff, CHECK_NULL); - if (k() == inner_klass) { - found = true; + found = (k() == inner_klass); + if (found && ooff != 0) { ok = i_cp->klass_at(ooff, CHECK_NULL); outer_klass = instanceKlassHandle(thread, ok); + simple_name_index = noff; + inner_is_member = true; } } } } + if (found && outer_klass.is_null()) { + // It may be anonymous; try for that. + int encl_method_class_idx = k->enclosing_method_class_index(); + if (encl_method_class_idx != 0) { + ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL); + outer_klass = instanceKlassHandle(thread, ok); + inner_is_member = false; + } + } + // If no inner class attribute found for this class. - if (!found) return NULL; + if (outer_klass.is_null()) return NULL; // Throws an exception if outer klass has not declared k as an inner klass - Reflection::check_for_inner_class(outer_klass, k, CHECK_NULL); - - return (jclass)JNIHandles::make_local(env, outer_klass->java_mirror()); -JVM_END + // We need evidence that each klass knows about the other, or else + // the system could allow a spoof of an inner class to gain access rights. + Reflection::check_for_inner_class(outer_klass, k, inner_is_member, CHECK_NULL); + simple_name_result = (inner_is_member ? i_cp->symbol_at(simple_name_index) : symbolOop(NULL)); + return outer_klass(); +} JVM_ENTRY(jstring, JVM_GetClassSignature(JNIEnv *env, jclass cls)) assert (cls != NULL, "illegal class"); @@ -3213,8 +3252,12 @@ JVM_ENTRY(jclass, JVM_LoadClass0(JNIEnv *env, jobject receiver, } Handle h_loader(THREAD, loader); Handle h_prot (THREAD, protection_domain); - return find_class_from_class_loader(env, name, true, h_loader, h_prot, - false, thread); + jclass result = find_class_from_class_loader(env, name, true, h_loader, h_prot, + false, thread); + if (TraceClassResolution && result != NULL) { + trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result))); + } + return result; JVM_END diff --git a/hotspot/src/share/vm/prims/jvm_misc.hpp b/hotspot/src/share/vm/prims/jvm_misc.hpp index 7af47518c0f..50644842bbd 100644 --- a/hotspot/src/share/vm/prims/jvm_misc.hpp +++ b/hotspot/src/share/vm/prims/jvm_misc.hpp @@ -27,6 +27,7 @@ jclass find_class_from_class_loader(JNIEnv* env, symbolHandle name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS); +void trace_class_resolution(klassOop to_class); /* * Support for Serialization and RMI. Currently used by HotSpot only. diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp index a19c48972c8..95977f0092e 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp @@ -99,6 +99,9 @@ JvmtiEnv::SetThreadLocalStorage(JavaThread* java_thread, const void* data) { } // otherwise, create the state state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } } state->env_thread_state(this)->set_agent_thread_local_storage_data((void*)data); return JVMTI_ERROR_NONE; @@ -1308,6 +1311,9 @@ JvmtiEnv::GetFrameCount(JavaThread* java_thread, jint* count_ptr) { // retrieve or create JvmtiThreadState. JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } uint32_t debug_bits = 0; if (is_thread_fully_suspended(java_thread, true, &debug_bits)) { err = get_frame_count(state, count_ptr); @@ -1329,6 +1335,12 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) { HandleMark hm(current_thread); uint32_t debug_bits = 0; + // retrieve or create the state + JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } + // Check if java_thread is fully suspended if (!is_thread_fully_suspended(java_thread, true /* wait for suspend completion */, &debug_bits)) { return JVMTI_ERROR_THREAD_NOT_SUSPENDED; @@ -1399,9 +1411,6 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) { // It's fine to update the thread state here because no JVMTI events // shall be posted for this PopFrame. - // retreive or create the state - JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); - state->update_for_pop_top_frame(); java_thread->set_popframe_condition(JavaThread::popframe_pending_bit); // Set pending step flag for this popframe and it is cleared when next @@ -1445,6 +1454,11 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) { ResourceMark rm; uint32_t debug_bits = 0; + JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } + if (!JvmtiEnv::is_thread_fully_suspended(java_thread, true, &debug_bits)) { return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } @@ -1464,7 +1478,6 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) { assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL"); - JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread); int frame_number = state->count_frames() - depth; state->env_thread_state(this)->set_frame_pop(frame_number); diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp index 3152e91c3a5..c0c98f01e53 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp @@ -94,6 +94,35 @@ JvmtiEnvBase::initialize() { } +bool +JvmtiEnvBase::is_valid() { + jint value = 0; + + // This object might not be a JvmtiEnvBase so we can't assume + // the _magic field is properly aligned. Get the value in a safe + // way and then check against JVMTI_MAGIC. + + switch (sizeof(_magic)) { + case 2: + value = Bytes::get_native_u2((address)&_magic); + break; + + case 4: + value = Bytes::get_native_u4((address)&_magic); + break; + + case 8: + value = Bytes::get_native_u8((address)&_magic); + break; + + default: + guarantee(false, "_magic field is an unexpected size"); + } + + return value == JVMTI_MAGIC; +} + + JvmtiEnvBase::JvmtiEnvBase() : _env_event_enable() { _env_local_storage = NULL; _tag_map = NULL; @@ -1322,6 +1351,12 @@ JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState HandleMark hm(current_thread); uint32_t debug_bits = 0; + // retrieve or create the state + JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); + if (state == NULL) { + return JVMTI_ERROR_THREAD_NOT_ALIVE; + } + // Check if java_thread is fully suspended if (!is_thread_fully_suspended(java_thread, true /* wait for suspend completion */, @@ -1329,9 +1364,6 @@ JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } - // retreive or create the state - JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread); - // Check to see if a ForceEarlyReturn was already in progress if (state->is_earlyret_pending()) { // Probably possible for JVMTI clients to trigger this, but the diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp index 477725ffec5..e6dd31e5870 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp @@ -120,7 +120,7 @@ class JvmtiEnvBase : public CHeapObj { public: - bool is_valid() { return _magic == JVMTI_MAGIC; } + bool is_valid(); bool is_retransformable() { return _is_retransformable; } diff --git a/hotspot/src/share/vm/prims/jvmtiEventController.cpp b/hotspot/src/share/vm/prims/jvmtiEventController.cpp index ebadd45e2c2..4e07d6f84c2 100644 --- a/hotspot/src/share/vm/prims/jvmtiEventController.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEventController.cpp @@ -478,6 +478,11 @@ JvmtiEventControllerPrivate::recompute_env_thread_enabled(JvmtiEnvThreadState* e // set external state accordingly. Only thread-filtered events are included. jlong JvmtiEventControllerPrivate::recompute_thread_enabled(JvmtiThreadState *state) { + if (state == NULL) { + // associated JavaThread is exiting + return (jlong)0; + } + jlong was_any_env_enabled = state->thread_event_enable()->_event_enabled.get_bits(); jlong any_env_enabled = 0; @@ -553,6 +558,7 @@ JvmtiEventControllerPrivate::recompute_enabled() { { MutexLocker mu(Threads_lock); //hold the Threads_lock for the iteration for (JavaThread *tp = Threads::first(); tp != NULL; tp = tp->next()) { + // state_for_while_locked() makes tp->is_exiting() check JvmtiThreadState::state_for_while_locked(tp); // create the thread state if missing } }// release Threads_lock diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index a3894b3d66e..50ecb4b9559 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp @@ -1872,6 +1872,9 @@ void JvmtiExport::post_dynamic_code_generated_while_holding_locks(const char* na { // register the stub with the current dynamic code event collector JvmtiThreadState* state = JvmtiThreadState::state_for(JavaThread::current()); + // state can only be NULL if the current thread is exiting which + // should not happen since we're trying to post an event + guarantee(state != NULL, "attempt to register stub via an exiting thread"); JvmtiDynamicCodeEventCollector* collector = state->get_dynamic_code_event_collector(); guarantee(collector != NULL, "attempt to register stub without event collector"); collector->register_stub(name, code_begin, code_end); @@ -2253,6 +2256,9 @@ void JvmtiExport::cms_ref_processing_epilogue() { void JvmtiEventCollector::setup_jvmti_thread_state() { // set this event collector to be the current one. JvmtiThreadState* state = JvmtiThreadState::state_for(JavaThread::current()); + // state can only be NULL if the current thread is exiting which + // should not happen since we're trying to configure for event collection + guarantee(state != NULL, "exiting thread called setup_jvmti_thread_state"); if (is_vm_object_alloc_event()) { _prev = state->get_vm_object_alloc_event_collector(); state->set_vm_object_alloc_event_collector((JvmtiVMObjectAllocEventCollector *)this); diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.cpp b/hotspot/src/share/vm/prims/jvmtiImpl.cpp index f9a512c4222..5a174b35bc3 100644 --- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp +++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp @@ -238,6 +238,35 @@ JvmtiRawMonitor::~JvmtiRawMonitor() { } +bool +JvmtiRawMonitor::is_valid() { + int value = 0; + + // This object might not be a JvmtiRawMonitor so we can't assume + // the _magic field is properly aligned. Get the value in a safe + // way and then check against JVMTI_RM_MAGIC. + + switch (sizeof(_magic)) { + case 2: + value = Bytes::get_native_u2((address)&_magic); + break; + + case 4: + value = Bytes::get_native_u4((address)&_magic); + break; + + case 8: + value = Bytes::get_native_u8((address)&_magic); + break; + + default: + guarantee(false, "_magic field is an unexpected size"); + } + + return value == JVMTI_RM_MAGIC; +} + + // // class JvmtiBreakpoint // diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.hpp b/hotspot/src/share/vm/prims/jvmtiImpl.hpp index d1b8414e61e..2605546c62d 100644 --- a/hotspot/src/share/vm/prims/jvmtiImpl.hpp +++ b/hotspot/src/share/vm/prims/jvmtiImpl.hpp @@ -349,7 +349,7 @@ public: ~JvmtiRawMonitor(); int magic() { return _magic; } const char *get_name() { return _name; } - bool is_valid() { return _magic == JVMTI_RM_MAGIC; } + bool is_valid(); }; // Onload pending raw monitors diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index 4cc6b577b47..ba9b1d877b0 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -831,6 +831,9 @@ jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) { ResourceMark rm(THREAD); JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current()); + // state can only be NULL if the current thread is exiting which + // should not happen since we're trying to do a RedefineClasses + guarantee(state != NULL, "exiting thread calling load_new_class_versions"); for (int i = 0; i < _class_count; i++) { oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass); // classes for primitives cannot be redefined @@ -1349,39 +1352,39 @@ bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class, // rewrite constant pool references in the methods: if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) { - // propogate failure back to caller + // propagate failure back to caller return false; } // rewrite constant pool references in the class_annotations: if (!rewrite_cp_refs_in_class_annotations(scratch_class, THREAD)) { - // propogate failure back to caller + // propagate failure back to caller return false; } // rewrite constant pool references in the fields_annotations: if (!rewrite_cp_refs_in_fields_annotations(scratch_class, THREAD)) { - // propogate failure back to caller + // propagate failure back to caller return false; } // rewrite constant pool references in the methods_annotations: if (!rewrite_cp_refs_in_methods_annotations(scratch_class, THREAD)) { - // propogate failure back to caller + // propagate failure back to caller return false; } // rewrite constant pool references in the methods_parameter_annotations: if (!rewrite_cp_refs_in_methods_parameter_annotations(scratch_class, THREAD)) { - // propogate failure back to caller + // propagate failure back to caller return false; } // rewrite constant pool references in the methods_default_annotations: if (!rewrite_cp_refs_in_methods_default_annotations(scratch_class, THREAD)) { - // propogate failure back to caller + // propagate failure back to caller return false; } @@ -1600,7 +1603,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_annotations_typeArray( byte_i_ref, THREAD)) { RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad annotation_struct at %d", calc_num_annotations)); - // propogate failure back to caller + // propagate failure back to caller return false; } } @@ -1666,7 +1669,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_annotation_struct( byte_i_ref, THREAD)) { RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad element_value at %d", calc_num_element_value_pairs)); - // propogate failure back to caller + // propagate failure back to caller return false; } } // end for each component @@ -1815,7 +1818,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_element_value( // field. This is a nested annotation. if (!rewrite_cp_refs_in_annotation_struct(annotations_typeArray, byte_i_ref, THREAD)) { - // propogate failure back to caller + // propagate failure back to caller return false; } break; @@ -1842,7 +1845,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_element_value( annotations_typeArray, byte_i_ref, THREAD)) { RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad nested element_value at %d", calc_num_values)); - // propogate failure back to caller + // propagate failure back to caller return false; } } @@ -1886,7 +1889,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_fields_annotations( THREAD)) { RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad field_annotations at %d", i)); - // propogate failure back to caller + // propagate failure back to caller return false; } } @@ -1923,7 +1926,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_annotations( THREAD)) { RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad method_annotations at %d", i)); - // propogate failure back to caller + // propagate failure back to caller return false; } } @@ -1991,7 +1994,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_parameter_annotations( method_parameter_annotations, byte_i, THREAD)) { RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad method_parameter_annotations at %d", calc_num_parameters)); - // propogate failure back to caller + // propagate failure back to caller return false; } } @@ -2041,7 +2044,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_default_annotations( method_default_annotations, byte_i, THREAD)) { RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad default element_value at %d", i)); - // propogate failure back to caller + // propagate failure back to caller return false; } } diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp b/hotspot/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp index 83192cf16d7..6762e572baa 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp @@ -49,8 +49,8 @@ // 0x00000400 | 1024 - previous class weak reference mgmt during // add previous ops (GC) // 0x00000800 | 2048 - previous class breakpoint mgmt -// 0x00001000 | 4096 - unused -// 0x00002000 | 8192 - unused +// 0x00001000 | 4096 - detect calls to obsolete methods +// 0x00002000 | 8192 - fail a guarantee() in addition to detection // 0x00004000 | 16384 - unused // 0x00008000 | 32768 - old/new method matching/add/delete // 0x00010000 | 65536 - impl details: CP size info diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp index dcf83bb22d4..41c0693a4c3 100644 --- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/prims/jvmtiThreadState.hpp b/hotspot/src/share/vm/prims/jvmtiThreadState.hpp index 703d873397f..d77d2a8a428 100644 --- a/hotspot/src/share/vm/prims/jvmtiThreadState.hpp +++ b/hotspot/src/share/vm/prims/jvmtiThreadState.hpp @@ -314,17 +314,24 @@ class JvmtiThreadState : public CHeapObj { void update_for_pop_top_frame(); // already holding JvmtiThreadState_lock - retrieve or create JvmtiThreadState + // Can return NULL if JavaThread is exiting. inline static JvmtiThreadState *state_for_while_locked(JavaThread *thread) { assert(JvmtiThreadState_lock->is_locked(), "sanity check"); JvmtiThreadState *state = thread->jvmti_thread_state(); if (state == NULL) { + if (thread->is_exiting()) { + // don't add a JvmtiThreadState to a thread that is exiting + return NULL; + } + state = new JvmtiThreadState(thread); } return state; } // retrieve or create JvmtiThreadState + // Can return NULL if JavaThread is exiting. inline static JvmtiThreadState *state_for(JavaThread *thread) { JvmtiThreadState *state = thread->jvmti_thread_state(); if (state == NULL) { diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 417522943ad..53ea39cd082 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -852,16 +852,13 @@ bool Arguments::add_property(const char* prop) { FreeHeap(value); } return true; - } - else if (strcmp(key, "sun.java.command") == 0) { - + } else if (strcmp(key, "sun.java.command") == 0) { _java_command = value; // don't add this property to the properties exposed to the java application FreeHeap(key); return true; - } - else if (strcmp(key, "sun.java.launcher.pid") == 0) { + } else if (strcmp(key, "sun.java.launcher.pid") == 0) { // launcher.pid property is private and is processed // in process_sun_java_launcher_properties(); // the sun.java.launcher property is passed on to the java application @@ -870,13 +867,14 @@ bool Arguments::add_property(const char* prop) { FreeHeap(value); } return true; - } - else if (strcmp(key, "java.vendor.url.bug") == 0) { + } else if (strcmp(key, "java.vendor.url.bug") == 0) { // save it in _java_vendor_url_bug, so JVM fatal error handler can access // its value without going through the property list or making a Java call. _java_vendor_url_bug = value; + } else if (strcmp(key, "sun.boot.library.path") == 0) { + PropertyList_unique_add(&_system_properties, key, value, true); + return true; } - // Create new property and add at the end of the list PropertyList_unique_add(&_system_properties, key, value); return true; @@ -895,7 +893,7 @@ void Arguments::set_mode_flags(Mode mode) { // Ensure Agent_OnLoad has the correct initial values. // This may not be the final mode; mode may change later in onload phase. PropertyList_unique_add(&_system_properties, "java.vm.info", - (char*)Abstract_VM_Version::vm_info_string()); + (char*)Abstract_VM_Version::vm_info_string(), false); UseInterpreter = true; UseCompiler = true; @@ -971,7 +969,7 @@ void Arguments::set_parnew_gc_flags() { } else { no_shared_spaces(); - // By default YoungPLABSize and OldPLABSize are set to 4096 and 1024 correspondinly, + // By default YoungPLABSize and OldPLABSize are set to 4096 and 1024 respectively, // these settings are default for Parallel Scavenger. For ParNew+Tenured configuration // we set them to 1024 and 1024. // See CR 6362902. @@ -987,6 +985,16 @@ void Arguments::set_parnew_gc_flags() { if (AlwaysTenure) { FLAG_SET_CMDLINE(intx, MaxTenuringThreshold, 0); } + // When using compressed oops, we use local overflow stacks, + // rather than using a global overflow list chained through + // the klass word of the object's pre-image. + if (UseCompressedOops && !ParGCUseLocalOverflow) { + if (!FLAG_IS_DEFAULT(ParGCUseLocalOverflow)) { + warning("Forcing +ParGCUseLocalOverflow: needed if using compressed references"); + } + FLAG_SET_DEFAULT(ParGCUseLocalOverflow, true); + } + assert(ParGCUseLocalOverflow || !UseCompressedOops, "Error"); } } @@ -1211,7 +1219,9 @@ void Arguments::set_ergonomics_flags() { if (UseLargePages && UseCompressedOops) { // Cannot allocate guard pages for implicit checks in indexed addressing // mode, when large pages are specified on windows. - FLAG_SET_DEFAULT(UseImplicitNullCheckForNarrowOop, false); + // This flag could be switched ON if narrow oop base address is set to 0, + // see code in Universe::initialize_heap(). + Universe::set_narrow_oop_use_implicit_null_checks(false); } #endif // _WIN64 } else { @@ -1364,9 +1374,6 @@ void Arguments::set_aggressive_opts_flags() { if (AggressiveOpts && FLAG_IS_DEFAULT(DoEscapeAnalysis)) { FLAG_SET_DEFAULT(DoEscapeAnalysis, true); } - if (AggressiveOpts && FLAG_IS_DEFAULT(SpecialArraysEquals)) { - FLAG_SET_DEFAULT(SpecialArraysEquals, true); - } if (AggressiveOpts && FLAG_IS_DEFAULT(BiasedLockingStartupDelay)) { FLAG_SET_DEFAULT(BiasedLockingStartupDelay, 500); } @@ -2765,7 +2772,7 @@ void Arguments::PropertyList_add(SystemProperty** plist, const char* k, char* v) } // This add maintains unique property key in the list. -void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) { +void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append) { if (plist == NULL) return; @@ -2773,7 +2780,11 @@ void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, c SystemProperty* prop; for (prop = *plist; prop != NULL; prop = prop->next()) { if (strcmp(k, prop->key()) == 0) { - prop->set_value(v); + if (append) { + prop->append_value(v); + } else { + prop->set_value(v); + } return; } } diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index b5dca5b90de..c11aef0001a 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -475,10 +475,13 @@ class Arguments : AllStatic { // System properties static void init_system_properties(); - // Proptery List manipulation + // Property List manipulation static void PropertyList_add(SystemProperty** plist, SystemProperty *element); static void PropertyList_add(SystemProperty** plist, const char* k, char* v); - static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v); + static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) { + PropertyList_unique_add(plist, k, v, false); + } + static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append); static const char* PropertyList_get_value(SystemProperty* plist, const char* key); static int PropertyList_count(SystemProperty* pl); static const char* PropertyList_get_key_at(SystemProperty* pl,int index); diff --git a/hotspot/src/share/vm/runtime/extendedPC.hpp b/hotspot/src/share/vm/runtime/extendedPC.hpp index a2680851adc..19ce2a51447 100644 --- a/hotspot/src/share/vm/runtime/extendedPC.hpp +++ b/hotspot/src/share/vm/runtime/extendedPC.hpp @@ -23,7 +23,7 @@ */ // An ExtendedPC contains the _pc from a signal handler in a platform -// independant way. +// independent way. class ExtendedPC VALUE_OBJ_CLASS_SPEC { private: diff --git a/hotspot/src/share/vm/runtime/fieldDescriptor.cpp b/hotspot/src/share/vm/runtime/fieldDescriptor.cpp index d750981a4c3..a5e40ad8e26 100644 --- a/hotspot/src/share/vm/runtime/fieldDescriptor.cpp +++ b/hotspot/src/share/vm/runtime/fieldDescriptor.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,13 +107,14 @@ void fieldDescriptor::print_on(outputStream* st) const { void fieldDescriptor::print_on_for(outputStream* st, oop obj) { print_on(st); BasicType ft = field_type(); - jint as_int; + jint as_int = 0; switch (ft) { case T_BYTE: as_int = (jint)obj->byte_field(offset()); st->print(" %d", obj->byte_field(offset())); break; case T_CHAR: + as_int = (jint)obj->char_field(offset()); { jchar c = obj->char_field(offset()); as_int = c; @@ -128,6 +129,7 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj) { st->print(" %f", obj->float_field(offset())); break; case T_INT: + as_int = obj->int_field(offset()); st->print(" %d", obj->int_field(offset())); break; case T_LONG: @@ -144,12 +146,12 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj) { break; case T_ARRAY: st->print(" "); - as_int = obj->int_field(offset()); + NOT_LP64(as_int = obj->int_field(offset())); obj->obj_field(offset())->print_value_on(st); break; case T_OBJECT: st->print(" "); - as_int = obj->int_field(offset()); + NOT_LP64(as_int = obj->int_field(offset())); obj->obj_field(offset())->print_value_on(st); break; default: @@ -158,9 +160,9 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj) { } // Print a hint as to the underlying integer representation. This can be wrong for // pointers on an LP64 machine - if (ft == T_LONG || ft == T_DOUBLE) { + if (ft == T_LONG || ft == T_DOUBLE LP64_ONLY(|| !is_java_primitive(ft)) ) { st->print(" (%x %x)", obj->int_field(offset()), obj->int_field(offset()+sizeof(jint))); - } else { + } else if (as_int < 0 || as_int > 9) { st->print(" (%x)", as_int); } } diff --git a/hotspot/src/share/vm/runtime/fprofiler.cpp b/hotspot/src/share/vm/runtime/fprofiler.cpp index adecc642de4..87554e371f2 100644 --- a/hotspot/src/share/vm/runtime/fprofiler.cpp +++ b/hotspot/src/share/vm/runtime/fprofiler.cpp @@ -988,7 +988,7 @@ extern "C" void find(int x); void ThreadProfiler::record_tick_for_running_frame(JavaThread* thread, frame fr) { - // The tick happend in real code -> non VM code + // The tick happened in real code -> non VM code if (fr.is_interpreted_frame()) { interval_data_ref()->inc_interpreted(); record_interpreted_tick(thread, fr, tp_code, FlatProfiler::bytecode_ticks); @@ -1019,7 +1019,7 @@ void ThreadProfiler::record_tick_for_running_frame(JavaThread* thread, frame fr) } void ThreadProfiler::record_tick_for_calling_frame(JavaThread* thread, frame fr) { - // The tick happend in VM code + // The tick happened in VM code interval_data_ref()->inc_native(); if (fr.is_interpreted_frame()) { record_interpreted_tick(thread, fr, tp_native, FlatProfiler::bytecode_ticks_stub); diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index e84d6d3ad8b..8d53406e41b 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -930,7 +930,7 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer // => process callee's arguments // // Note: The expression stack can be empty if an exception - // occured during method resolution/execution. In all + // occurred during method resolution/execution. In all // cases we empty the expression stack completely be- // fore handling the exception (the exception handling // code in the interpreter calls a blocking runtime diff --git a/hotspot/src/share/vm/runtime/frame.inline.hpp b/hotspot/src/share/vm/runtime/frame.inline.hpp index 3449ead761a..95acb8dbbda 100644 --- a/hotspot/src/share/vm/runtime/frame.inline.hpp +++ b/hotspot/src/share/vm/runtime/frame.inline.hpp @@ -22,7 +22,7 @@ * */ -// This file holds platform-independant bodies of inline functions for frames. +// This file holds platform-independent bodies of inline functions for frames. // Note: The bcx usually contains the bcp; however during GC it contains the bci // (changed by gc_prologue() and gc_epilogue()) to be methodOop position diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index c16ae09ec32..3bbf2bd6cf5 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ define_pd_global(intx, Tier4BackEdgeThreshold, 0); define_pd_global(intx, OnStackReplacePercentage, 0); define_pd_global(bool, ResizeTLAB, false); define_pd_global(intx, FreqInlineSize, 0); +define_pd_global(intx, InlineSmallCode, 0); define_pd_global(intx, NewSizeThreadIncrease, 4*K); define_pd_global(intx, NewRatio, 4); define_pd_global(intx, InlineClassNatives, true); @@ -303,11 +304,14 @@ class CommandLineFlags { "Use 32-bit object references in 64-bit VM. " \ "lp64_product means flag is always constant in 32 bit VM") \ \ - lp64_product(bool, CheckCompressedOops, trueInDebug, \ - "generate checks in encoding/decoding code") \ + notproduct(bool, CheckCompressedOops, true, \ + "generate checks in encoding/decoding code in debug VM") \ \ - product(bool, UseImplicitNullCheckForNarrowOop, true, \ - "generate implicit null check in indexed addressing mode.") \ + product_pd(uintx, HeapBaseMinAddress, \ + "OS specific low limit for heap base address") \ + \ + diagnostic(bool, PrintCompressedOopsMode, false, \ + "Print compressed oops base address and encoding mode") \ \ /* UseMembar is theoretically a temp flag used for memory barrier \ * removal testing. It was supposed to be removed before FCS but has \ @@ -487,9 +491,15 @@ class CommandLineFlags { develop(bool, SpecialStringIndexOf, true, \ "special version of string indexOf") \ \ - product(bool, SpecialArraysEquals, false, \ + develop(bool, SpecialStringEquals, true, \ + "special version of string equals") \ + \ + develop(bool, SpecialArraysEquals, true, \ "special version of Arrays.equals(char[],char[])") \ \ + product(bool, UseSSE42Intrinsics, false, \ + "SSE4.2 versions of intrinsics") \ + \ develop(bool, TraceCallFixup, false, \ "traces all call fixups") \ \ @@ -662,6 +672,12 @@ class CommandLineFlags { product(ccstrlist, OnOutOfMemoryError, "", \ "Run user-defined commands on first java.lang.OutOfMemoryError") \ \ + manageable(bool, HeapDumpBeforeFullGC, false, \ + "Dump heap to file before any major stop-world GC") \ + \ + manageable(bool, HeapDumpAfterFullGC, false, \ + "Dump heap to file after any major stop-world GC") \ + \ manageable(bool, HeapDumpOnOutOfMemoryError, false, \ "Dump heap to file when java.lang.OutOfMemoryError is thrown") \ \ @@ -1307,6 +1323,12 @@ class CommandLineFlags { product(intx, ParGCArrayScanChunk, 50, \ "Scan a subset and push remainder, if array is bigger than this") \ \ + product(bool, ParGCUseLocalOverflow, false, \ + "Instead of a global overflow list, use local overflow stacks") \ + \ + product(bool, ParGCTrimOverflow, true, \ + "Eagerly trim the local overflow lists (when ParGCUseLocalOverflow") \ + \ notproduct(bool, ParGCWorkQueueOverflowALot, false, \ "Whether we should simulate work queue overflow in ParNew") \ \ @@ -1971,6 +1993,12 @@ class CommandLineFlags { product(bool, PrintHeapAtSIGBREAK, true, \ "Print heap layout in response to SIGBREAK") \ \ + manageable(bool, PrintClassHistogramBeforeFullGC, false, \ + "Print a class histogram before any major stop-world GC") \ + \ + manageable(bool, PrintClassHistogramAfterFullGC, false, \ + "Print a class histogram after any major stop-world GC") \ + \ manageable(bool, PrintClassHistogram, false, \ "Print a histogram of class instances") \ \ @@ -2157,6 +2185,9 @@ class CommandLineFlags { diagnostic(bool, PrintIntrinsics, false, \ "prints attempted and successful inlining of intrinsics") \ \ + product(bool, UsePopCountInstruction, false, \ + "Use population count instruction") \ + \ diagnostic(ccstrlist, DisableIntrinsic, "", \ "do not expand intrinsics whose (internal) names appear here") \ \ @@ -2598,7 +2629,7 @@ class CommandLineFlags { develop(intx, MaxRecursiveInlineLevel, 1, \ "maximum number of nested recursive calls that are inlined") \ \ - product(intx, InlineSmallCode, 1000, \ + product_pd(intx, InlineSmallCode, \ "Only inline already compiled methods if their code size is " \ "less than this") \ \ diff --git a/hotspot/src/share/vm/runtime/handles.hpp b/hotspot/src/share/vm/runtime/handles.hpp index 55e9b41fa20..c44c6ac3d22 100644 --- a/hotspot/src/share/vm/runtime/handles.hpp +++ b/hotspot/src/share/vm/runtime/handles.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,6 +137,14 @@ class KlassHandle: public Handle { assert(is_null() || obj()->is_klass(), "not a klassOop"); } + // Direct interface, use very sparingly. + // Used by SystemDictionaryHandles to create handles on existing WKKs. + // The obj of such a klass handle may be null, because the handle is formed + // during system bootstrapping. + KlassHandle(klassOop *handle, bool dummy) : Handle((oop*)handle, dummy) { + assert(SharedSkipVerify || is_null() || obj() == NULL || obj()->is_klass(), "not a klassOop"); + } + // General access klassOop operator () () const { return obj(); } Klass* operator -> () const { return as_klass(); } diff --git a/hotspot/src/share/vm/runtime/hpi.hpp b/hotspot/src/share/vm/runtime/hpi.hpp index 1e05ca7525a..506b911ca12 100644 --- a/hotspot/src/share/vm/runtime/hpi.hpp +++ b/hotspot/src/share/vm/runtime/hpi.hpp @@ -90,7 +90,7 @@ public: static inline struct protoent* get_proto_by_name(char* name); // HPI_LibraryInterface - static inline void dll_build_name(char *buf, int buf_len, char* path, + static inline void dll_build_name(char *buf, int buf_len, const char* path, const char *name); static inline void* dll_load(const char *name, char *ebuf, int ebuflen); static inline void dll_unload(void *lib); @@ -137,7 +137,15 @@ public: return result; \ } - +#define VM_HPIDECL_VOID(name, names, func, arg_type, arg_print, arg) \ + inline void hpi::name arg_type { \ + if (TraceHPI) { \ + tty->print("hpi::" names "("); \ + tty->print arg_print; \ + tty->print(") = "); \ + } \ + func arg; \ + } #define HPIDECL_VOID(name, names, intf, func, arg_type, arg_print, arg) \ inline void hpi::name arg_type { \ @@ -197,11 +205,11 @@ HPIDECL(fsize, "fsize", _file, FileSizeFD, int, "%d", (fd, size)); // HPI_LibraryInterface -HPIDECL_VOID(dll_build_name, "dll_build_name", _library, BuildLibName, - (char *buf, int buf_len, char *path, const char *name), - ("buf = %p, buflen = %d, path = %s, name = %s", - buf, buf_len, path, name), - (buf, buf_len, path, name)); +VM_HPIDECL_VOID(dll_build_name, "dll_build_name", os::dll_build_name, + (char *buf, int buf_len, const char *path, const char *name), + ("buf = %p, buflen = %d, path = %s, name = %s", + buf, buf_len, path, name), + (buf, buf_len, path, name)); VM_HPIDECL(dll_load, "dll_load", os::dll_load, void *, "(void *)%p", diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 77950cf7679..92773e80930 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/runtime/memprofiler.cpp b/hotspot/src/share/vm/runtime/memprofiler.cpp index f8a259f9be2..c141e3216a6 100644 --- a/hotspot/src/share/vm/runtime/memprofiler.cpp +++ b/hotspot/src/share/vm/runtime/memprofiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/runtime/mutex.hpp b/hotspot/src/share/vm/runtime/mutex.hpp index edebb8800ae..f0b9e8bd79d 100644 --- a/hotspot/src/share/vm/runtime/mutex.hpp +++ b/hotspot/src/share/vm/runtime/mutex.hpp @@ -82,7 +82,7 @@ class ParkEvent ; // *in that order*. If their implementations change such that these // assumptions are violated, a whole lot of code will break. -// The default length of monitor name is choosen to be 64 to avoid false sharing. +// The default length of monitor name is chosen to be 64 to avoid false sharing. static const int MONITOR_NAME_LEN = 64; class Monitor : public CHeapObj { diff --git a/hotspot/src/share/vm/runtime/orderAccess.cpp b/hotspot/src/share/vm/runtime/orderAccess.cpp index 392b5978126..1e66d6258f5 100644 --- a/hotspot/src/share/vm/runtime/orderAccess.cpp +++ b/hotspot/src/share/vm/runtime/orderAccess.cpp @@ -26,3 +26,15 @@ # include "incls/_orderAccess.cpp.incl" volatile intptr_t OrderAccess::dummy = 0; + +void OrderAccess::StubRoutines_fence() { + // Use a stub if it exists. It may not exist during bootstrap so do + // nothing in that case but assert if no fence code exists after threads have been created + void (*func)() = CAST_TO_FN_PTR(void (*)(), StubRoutines::fence_entry()); + + if (func != NULL) { + (*func)(); + return; + } + assert(Threads::number_of_threads() == 0, "for bootstrap only"); +} diff --git a/hotspot/src/share/vm/runtime/orderAccess.hpp b/hotspot/src/share/vm/runtime/orderAccess.hpp index a2040ed8488..d6b83466da5 100644 --- a/hotspot/src/share/vm/runtime/orderAccess.hpp +++ b/hotspot/src/share/vm/runtime/orderAccess.hpp @@ -31,7 +31,7 @@ // at runtime. // // In the following, the terms 'previous', 'subsequent', 'before', -// 'after', 'preceeding' and 'succeeding' refer to program order. The +// 'after', 'preceding' and 'succeeding' refer to program order. The // terms 'down' and 'below' refer to forward load or store motion // relative to program order, while 'up' and 'above' refer to backward // motion. @@ -300,4 +300,10 @@ class OrderAccess : AllStatic { // In order to force a memory access, implementations may // need a volatile externally visible dummy variable. static volatile intptr_t dummy; + + private: + // This is a helper that invokes the StubRoutines::fence_entry() + // routine if it exists, It should only be used by platforms that + // don't another way to do the inline eassembly. + static void StubRoutines_fence(); }; diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 8c81d42734a..f23f6af42e7 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,7 +207,8 @@ static void signal_thread_entry(JavaThread* thread, TRAPS) { VMThread::execute(&op1); Universe::print_heap_at_SIGBREAK(); if (PrintClassHistogram) { - VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */); + VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */, + true /* need_prologue */); VMThread::execute(&op1); } if (JvmtiExport::should_post_data_dump()) { @@ -862,7 +863,6 @@ char* os::format_boot_path(const char* format_string, bool os::set_boot_path(char fileSep, char pathSep) { - const char* home = Arguments::get_java_home(); int home_len = (int)strlen(home); @@ -892,6 +892,60 @@ bool os::set_boot_path(char fileSep, char pathSep) { return true; } +/* + * Splits a path, based on its separator, the number of + * elements is returned back in n. + * It is the callers responsibility to: + * a> check the value of n, and n may be 0. + * b> ignore any empty path elements + * c> free up the data. + */ +char** os::split_path(const char* path, int* n) { + *n = 0; + if (path == NULL || strlen(path) == 0) { + return NULL; + } + const char psepchar = *os::path_separator(); + char* inpath = (char*)NEW_C_HEAP_ARRAY(char, strlen(path) + 1); + if (inpath == NULL) { + return NULL; + } + strncpy(inpath, path, strlen(path)); + int count = 1; + char* p = strchr(inpath, psepchar); + // Get a count of elements to allocate memory + while (p != NULL) { + count++; + p++; + p = strchr(p, psepchar); + } + char** opath = (char**) NEW_C_HEAP_ARRAY(char*, count); + if (opath == NULL) { + return NULL; + } + + // do the actual splitting + p = inpath; + for (int i = 0 ; i < count ; i++) { + size_t len = strcspn(p, os::path_separator()); + if (len > JVM_MAXPATHLEN) { + return NULL; + } + // allocate the string and add terminator storage + char* s = (char*)NEW_C_HEAP_ARRAY(char, len + 1); + if (s == NULL) { + return NULL; + } + strncpy(s, p, len); + s[len] = '\0'; + opath[i] = s; + p += len + 1; + } + FREE_C_HEAP_ARRAY(char, inpath); + *n = count; + return opath; +} + void os::set_memory_serialize_page(address page) { int count = log2_intptr(sizeof(class JavaThread)) - log2_intptr(64); _mem_serialize_page = (volatile int32_t *)page; @@ -943,7 +997,7 @@ bool os::stack_shadow_pages_available(Thread *thread, methodHandle method) { assert(StackRedPages > 0 && StackYellowPages > 0,"Sanity check"); address sp = current_stack_pointer(); // Check if we have StackShadowPages above the yellow zone. This parameter - // is dependant on the depth of the maximum VM call stack possible from + // is dependent on the depth of the maximum VM call stack possible from // the handler for stack overflow. 'instanceof' in the stack overflow // handler or a println uses at least 8k stack of VM and native code // respectively. diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index ce653c5f6f2..41408583200 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -202,8 +202,10 @@ class os: AllStatic { static char* attempt_reserve_memory_at(size_t bytes, char* addr); static void split_reserved_memory(char *base, size_t size, size_t split, bool realloc); - static bool commit_memory(char* addr, size_t bytes); - static bool commit_memory(char* addr, size_t size, size_t alignment_hint); + static bool commit_memory(char* addr, size_t bytes, + bool executable = false); + static bool commit_memory(char* addr, size_t size, size_t alignment_hint, + bool executable = false); static bool uncommit_memory(char* addr, size_t bytes); static bool release_memory(char* addr, size_t bytes); @@ -243,7 +245,8 @@ class os: AllStatic { static char* non_memory_address_word(); // reserve, commit and pin the entire memory region - static char* reserve_memory_special(size_t size); + static char* reserve_memory_special(size_t size, char* addr = NULL, + bool executable = false); static bool release_memory_special(char* addr, size_t bytes); static bool large_page_init(); static size_t large_page_size(); @@ -604,6 +607,7 @@ class os: AllStatic { char fileSep, char pathSep); static bool set_boot_path(char fileSep, char pathSep); + static char** split_path(const char* path, int* n); }; // Note that "PAUSE" is almost always used with synchronization diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index 3bc1b029d4c..6c7fe33ee6b 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -554,10 +554,18 @@ bool Reflection::is_same_class_package(klassOop class1, klassOop class2) { return instanceKlass::cast(class1)->is_same_class_package(class2); } +bool Reflection::is_same_package_member(klassOop class1, klassOop class2, TRAPS) { + return instanceKlass::cast(class1)->is_same_package_member(class2, THREAD); +} + // Checks that the 'outer' klass has declared 'inner' as being an inner klass. If not, // throw an incompatible class change exception -void Reflection::check_for_inner_class(instanceKlassHandle outer, instanceKlassHandle inner, TRAPS) { +// If inner_is_member, require the inner to be a member of the outer. +// If !inner_is_member, require the inner to be anonymous (a non-member). +// Caller is responsible for figuring out in advance which case must be true. +void Reflection::check_for_inner_class(instanceKlassHandle outer, instanceKlassHandle inner, + bool inner_is_member, TRAPS) { const int inner_class_info_index = 0; const int outer_class_info_index = 1; @@ -567,7 +575,7 @@ void Reflection::check_for_inner_class(instanceKlassHandle outer, instanceKlassH int ioff = icls->ushort_at(i + inner_class_info_index); int ooff = icls->ushort_at(i + outer_class_info_index); - if (ioff != 0 && ooff != 0) { + if (inner_is_member && ioff != 0 && ooff != 0) { klassOop o = cp->klass_at(ooff, CHECK); if (o == outer()) { klassOop i = cp->klass_at(ioff, CHECK); @@ -576,6 +584,13 @@ void Reflection::check_for_inner_class(instanceKlassHandle outer, instanceKlassH } } } + if (!inner_is_member && ioff != 0 && ooff == 0 && + cp->klass_name_at_matches(inner, ioff)) { + klassOop i = cp->klass_at(ioff, CHECK); + if (i == inner()) { + return; + } + } } // 'inner' not declared as an inner klass in outer diff --git a/hotspot/src/share/vm/runtime/reflection.hpp b/hotspot/src/share/vm/runtime/reflection.hpp index 4e8054af5cd..56a54cd0e32 100644 --- a/hotspot/src/share/vm/runtime/reflection.hpp +++ b/hotspot/src/share/vm/runtime/reflection.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,12 +87,18 @@ class Reflection: public AllStatic { bool classloader_only, bool protected_restriction = false); static bool is_same_class_package(klassOop class1, klassOop class2); + static bool is_same_package_member(klassOop class1, klassOop class2, TRAPS); static bool can_relax_access_check_for( klassOop accessor, klassOop accesee, bool classloader_only); // inner class reflection - static void check_for_inner_class(instanceKlassHandle outer, instanceKlassHandle inner, TRAPS); + // raise an ICCE unless the required relationship can be proven to hold + // If inner_is_member, require the inner to be a member of the outer. + // If !inner_is_member, require the inner to be anonymous (a non-member). + // Caller is responsible for figuring out in advance which case must be true. + static void check_for_inner_class(instanceKlassHandle outer, instanceKlassHandle inner, + bool inner_is_member, TRAPS); // // Support for reflection based on dynamic bytecode generation (JDK 1.4) diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp index c13af643a85..eed2afff8f9 100644 --- a/hotspot/src/share/vm/runtime/safepoint.cpp +++ b/hotspot/src/share/vm/runtime/safepoint.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -369,7 +369,7 @@ void SafepointSynchronize::end() { // Start suspended threads for(JavaThread *current = Threads::first(); current; current = current->next()) { - // A problem occuring on Solaris is when attempting to restart threads + // A problem occurring on Solaris is when attempting to restart threads // the first #cpus - 1 go well, but then the VMThread is preempted when we get // to the next one (since it has been running the longest). We then have // to wait for a cpu to become available before we can continue restarting diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index cf69631c0bb..787674569e7 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -377,6 +377,32 @@ void SharedRuntime::throw_and_post_jvmti_exception(JavaThread *thread, symbolOop throw_and_post_jvmti_exception(thread, h_exception); } +// The interpreter code to call this tracing function is only +// called/generated when TraceRedefineClasses has the right bits +// set. Since obsolete methods are never compiled, we don't have +// to modify the compilers to generate calls to this function. +// +JRT_LEAF(int, SharedRuntime::rc_trace_method_entry( + JavaThread* thread, methodOopDesc* method)) + assert(RC_TRACE_IN_RANGE(0x00001000, 0x00002000), "wrong call"); + + if (method->is_obsolete()) { + // We are calling an obsolete method, but this is not necessarily + // an error. Our method could have been redefined just after we + // fetched the methodOop from the constant pool. + + // RC_TRACE macro has an embedded ResourceMark + RC_TRACE_WITH_THREAD(0x00001000, thread, + ("calling obsolete method '%s'", + method->name_and_sig_as_C_string())); + if (RC_TRACE_ENABLED(0x00002000)) { + // this option is provided to debug calls to obsolete methods + guarantee(false, "faulting at call to an obsolete method."); + } + } + return 0; +JRT_END + // ret_pc points into caller; we are returning caller's exception handler // for given exception address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, Handle& exception, @@ -649,48 +675,6 @@ JRT_ENTRY(void, SharedRuntime::yield_all(JavaThread* thread, int attempts)) JRT_END -// --------------------------------------------------------------------------------------------------------- -// Non-product code -#ifndef PRODUCT - -void SharedRuntime::verify_caller_frame(frame caller_frame, methodHandle callee_method) { - ResourceMark rm; - assert (caller_frame.is_interpreted_frame(), "sanity check"); - assert (callee_method->has_compiled_code(), "callee must be compiled"); - methodHandle caller_method (Thread::current(), caller_frame.interpreter_frame_method()); - jint bci = caller_frame.interpreter_frame_bci(); - methodHandle method = find_callee_method_inside_interpreter(caller_frame, caller_method, bci); - assert (callee_method == method, "incorrect method"); -} - -methodHandle SharedRuntime::find_callee_method_inside_interpreter(frame caller_frame, methodHandle caller_method, int bci) { - EXCEPTION_MARK; - Bytecode_invoke* bytecode = Bytecode_invoke_at(caller_method, bci); - methodHandle staticCallee = bytecode->static_target(CATCH); // Non-product code - - bytecode = Bytecode_invoke_at(caller_method, bci); - int bytecode_index = bytecode->index(); - Bytecodes::Code bc = bytecode->adjusted_invoke_code(); - - Handle receiver; - if (bc == Bytecodes::_invokeinterface || - bc == Bytecodes::_invokevirtual || - bc == Bytecodes::_invokespecial) { - symbolHandle signature (THREAD, staticCallee->signature()); - receiver = Handle(THREAD, retrieve_receiver(signature, caller_frame)); - } else { - receiver = Handle(); - } - CallInfo result; - constantPoolHandle constants (THREAD, caller_method->constants()); - LinkResolver::resolve_invoke(result, receiver, constants, bytecode_index, bc, CATCH); // Non-product code - methodHandle calleeMethod = result.selected_method(); - return calleeMethod; -} - -#endif // PRODUCT - - JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* thread, oopDesc* obj)) assert(obj->is_oop(), "must be a valid oop"); assert(obj->klass()->klass_part()->has_finalizer(), "shouldn't be here otherwise"); diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index d040660dcfa..e98f71d1ce6 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -166,6 +166,9 @@ class SharedRuntime: AllStatic { static void throw_and_post_jvmti_exception(JavaThread *thread, Handle h_exception); static void throw_and_post_jvmti_exception(JavaThread *thread, symbolOop name, const char *message = NULL); + // RedefineClasses() tracing support for obsolete method entry + static int rc_trace_method_entry(JavaThread* thread, methodOopDesc* m); + // To be used as the entry point for unresolved native methods. static address native_method_throw_unsatisfied_link_error_entry(); @@ -177,9 +180,6 @@ class SharedRuntime: AllStatic { static oop retrieve_receiver( symbolHandle sig, frame caller ); - static void verify_caller_frame(frame caller_frame, methodHandle callee_method) PRODUCT_RETURN; - static methodHandle find_callee_method_inside_interpreter(frame caller_frame, methodHandle caller_method, int bci) PRODUCT_RETURN_(return methodHandle();); - static void register_finalizer(JavaThread* thread, oopDesc* obj); // dtrace notifications diff --git a/hotspot/src/share/vm/runtime/signature.hpp b/hotspot/src/share/vm/runtime/signature.hpp index 51b45a0a063..9b506d32902 100644 --- a/hotspot/src/share/vm/runtime/signature.hpp +++ b/hotspot/src/share/vm/runtime/signature.hpp @@ -266,7 +266,7 @@ class Fingerprinter: public SignatureIterator { class NativeSignatureIterator: public SignatureIterator { private: methodHandle _method; -// We need seperate JNI and Java offset values because in 64 bit mode, +// We need separate JNI and Java offset values because in 64 bit mode, // the argument offsets are not in sync with the Java stack. // For example a long takes up 1 "C" stack entry but 2 Java stack entries. int _offset; // The java stack offset diff --git a/hotspot/src/share/vm/runtime/synchronizer.cpp b/hotspot/src/share/vm/runtime/synchronizer.cpp index e0f3cfe04bb..ca6bdb13ade 100644 --- a/hotspot/src/share/vm/runtime/synchronizer.cpp +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 2e4c6360143..547ea7fe64c 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -3007,17 +3007,19 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { } if (UseStringCache) { - // Forcibly initialize java/lang/String and mutate the private + // Forcibly initialize java/lang/StringValue and mutate the private // static final "stringCacheEnabled" field before we start creating instances - klassOop k_o = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_String(), Handle(), Handle(), CHECK_0); - KlassHandle k = KlassHandle(THREAD, k_o); - guarantee(k.not_null(), "Must find java/lang/String"); - instanceKlassHandle ik = instanceKlassHandle(THREAD, k()); - ik->initialize(CHECK_0); - fieldDescriptor fd; - // Possible we might not find this field; if so, don't break - if (ik->find_local_field(vmSymbols::stringCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { - k()->bool_field_put(fd.offset(), true); + klassOop k_o = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_StringValue(), Handle(), Handle(), CHECK_0); + // Possible that StringValue isn't present: if so, silently don't break + if (k_o != NULL) { + KlassHandle k = KlassHandle(THREAD, k_o); + instanceKlassHandle ik = instanceKlassHandle(THREAD, k()); + ik->initialize(CHECK_0); + fieldDescriptor fd; + // Possible we might not find this field: if so, silently don't break + if (ik->find_local_field(vmSymbols::stringCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { + k()->bool_field_put(fd.offset(), true); + } } } } diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 6e6e88fe318..59aea77b930 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -1345,6 +1345,13 @@ public: public: // Thread local information maintained by JVMTI. void set_jvmti_thread_state(JvmtiThreadState *value) { _jvmti_thread_state = value; } + // A JvmtiThreadState is lazily allocated. This jvmti_thread_state() + // getter is used to get this JavaThread's JvmtiThreadState if it has + // one which means NULL can be returned. JvmtiThreadState::state_for() + // is used to get the specified JavaThread's JvmtiThreadState if it has + // one or it allocates a new JvmtiThreadState for the JavaThread and + // returns it. JvmtiThreadState::state_for() will return NULL only if + // the specified JavaThread is exiting. JvmtiThreadState *jvmti_thread_state() const { return _jvmti_thread_state; } static ByteSize jvmti_thread_state_offset() { return byte_offset_of(JavaThread, _jvmti_thread_state); } void set_jvmti_get_loaded_classes_closure(JvmtiGetLoadedClassesClosure* value) { _jvmti_get_loaded_classes_closure = value; } diff --git a/hotspot/src/share/vm/runtime/threadCritical.hpp b/hotspot/src/share/vm/runtime/threadCritical.hpp index 6f8529512e2..42b43379b5d 100644 --- a/hotspot/src/share/vm/runtime/threadCritical.hpp +++ b/hotspot/src/share/vm/runtime/threadCritical.hpp @@ -29,7 +29,7 @@ // // Due to race conditions during vm exit, some of the os level // synchronization primitives may not be deallocated at exit. It -// is a good plan to implement the platform dependant sections of +// is a good plan to implement the platform dependent sections of // code with resources that are recoverable during process // cleanup by the os. Calling the initialize method before use // is also problematic, it is best to use preinitialized primitives diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp index 5cd996194d9..e6e4b55a690 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.cpp +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp @@ -28,7 +28,7 @@ // ReservedSpace ReservedSpace::ReservedSpace(size_t size) { - initialize(size, 0, false, NULL, 0); + initialize(size, 0, false, NULL, 0, false); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, @@ -36,7 +36,13 @@ ReservedSpace::ReservedSpace(size_t size, size_t alignment, char* requested_address, const size_t noaccess_prefix) { initialize(size+noaccess_prefix, alignment, large, requested_address, - noaccess_prefix); + noaccess_prefix, false); +} + +ReservedSpace::ReservedSpace(size_t size, size_t alignment, + bool large, + bool executable) { + initialize(size, alignment, large, NULL, 0, executable); } char * @@ -109,6 +115,7 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, const size_t prefix_align, const size_t suffix_size, const size_t suffix_align, + char* requested_address, const size_t noaccess_prefix) { assert(prefix_size != 0, "sanity"); @@ -131,7 +138,8 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, const bool try_reserve_special = UseLargePages && prefix_align == os::large_page_size(); if (!os::can_commit_large_page_memory() && try_reserve_special) { - initialize(size, prefix_align, true, NULL, noaccess_prefix); + initialize(size, prefix_align, true, requested_address, noaccess_prefix, + false); return; } @@ -140,13 +148,20 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, _alignment = 0; _special = false; _noaccess_prefix = 0; + _executable = false; // Assert that if noaccess_prefix is used, it is the same as prefix_align. assert(noaccess_prefix == 0 || noaccess_prefix == prefix_align, "noaccess prefix wrong"); // Optimistically try to reserve the exact size needed. - char* addr = os::reserve_memory(size, NULL, prefix_align); + char* addr; + if (requested_address != 0) { + addr = os::attempt_reserve_memory_at(size, + requested_address-noaccess_prefix); + } else { + addr = os::reserve_memory(size, NULL, prefix_align); + } if (addr == NULL) return; // Check whether the result has the needed alignment (unlikely unless @@ -182,7 +197,8 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, void ReservedSpace::initialize(size_t size, size_t alignment, bool large, char* requested_address, - const size_t noaccess_prefix) { + const size_t noaccess_prefix, + bool executable) { const size_t granularity = os::vm_allocation_granularity(); assert((size & granularity - 1) == 0, "size not aligned to os::vm_allocation_granularity()"); @@ -194,6 +210,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, _base = NULL; _size = 0; _special = false; + _executable = executable; _alignment = 0; _noaccess_prefix = 0; if (size == 0) { @@ -206,12 +223,8 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, char* base = NULL; if (special) { - // It's not hard to implement reserve_memory_special() such that it can - // allocate at fixed address, but there seems no use of this feature - // for now, so it's not implemented. - assert(requested_address == NULL, "not implemented"); - base = os::reserve_memory_special(size); + base = os::reserve_memory_special(size, requested_address, executable); if (base != NULL) { // Check alignment constraints @@ -281,7 +294,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment, - bool special) { + bool special, bool executable) { assert((size % os::vm_allocation_granularity()) == 0, "size not allocation aligned"); _base = base; @@ -289,6 +302,7 @@ ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment, _alignment = alignment; _noaccess_prefix = 0; _special = special; + _executable = executable; } @@ -296,9 +310,10 @@ ReservedSpace ReservedSpace::first_part(size_t partition_size, size_t alignment, bool split, bool realloc) { assert(partition_size <= size(), "partition failed"); if (split) { - os::split_reserved_memory(_base, _size, partition_size, realloc); + os::split_reserved_memory(base(), size(), partition_size, realloc); } - ReservedSpace result(base(), partition_size, alignment, special()); + ReservedSpace result(base(), partition_size, alignment, special(), + executable()); return result; } @@ -307,7 +322,7 @@ ReservedSpace ReservedSpace::last_part(size_t partition_size, size_t alignment) { assert(partition_size <= size(), "partition failed"); ReservedSpace result(base() + partition_size, size() - partition_size, - alignment, special()); + alignment, special(), executable()); return result; } @@ -345,6 +360,7 @@ void ReservedSpace::release() { _size = 0; _noaccess_prefix = 0; _special = false; + _executable = false; } } @@ -372,7 +388,8 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large, char* requested_address) : ReservedSpace(size, alignment, large, requested_address, - UseCompressedOops && UseImplicitNullCheckForNarrowOop ? + (UseCompressedOops && (Universe::narrow_oop_base() != NULL) && + Universe::narrow_oop_use_implicit_null_checks()) ? lcm(os::vm_page_size(), alignment) : 0) { // Only reserved space for the java heap should have a noaccess_prefix // if using compressed oops. @@ -382,13 +399,24 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, ReservedHeapSpace::ReservedHeapSpace(const size_t prefix_size, const size_t prefix_align, const size_t suffix_size, - const size_t suffix_align) : + const size_t suffix_align, + char* requested_address) : ReservedSpace(prefix_size, prefix_align, suffix_size, suffix_align, - UseCompressedOops && UseImplicitNullCheckForNarrowOop ? + requested_address, + (UseCompressedOops && (Universe::narrow_oop_base() != NULL) && + Universe::narrow_oop_use_implicit_null_checks()) ? lcm(os::vm_page_size(), prefix_align) : 0) { protect_noaccess_prefix(prefix_size+suffix_size); } +// Reserve space for code segment. Same as Java heap only we mark this as +// executable. +ReservedCodeSpace::ReservedCodeSpace(size_t r_size, + size_t rs_align, + bool large) : + ReservedSpace(r_size, rs_align, large, /*executable*/ true) { +} + // VirtualSpace VirtualSpace::VirtualSpace() { @@ -406,6 +434,7 @@ VirtualSpace::VirtualSpace() { _middle_alignment = 0; _upper_alignment = 0; _special = false; + _executable = false; } @@ -419,6 +448,7 @@ bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { _high = low(); _special = rs.special(); + _executable = rs.executable(); // When a VirtualSpace begins life at a large size, make all future expansion // and shrinking occur aligned to a granularity of large pages. This avoids @@ -476,6 +506,7 @@ void VirtualSpace::release() { _middle_alignment = 0; _upper_alignment = 0; _special = false; + _executable = false; } @@ -585,7 +616,7 @@ bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { assert(low_boundary() <= lower_high() && lower_high() + lower_needs <= lower_high_boundary(), "must not expand beyond region"); - if (!os::commit_memory(lower_high(), lower_needs)) { + if (!os::commit_memory(lower_high(), lower_needs, _executable)) { debug_only(warning("os::commit_memory failed")); return false; } else { @@ -596,7 +627,8 @@ bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { assert(lower_high_boundary() <= middle_high() && middle_high() + middle_needs <= middle_high_boundary(), "must not expand beyond region"); - if (!os::commit_memory(middle_high(), middle_needs, middle_alignment())) { + if (!os::commit_memory(middle_high(), middle_needs, middle_alignment(), + _executable)) { debug_only(warning("os::commit_memory failed")); return false; } @@ -606,7 +638,7 @@ bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { assert(middle_high_boundary() <= upper_high() && upper_high() + upper_needs <= upper_high_boundary(), "must not expand beyond region"); - if (!os::commit_memory(upper_high(), upper_needs)) { + if (!os::commit_memory(upper_high(), upper_needs, _executable)) { debug_only(warning("os::commit_memory failed")); return false; } else { diff --git a/hotspot/src/share/vm/runtime/virtualspace.hpp b/hotspot/src/share/vm/runtime/virtualspace.hpp index fa65035fde0..f412d11ad55 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.hpp +++ b/hotspot/src/share/vm/runtime/virtualspace.hpp @@ -32,12 +32,15 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC { size_t _noaccess_prefix; size_t _alignment; bool _special; + bool _executable; // ReservedSpace - ReservedSpace(char* base, size_t size, size_t alignment, bool special); + ReservedSpace(char* base, size_t size, size_t alignment, bool special, + bool executable); void initialize(size_t size, size_t alignment, bool large, char* requested_address, - const size_t noaccess_prefix); + const size_t noaccess_prefix, + bool executable); // Release parts of an already-reserved memory region [addr, addr + len) to // get a new region that has "compound alignment." Return the start of the @@ -73,17 +76,18 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC { const size_t noaccess_prefix = 0); ReservedSpace(const size_t prefix_size, const size_t prefix_align, const size_t suffix_size, const size_t suffix_align, - const size_t noaccess_prefix); + char* requested_address, + const size_t noaccess_prefix = 0); + ReservedSpace(size_t size, size_t alignment, bool large, bool executable); // Accessors - char* base() const { return _base; } - size_t size() const { return _size; } - size_t alignment() const { return _alignment; } - bool special() const { return _special; } - - size_t noaccess_prefix() const { return _noaccess_prefix; } - - bool is_reserved() const { return _base != NULL; } + char* base() const { return _base; } + size_t size() const { return _size; } + size_t alignment() const { return _alignment; } + bool special() const { return _special; } + bool executable() const { return _executable; } + size_t noaccess_prefix() const { return _noaccess_prefix; } + bool is_reserved() const { return _base != NULL; } void release(); // Splitting @@ -121,7 +125,15 @@ public: ReservedHeapSpace(size_t size, size_t forced_base_alignment, bool large, char* requested_address); ReservedHeapSpace(const size_t prefix_size, const size_t prefix_align, - const size_t suffix_size, const size_t suffix_align); + const size_t suffix_size, const size_t suffix_align, + char* requested_address); +}; + +// Class encapsulating behavior specific memory space for Code +class ReservedCodeSpace : public ReservedSpace { + public: + // Constructor + ReservedCodeSpace(size_t r_size, size_t rs_align, bool large); }; // VirtualSpace is data structure for committing a previously reserved address range in smaller chunks. @@ -141,6 +153,9 @@ class VirtualSpace VALUE_OBJ_CLASS_SPEC { // os::commit_memory() or os::uncommit_memory(). bool _special; + // Need to know if commit should be executable. + bool _executable; + // MPSS Support // Each virtualspace region has a lower, middle, and upper region. // Each region has an end boundary and a high pointer which is the diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index bc8ea34d52e..2de7bbdf56f 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -263,7 +263,9 @@ static inline uint64_t cast_uint64_t(size_t x) static_field(Universe, _bootstrapping, bool) \ static_field(Universe, _fully_initialized, bool) \ static_field(Universe, _verify_count, int) \ - static_field(Universe, _heap_base, address) \ + static_field(Universe, _narrow_oop._base, address) \ + static_field(Universe, _narrow_oop._shift, int) \ + static_field(Universe, _narrow_oop._use_implicit_null_checks, bool) \ \ /**********************************************************************************/ \ /* Generation and Space hierarchies */ \ diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index a2ed20b3b02..8f6e114623b 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -59,7 +59,6 @@ template(G1CollectFull) \ template(G1CollectForAllocation) \ template(G1IncCollectionPause) \ - template(G1PopRegionCollectionPause) \ template(EnableBiasedLocking) \ template(RevokeBias) \ template(BulkRevokeBias) \ diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index 653309db0ac..3e7a7e6e0fe 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -163,9 +163,11 @@ const char* Abstract_VM_Version::internal_vm_info_string() { #elif _MSC_VER == 1200 #define HOTSPOT_BUILD_COMPILER "MS VC++ 6.0" #elif _MSC_VER == 1310 - #define HOTSPOT_BUILD_COMPILER "MS VC++ 7.1" + #define HOTSPOT_BUILD_COMPILER "MS VC++ 7.1 (VS2003)" #elif _MSC_VER == 1400 - #define HOTSPOT_BUILD_COMPILER "MS VC++ 8.0" + #define HOTSPOT_BUILD_COMPILER "MS VC++ 8.0 (VS2005)" + #elif _MSC_VER == 1500 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 9.0 (VS2008)" #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif diff --git a/hotspot/src/share/vm/services/attachListener.cpp b/hotspot/src/share/vm/services/attachListener.cpp index 2361f200a4e..007de28da37 100644 --- a/hotspot/src/share/vm/services/attachListener.cpp +++ b/hotspot/src/share/vm/services/attachListener.cpp @@ -194,7 +194,7 @@ static jint heap_inspection(AttachOperation* op, outputStream* out) { } live_objects_only = strcmp(arg0, "-live") == 0; } - VM_GC_HeapInspection heapop(out, live_objects_only /* request gc */); + VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, true /* need_prologue */); VMThread::execute(&heapop); return JNI_OK; } diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 18bd9f477d7..49e343025ab 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -347,7 +347,6 @@ enum { INITIAL_CLASS_COUNT = 200 }; - // Supports I/O operations on a dump file class DumpWriter : public StackObj { @@ -1303,7 +1302,9 @@ void HeapObjectDumper::do_object(oop o) { // The VM operation that performs the heap dump class VM_HeapDumper : public VM_GC_Operation { private: - DumpWriter* _writer; + static VM_HeapDumper* _global_dumper; + static DumpWriter* _global_writer; + DumpWriter* _local_writer; bool _gc_before_heap_dump; bool _is_segmented_dump; jlong _dump_start; @@ -1311,8 +1312,20 @@ class VM_HeapDumper : public VM_GC_Operation { ThreadStackTrace** _stack_traces; int _num_threads; - // accessors - DumpWriter* writer() const { return _writer; } + // accessors and setters + static VM_HeapDumper* dumper() { assert(_global_dumper != NULL, "Error"); return _global_dumper; } + static DumpWriter* writer() { assert(_global_writer != NULL, "Error"); return _global_writer; } + void set_global_dumper() { + assert(_global_dumper == NULL, "Error"); + _global_dumper = this; + } + void set_global_writer() { + assert(_global_writer == NULL, "Error"); + _global_writer = _local_writer; + } + void clear_global_dumper() { _global_dumper = NULL; } + void clear_global_writer() { _global_writer = NULL; } + bool is_segmented_dump() const { return _is_segmented_dump; } void set_segmented_dump() { _is_segmented_dump = true; } jlong dump_start() const { return _dump_start; } @@ -1357,7 +1370,7 @@ class VM_HeapDumper : public VM_GC_Operation { VM_GC_Operation(0 /* total collections, dummy, ignored */, 0 /* total full collections, dummy, ignored */, gc_before_heap_dump) { - _writer = writer; + _local_writer = writer; _gc_before_heap_dump = gc_before_heap_dump; _is_segmented_dump = false; _dump_start = (jlong)-1; @@ -1381,6 +1394,9 @@ class VM_HeapDumper : public VM_GC_Operation { void doit(); }; +VM_HeapDumper* VM_HeapDumper::_global_dumper = NULL; +DumpWriter* VM_HeapDumper::_global_writer = NULL; + bool VM_HeapDumper::skip_operation() const { return false; } @@ -1479,31 +1495,28 @@ void HeapObjectDumper::mark_end_of_record() { void VM_HeapDumper::do_load_class(klassOop k) { static u4 class_serial_num = 0; - VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); - DumpWriter* writer = dumper->writer(); - // len of HPROF_LOAD_CLASS record u4 remaining = 2*oopSize + 2*sizeof(u4); // write a HPROF_LOAD_CLASS for the class and each array class do { - DumperSupport::write_header(writer, HPROF_LOAD_CLASS, remaining); + DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining); // class serial number is just a number - writer->write_u4(++class_serial_num); + writer()->write_u4(++class_serial_num); // class ID Klass* klass = Klass::cast(k); - writer->write_classID(klass); + writer()->write_classID(klass); // add the klassOop and class serial number pair - dumper->add_class_serial_number(klass, class_serial_num); + dumper()->add_class_serial_number(klass, class_serial_num); - writer->write_u4(STACK_TRACE_ID); + writer()->write_u4(STACK_TRACE_ID); // class name ID symbolOop name = klass->name(); - writer->write_objectID(name); + writer()->write_objectID(name); // write a LOAD_CLASS record for the array type (if it exists) k = klass->array_klass_or_null(); @@ -1512,17 +1525,13 @@ void VM_HeapDumper::do_load_class(klassOop k) { // writes a HPROF_GC_CLASS_DUMP record for the given class void VM_HeapDumper::do_class_dump(klassOop k) { - VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); - DumpWriter* writer = dumper->writer(); - DumperSupport::dump_class_and_array_classes(writer, k); + DumperSupport::dump_class_and_array_classes(writer(), k); } // writes a HPROF_GC_CLASS_DUMP records for a given basic type // array (and each multi-dimensional array too) void VM_HeapDumper::do_basic_type_array_class_dump(klassOop k) { - VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); - DumpWriter* writer = dumper->writer(); - DumperSupport::dump_basic_type_array_class(writer, k); + DumperSupport::dump_basic_type_array_class(writer(), k); } // Walk the stack of the given thread. @@ -1658,6 +1667,11 @@ void VM_HeapDumper::doit() { ch->ensure_parsability(false); } + // At this point we should be the only dumper active, so + // the following should be safe. + set_global_dumper(); + set_global_writer(); + // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1 size_t used = ch->used(); const char* header; @@ -1667,6 +1681,7 @@ void VM_HeapDumper::doit() { } else { header = "JAVA PROFILE 1.0.1"; } + // header is few bytes long - no chance to overflow int writer()->write_raw((void*)header, (int)strlen(header)); writer()->write_u1(0); // terminator @@ -1723,6 +1738,10 @@ void VM_HeapDumper::doit() { // fixes up the length of the dump record. In the case of a segmented // heap then the HPROF_HEAP_DUMP_END record is also written. end_of_dump(); + + // Now we clear the global variables, so that a future dumper might run. + clear_global_dumper(); + clear_global_writer(); } void VM_HeapDumper::dump_stack_traces() { @@ -1790,7 +1809,12 @@ int HeapDumper::dump(const char* path) { // generate the dump VM_HeapDumper dumper(&writer, _gc_before_heap_dump); - VMThread::execute(&dumper); + if (Thread::current()->is_VM_thread()) { + assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint"); + dumper.doit(); + } else { + VMThread::execute(&dumper); + } // close dump file and record any error that the writer may have encountered writer.close(); @@ -1845,49 +1869,68 @@ void HeapDumper::set_error(char* error) { } } - -// Called by error reporting +// Called by error reporting by a single Java thread outside of a JVM safepoint, +// or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various +// callers are strictly serialized and guaranteed not to interfere below. For more +// general use, however, this method will need modification to prevent +// inteference when updating the static variables base_path and dump_file_seq below. void HeapDumper::dump_heap() { - static char path[JVM_MAXPATHLEN]; + static char base_path[JVM_MAXPATHLEN] = {'\0'}; + static uint dump_file_seq = 0; + char my_path[JVM_MAXPATHLEN] = {'\0'}; // The dump file defaults to java_pid.hprof in the current working // directory. HeapDumpPath= can be used to specify an alternative // dump file name or a directory where dump file is created. - bool use_default_filename = true; - if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') { - path[0] = '\0'; // HeapDumpPath= not specified - } else { - assert(strlen(HeapDumpPath) < sizeof(path), "HeapDumpPath too long"); - strcpy(path, HeapDumpPath); - // check if the path is a directory (must exist) - DIR* dir = os::opendir(path); - if (dir == NULL) { - use_default_filename = false; + if (dump_file_seq == 0) { // first time in, we initialize base_path + bool use_default_filename = true; + if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') { + // HeapDumpPath= not specified } else { - // HeapDumpPath specified a directory. We append a file separator - // (if needed). - os::closedir(dir); - size_t fs_len = strlen(os::file_separator()); - if (strlen(path) >= fs_len) { - char* end = path; - end += (strlen(path) - fs_len); - if (strcmp(end, os::file_separator()) != 0) { - assert(strlen(path) + strlen(os::file_separator()) < sizeof(path), - "HeapDumpPath too long"); - strcat(path, os::file_separator()); + assert(strlen(HeapDumpPath) < sizeof(base_path), "HeapDumpPath too long"); + strcpy(base_path, HeapDumpPath); + // check if the path is a directory (must exist) + DIR* dir = os::opendir(base_path); + if (dir == NULL) { + use_default_filename = false; + } else { + // HeapDumpPath specified a directory. We append a file separator + // (if needed). + os::closedir(dir); + size_t fs_len = strlen(os::file_separator()); + if (strlen(base_path) >= fs_len) { + char* end = base_path; + end += (strlen(base_path) - fs_len); + if (strcmp(end, os::file_separator()) != 0) { + assert(strlen(base_path) + strlen(os::file_separator()) < sizeof(base_path), + "HeapDumpPath too long"); + strcat(base_path, os::file_separator()); + } } } } + // If HeapDumpPath wasn't a file name then we append the default name + if (use_default_filename) { + char fn[32]; + sprintf(fn, "java_pid%d", os::current_process_id()); + assert(strlen(base_path) + strlen(fn) < sizeof(base_path), "HeapDumpPath too long"); + strcat(base_path, fn); + } + assert(strlen(base_path) < sizeof(my_path), "Buffer too small"); + strcpy(my_path, base_path); + } else { + // Append a sequence number id for dumps following the first + char fn[33]; + sprintf(fn, ".%d", dump_file_seq); + assert(strlen(base_path) + strlen(fn) < sizeof(my_path), "HeapDumpPath too long"); + strcpy(my_path, base_path); + strcat(my_path, fn); } - // If HeapDumpPath wasn't a file name then we append the default name - if (use_default_filename) { - char fn[32]; - sprintf(fn, "java_pid%d.hprof", os::current_process_id()); - assert(strlen(path) + strlen(fn) < sizeof(path), "HeapDumpPath too long"); - strcat(path, fn); - } + dump_file_seq++; // increment seq number for next time we dump + assert(strlen(".hprof") + strlen(my_path) < sizeof(my_path), "HeapDumpPath too long"); + strcat(my_path, ".hprof"); HeapDumper dumper(false /* no GC before heap dump */, true /* send to tty */); - dumper.dump(path); + dumper.dump(my_path); } diff --git a/hotspot/src/share/vm/services/heapDumper.hpp b/hotspot/src/share/vm/services/heapDumper.hpp index 247512e0182..d5f70e40ae8 100644 --- a/hotspot/src/share/vm/services/heapDumper.hpp +++ b/hotspot/src/share/vm/services/heapDumper.hpp @@ -53,7 +53,7 @@ class HeapDumper : public StackObj { public: HeapDumper(bool gc_before_heap_dump) : - _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false) { } + _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false) { } HeapDumper(bool gc_before_heap_dump, bool print_to_tty) : _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(print_to_tty) { } diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index f58e546ea13..669afbaeac8 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 0a9b8f2a2f3..757910c17b6 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -881,7 +881,7 @@ inline int log2_intptr(intptr_t x) { i++; p *= 2; } // p = 2^(i+1) && x < p (i.e., 2^i <= x < 2^(i+1)) - // (if p = 0 then overflow occured and i = 31) + // (if p = 0 then overflow occurred and i = 31) return i; } @@ -895,7 +895,7 @@ inline int log2_long(jlong x) { i++; p *= 2; } // p = 2^(i+1) && x < p (i.e., 2^i <= x < 2^(i+1)) - // (if p = 0 then overflow occured and i = 63) + // (if p = 0 then overflow occurred and i = 63) return i; } diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp index 48f2c7e886a..22cabe99f90 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp index 62c8b92e255..7053e8a06d8 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp index 6b4804ec565..2b64dfc4662 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp @@ -153,16 +153,8 @@ const jlong max_jlong = CONST64(0x7fffffffffffffff); //---------------------------------------------------------------------------------------------------- // Miscellaneous -inline int vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) { - // If number of characters written == count, Windows doesn't write a - // terminating NULL, so we do it ourselves. - int ret = _vsnprintf(buf, count, fmt, argptr); - if (count > 0) buf[count-1] = '\0'; - return ret; -} - // Visual Studio 2005 deprecates POSIX names - use ISO C++ names instead -#if _MSC_VER >= 1400 && !defined(_WIN64) +#if _MSC_VER >= 1400 #define open _open #define close _close #define read _read @@ -180,6 +172,17 @@ inline int vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) { #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union (needed in windows.h) #pragma warning( disable : 4511 ) // copy constructor could not be generated #pragma warning( disable : 4291 ) // no matching operator delete found; memory will not be freed if initialization thows an exception +#if _MSC_VER >= 1400 +#pragma warning( disable : 4996 ) // unsafe string functions. Same as define _CRT_SECURE_NO_WARNINGS/_CRT_SECURE_NO_DEPRICATE +#endif + +inline int vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) { + // If number of characters written == count, Windows doesn't write a + // terminating NULL, so we do it ourselves. + int ret = _vsnprintf(buf, count, fmt, argptr); + if (count > 0) buf[count-1] = '\0'; + return ret; +} // Portability macros #define PRAGMA_INTERFACE diff --git a/hotspot/src/share/vm/utilities/growableArray.cpp b/hotspot/src/share/vm/utilities/growableArray.cpp index eeb259c5317..8ad410249b4 100644 --- a/hotspot/src/share/vm/utilities/growableArray.cpp +++ b/hotspot/src/share/vm/utilities/growableArray.cpp @@ -43,11 +43,13 @@ void GenericGrowableArray::check_nesting() { #endif void* GenericGrowableArray::raw_allocate(int elementSize) { + assert(_max >= 0, "integer overflow"); + size_t byte_size = elementSize * (size_t) _max; if (on_stack()) { - return (void*)resource_allocate_bytes(elementSize * _max); + return (void*)resource_allocate_bytes(byte_size); } else if (on_C_heap()) { - return (void*)AllocateHeap(elementSize * _max, "GrET in " __FILE__); + return (void*)AllocateHeap(byte_size, "GrET in " __FILE__); } else { - return _arena->Amalloc(elementSize * _max); + return _arena->Amalloc(byte_size); } } diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index 65d18802ba2..60bc65e4eaf 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/utilities/taskqueue.cpp b/hotspot/src/share/vm/utilities/taskqueue.cpp index 2b3145813fd..768f9b5580b 100644 --- a/hotspot/src/share/vm/utilities/taskqueue.cpp +++ b/hotspot/src/share/vm/utilities/taskqueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/utilities/taskqueue.hpp b/hotspot/src/share/vm/utilities/taskqueue.hpp index 3a80a814238..6b83bc083f5 100644 --- a/hotspot/src/share/vm/utilities/taskqueue.hpp +++ b/hotspot/src/share/vm/utilities/taskqueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index a4d0cb0baf0..f3f3edc12fc 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -306,7 +306,7 @@ void VMError::report(outputStream* st) { strncpy(buf, file, buflen); if (len + 10 < buflen) { - sprintf(buf + len, ":" SIZE_FORMAT, _lineno); + sprintf(buf + len, ":%d", _lineno); } st->print(" (%s)", buf); } else { @@ -420,7 +420,7 @@ void VMError::report(outputStream* st) { if (fr.sp()) { st->print(", sp=" PTR_FORMAT, fr.sp()); - st->print(", free space=%dk", + st->print(", free space=%" INTPTR_FORMAT "k", ((intptr_t)fr.sp() - (intptr_t)stack_bottom) >> 10); } diff --git a/hotspot/src/share/vm/utilities/vmError.hpp b/hotspot/src/share/vm/utilities/vmError.hpp index 8e618d91462..4a8cc23523d 100644 --- a/hotspot/src/share/vm/utilities/vmError.hpp +++ b/hotspot/src/share/vm/utilities/vmError.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ class VMError : public StackObj { // additional info for VM internal errors const char * _filename; - size_t _lineno; + int _lineno; // used by fatal error handler int _current_step; diff --git a/hotspot/src/share/vm/utilities/workgroup.hpp b/hotspot/src/share/vm/utilities/workgroup.hpp index 45ddc9cbfc2..ebb111e6396 100644 --- a/hotspot/src/share/vm/utilities/workgroup.hpp +++ b/hotspot/src/share/vm/utilities/workgroup.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/test/Makefile b/hotspot/test/Makefile index f78c2d971c6..5fcc877dc5b 100644 --- a/hotspot/test/Makefile +++ b/hotspot/test/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/test/compiler/6378821/Test6378821.java b/hotspot/test/compiler/6378821/Test6378821.java new file mode 100644 index 00000000000..83c52decb41 --- /dev/null +++ b/hotspot/test/compiler/6378821/Test6378821.java @@ -0,0 +1,75 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6378821 + * @summary where available, bitCount() should use POPC on SPARC processors and AMD+10h + * + * @run main/othervm -Xcomp -XX:CompileOnly=Test6378821.fcomp Test6378821 + */ + +public class Test6378821 { + static final int[] ia = new int[] { 0x12345678 }; + static final long[] la = new long[] { 0x12345678abcdefL }; + + public static void main(String [] args) { + // Resolve the class and the method. + Integer.bitCount(1); + Long.bitCount(1); + + sub(ia[0]); + sub(la[0]); + sub(ia); + sub(la); + } + + static void check(int i, int expected, int result) { + if (result != expected) { + throw new InternalError("Wrong population count for " + i + ": " + result + " != " + expected); + } + } + + static void check(long l, int expected, int result) { + if (result != expected) { + throw new InternalError("Wrong population count for " + l + ": " + result + " != " + expected); + } + } + + static void sub(int i) { check(i, fint(i), fcomp(i) ); } + static void sub(int[] ia) { check(ia[0], fint(ia), fcomp(ia)); } + static void sub(long l) { check(l, fint(l), fcomp(l) ); } + static void sub(long[] la) { check(la[0], fint(la), fcomp(la)); } + + static int fint (int i) { return Integer.bitCount(i); } + static int fcomp(int i) { return Integer.bitCount(i); } + + static int fint (int[] ia) { return Integer.bitCount(ia[0]); } + static int fcomp(int[] ia) { return Integer.bitCount(ia[0]); } + + static int fint (long l) { return Long.bitCount(l); } + static int fcomp(long l) { return Long.bitCount(l); } + + static int fint (long[] la) { return Long.bitCount(la[0]); } + static int fcomp(long[] la) { return Long.bitCount(la[0]); } +} diff --git a/hotspot/test/compiler/6636138/Test1.java b/hotspot/test/compiler/6636138/Test1.java new file mode 100644 index 00000000000..e01ab7f1e8d --- /dev/null +++ b/hotspot/test/compiler/6636138/Test1.java @@ -0,0 +1,67 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6636138 + * @summary SuperWord::co_locate_pack(Node_List* p) generates memory graph that leads to memory order violation. + * + * @run main/othervm -server -Xbatch -XX:CompileOnly=Test1.init -XX:+UseSuperword Test1 + */ + +class Test1 { + + public static void init(int src[], int [] dst, int[] ref) { + // initialize the arrays + for (int i =0; i 0; i--){ + int tmp = src[i]; + src[i] = src[i-1]; + src[i-1] = tmp; + } + } + + public static void verify(int src[]) { + for (int i = 0; i < src.length; i++){ + int value = (i-1 + src.length)%src.length; // correct value after shifting + if (src[i] != value) { + System.out.println("Error: src["+i+"] should be "+ value + " instead of " + src[i]); + System.exit(-1); + } + } + } + + public static void test() { + int[] src = new int[10]; + init(src); + shift(src); + verify(src); + } + + public static void main(String[] args) { + for (int i=0; i< 2000; i++) + test(); + } +} diff --git a/hotspot/test/compiler/6757316/Test6757316.java b/hotspot/test/compiler/6757316/Test6757316.java index 2efc5acd84d..c91183e9550 100644 --- a/hotspot/test/compiler/6757316/Test6757316.java +++ b/hotspot/test/compiler/6757316/Test6757316.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/test/compiler/6758234/Test6758234.java b/hotspot/test/compiler/6758234/Test6758234.java index be916a2a191..f1b0a1f137c 100644 --- a/hotspot/test/compiler/6758234/Test6758234.java +++ b/hotspot/test/compiler/6758234/Test6758234.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/test/compiler/6775880/Test.java b/hotspot/test/compiler/6775880/Test.java index a938f9e73c4..925e616cae5 100644 --- a/hotspot/test/compiler/6775880/Test.java +++ b/hotspot/test/compiler/6775880/Test.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/test/compiler/6778657/Test.java b/hotspot/test/compiler/6778657/Test.java index 4fdd33e9386..efb6687425f 100644 --- a/hotspot/test/compiler/6778657/Test.java +++ b/hotspot/test/compiler/6778657/Test.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/test/compiler/6797305/Test6797305.java b/hotspot/test/compiler/6797305/Test6797305.java new file mode 100644 index 00000000000..d23b3cca9bc --- /dev/null +++ b/hotspot/test/compiler/6797305/Test6797305.java @@ -0,0 +1,114 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6797305 + * @summary Add LoadUB and LoadUI opcode class + * + * @run main/othervm -Xcomp -XX:CompileOnly=Test6797305.loadB,Test6797305.loadB2L,Test6797305.loadUB,Test6797305.loadUBmask,Test6797305.loadUB2L,Test6797305.loadS,Test6797305.loadS2L,Test6797305.loadUS,Test6797305.loadUSmask,Test6797305.loadUS2L,Test6797305.loadI,Test6797305.loadI2L,Test6797305.loadUI2L,Test6797305.loadL Test6797305 + */ + +public class Test6797305 { + static final byte[] ba = new byte[] { -1 }; + static final short[] sa = new short[] { -1 }; + static final int[] ia = new int[] { -1 }; + static final long[] la = new long[] { -1 }; + + public static void main(String[] args) + { + long b = loadB(ba); + if (b != -1) + throw new InternalError("loadB failed: " + b + " != " + -1); + + long b2l = loadB2L(ba); + if (b2l != -1L) + throw new InternalError("loadB2L failed: " + b2l + " != " + -1L); + + int ub = loadUB(ba); + if (ub != 0xFF) + throw new InternalError("loadUB failed: " + ub + " != " + 0xFF); + + int ubmask = loadUBmask(ba); + if (ubmask != 0xFE) + throw new InternalError("loadUBmask failed: " + ubmask + " != " + 0xFE); + + long ub2l = loadUB2L(ba); + if (ub2l != 0xFFL) + throw new InternalError("loadUB2L failed: " + ub2l + " != " + 0xFFL); + + int s = loadS(sa); + if (s != -1) + throw new InternalError("loadS failed: " + s + " != " + -1); + + long s2l = loadS2L(sa); + if (s2l != -1L) + throw new InternalError("loadS2L failed: " + s2l + " != " + -1L); + + int us = loadUS(sa); + if (us != 0xFFFF) + throw new InternalError("loadUS failed: " + us + " != " + 0xFFFF); + + int usmask = loadUSmask(sa); + if (usmask != 0xFFFE) + throw new InternalError("loadUBmask failed: " + ubmask + " != " + 0xFFFE); + + long us2l = loadUS2L(sa); + if (us2l != 0xFFFFL) + throw new InternalError("loadUS2L failed: " + us2l + " != " + 0xFFFFL); + + int i = loadI(ia); + if (i != -1) + throw new InternalError("loadI failed: " + i + " != " + -1); + + long i2l = loadI2L(ia); + if (i2l != -1L) + throw new InternalError("loadI2L failed: " + i2l + " != " + -1L); + + long ui2l = loadUI2L(ia); + if (ui2l != 0xFFFFFFFFL) + throw new InternalError("loadUI2L failed: " + ui2l + " != " + 0xFFFFFFFFL); + + long l = loadL(la); + if (l != -1L) + throw new InternalError("loadL failed: " + l + " != " + -1L); + } + + static int loadB (byte[] ba) { return ba[0]; } + static long loadB2L (byte[] ba) { return ba[0]; } + static int loadUB (byte[] ba) { return ba[0] & 0xFF; } + static int loadUBmask(byte[] ba) { return ba[0] & 0xFE; } + static long loadUB2L (byte[] ba) { return ba[0] & 0xFF; } + + static int loadS (short[] sa) { return sa[0]; } + static long loadS2L (short[] sa) { return sa[0]; } + static int loadUS (short[] sa) { return sa[0] & 0xFFFF; } + static int loadUSmask(short[] sa) { return sa[0] & 0xFFFE; } + static long loadUS2L (short[] sa) { return sa[0] & 0xFFFF; } + + static int loadI (int[] ia) { return ia[0]; } + static long loadI2L (int[] ia) { return ia[0]; } + static long loadUI2L (int[] ia) { return ia[0] & 0xFFFFFFFFL; } + + static long loadL (long[] la) { return la[0]; } +} diff --git a/hotspot/test/runtime/6819213/TestBootNativeLibraryPath.java b/hotspot/test/runtime/6819213/TestBootNativeLibraryPath.java new file mode 100644 index 00000000000..dc49db66122 --- /dev/null +++ b/hotspot/test/runtime/6819213/TestBootNativeLibraryPath.java @@ -0,0 +1,133 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test TestBootNativeLibraryPath.java + * @bug 6819213 + * @compile -XDignore.symbol.file TestBootNativeLibraryPath.java + * @summary verify sun.boot.native.library.path is expandable on 32 bit systems + * @run main TestBootNativeLibraryPath + * @author ksrini +*/ + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; + +public class TestBootNativeLibraryPath { + + private static final String TESTFILE = "Test6"; + + static void createTestClass() throws IOException { + FileOutputStream fos = new FileOutputStream(TESTFILE + ".java"); + PrintStream ps = new PrintStream(fos); + ps.println("public class " + TESTFILE + "{"); + ps.println("public static void main(String[] args) {\n"); + ps.println("System.out.println(System.getProperty(\"sun.boot.library.path\"));\n"); + ps.println("}}\n"); + ps.close(); + fos.close(); + + JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); + String javacOpts[] = {TESTFILE + ".java"}; + if (javac.run(null, null, null, javacOpts) != 0) { + throw new RuntimeException("compilation of " + TESTFILE + ".java Failed"); + } + } + + static List doExec(String... args) { + String javaCmd = System.getProperty("java.home") + "/bin/java"; + if (!new File(javaCmd).exists()) { + javaCmd = System.getProperty("java.home") + "/bin/java.exe"; + } + + ArrayList cmds = new ArrayList(); + cmds.add(javaCmd); + for (String x : args) { + cmds.add(x); + } + System.out.println("cmds=" + cmds); + ProcessBuilder pb = new ProcessBuilder(cmds); + + Map env = pb.environment(); + pb.directory(new File(".")); + + List out = new ArrayList(); + try { + pb.redirectErrorStream(true); + Process p = pb.start(); + BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()),8192); + String in = rd.readLine(); + while (in != null) { + out.add(in); + System.out.println(in); + in = rd.readLine(); + } + int retval = p.waitFor(); + p.destroy(); + if (retval != 0) { + throw new RuntimeException("Error: test returned non-zero value"); + } + return out; + } catch (Exception ex) { + ex.printStackTrace(); + throw new RuntimeException(ex.getMessage()); + } + } + + public static void main(String[] args) { + try { + if (!System.getProperty("sun.arch.data.model").equals("32")) { + System.out.println("Warning: test skipped for 64-bit systems\n"); + return; + } + String osname = System.getProperty("os.name"); + if (osname.startsWith("Windows")) { + osname = "Windows"; + } + + createTestClass(); + + // Test a simple path + String libpath = File.pathSeparator + "tmp" + File.pathSeparator + "foobar"; + List processOut = null; + String sunbootlibrarypath = "-Dsun.boot.library.path=" + libpath; + processOut = doExec(sunbootlibrarypath, "-cp", ".", TESTFILE); + if (processOut == null || !processOut.get(0).endsWith(libpath)) { + throw new RuntimeException("Error: did not get expected error string"); + } + } catch (IOException ex) { + throw new RuntimeException("Unexpected error " + ex); + } + } +} diff --git a/jaxp/.hgtags b/jaxp/.hgtags index a5c20cf42ee..5d76cae3784 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -23,3 +23,9 @@ b203df0741af3eb08687bc5eb798bac87363758d jdk7-b44 b2271877894af809b7703767fe8d4e38591a02a2 jdk7-b46 d711ad1954b294957737ea386cfd4d3c05028a36 jdk7-b47 39de90eb4822cafaacc69edd67ab5547e55ae920 jdk7-b48 +5c1f24531903573c1830775432276da567243f9c jdk7-b49 +e8514e2be76d90889ebdb90d627aca2db5c150c6 jdk7-b50 +ae890d80d5dffcd4dc77a1f17d768e192d1852c7 jdk7-b51 +69ad87dc25cbcaaaded4727199395ad0c78bc427 jdk7-b52 +e8837366d3fd72f7c7a47ebfdbd5106c16156f12 jdk7-b53 +946a9f0c493261fa6a010dc33e61b9b535ba80c1 jdk7-b54 diff --git a/jaxp/make/Makefile b/jaxp/make/Makefile index 1f742fd849d..e8ea3347b31 100644 --- a/jaxp/make/Makefile +++ b/jaxp/make/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/jaxp/make/jprt.config b/jaxp/make/jprt.config deleted file mode 100644 index 90200b1bc41..00000000000 --- a/jaxp/make/jprt.config +++ /dev/null @@ -1,241 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# Windows Only: -# PATH -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# -# Output environment variables: -# PATH -# Windows Only: -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Add basic solaris system paths - path4sdk=/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Add basic paths - path4sdk=/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk="${antbindir};${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 0229b71ed66..82117eae928 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -23,3 +23,9 @@ dea7753d713936c5b6fd942a91811b0676537fd0 jdk7-b45 af4a3eeb7812a5d09a241c50b51b3c648a9d45c1 jdk7-b46 223011570edbd49bb0fe51cdeb2089f95d305267 jdk7-b47 01e5dd31d0c10a2db3d50db346905d2d3db45e88 jdk7-b48 +18ca864890f3d4ed942ecbffb78c936a57759921 jdk7-b49 +5be52db581f1ea91ab6e0eb34ba7f439125bfb16 jdk7-b50 +41a66a42791ba90bff489af72cbfea71be9b40a5 jdk7-b51 +e646890d18b770f625f14ed4ad5c50554d8d3d8b jdk7-b52 +b250218eb2e534384667ec73e3713e684667fd4c jdk7-b53 +50ea00dc5f143fe00025233e704903c37f8464aa jdk7-b54 diff --git a/jaxws/make/Makefile b/jaxws/make/Makefile index e3019a3d45e..56696720183 100644 --- a/jaxws/make/Makefile +++ b/jaxws/make/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/jaxws/make/jprt.config b/jaxws/make/jprt.config deleted file mode 100644 index 90200b1bc41..00000000000 --- a/jaxws/make/jprt.config +++ /dev/null @@ -1,241 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# Windows Only: -# PATH -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# -# Output environment variables: -# PATH -# Windows Only: -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Add basic solaris system paths - path4sdk=/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Add basic paths - path4sdk=/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk="${antbindir};${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - diff --git a/jdk/.hgtags b/jdk/.hgtags index 95051d6a0d4..f3ad419b9a7 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -23,3 +23,10 @@ d8eb2738db6b148911177d9bcfe888109b7f2f71 jdk7-b44 4b03e27a44090d1f646af28dc58f9ead827e24c7 jdk7-b46 b4ac413b1f129eeef0acab3f31081c1b7dfe3b27 jdk7-b47 5fbd9ea7def17186693b6f7099b5d0dc73903eee jdk7-b48 +8311105ea7a3db7bcbcb2b696459127c7f2297a4 jdk7-b49 +58ba2cd5a25053684ec53205d95edeeaa0006f13 jdk7-b50 +fea0898259ae41c73620b1815aa48f036216155c jdk7-b51 +bcbeadb4a5d759b29e876ee2c83401e91ff22f60 jdk7-b52 +a2033addca678f9e4c0d92ffa1e389171cc9321d jdk7-b53 +d1c43d1f5676a24ba86221ac7cad5694f3a9afda jdk7-b54 +522bb5aa17e0c0cff00b1ed7d1b51bc4db2cfef9 jdk7-b55 diff --git a/jdk/THIRD_PARTY_README b/jdk/THIRD_PARTY_README index 9f4d7e5087a..690890548f2 100644 --- a/jdk/THIRD_PARTY_README +++ b/jdk/THIRD_PARTY_README @@ -61,6 +61,28 @@ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +%% This notice is provided with respect to littlecms, which may be included with this software: + +Little cms +Copyright (C) 1998-2004 Marti Maria + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. %% This notice is provided with respect to zlib 1.1.3, which may be included with this software: Acknowledgments: @@ -115,16 +137,6 @@ COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQ The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders. ____________________________________ This formulation of W3C's notice and license became active on August 14 1998 so as to improve compatibility with GPL. This version ensures that W3C software licensing terms are no more restrictive than GPL and consequently W3C software may be distributed in GPL packages. See the older formulation for the policy prior to this date. Please see our Copyright FAQ for common questions about using materials from our site, including specific terms and conditions for packages like libwww, Amaya, and Jigsaw. Other questions about this notice can be directed to site-policy@w3.org. -  -%% This notice is provided with respect to jscheme.jar, which may be included with this software: -Software License Agreement -Copyright © 1998-2002 by Peter Norvig. -Permission is granted to anyone to use this software, in source or object code form, on any computer system, and to modify, compile, decompile, run, and redistribute it to anyone else, subject to the following restrictions: -1.The author makes no warranty of any kind, either expressed or implied, about the suitability of this software for any purpose. -2.The author accepts no liability of any kind for damages or other consequences of the use of this software, even if they arise from defects in the software. -3.The origin of this software must not be misrepresented, either by explicit claim or by omission. -4.Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. Altered versions may be distributed in packages under other licenses (such as the GNU license). -If you find this software useful, it would be nice if you let me (peter@norvig.com) know about it, and nicer still if you send me modifications that you are willing to share. However, you are not required to do so. %% This notice is provided with respect to PC/SC Lite for Suse Linux v. 1.1.1, which may be included with this software: diff --git a/jdk/make/com/sun/jmx/Makefile b/jdk/make/com/sun/jmx/Makefile index c529dd4be31..81470f0befe 100644 --- a/jdk/make/com/sun/jmx/Makefile +++ b/jdk/make/com/sun/jmx/Makefile @@ -41,7 +41,15 @@ include $(BUILDDIR)/common/Defs.gmk # Note : some targets are double colon rules and some single colon rules # within common included gmk files : that is why the following for loop # has been duplicated. -SUBDIRS = snmp + +# When building the openjdk, build snmp only if importing binary plugs, +ifdef OPENJDK + ifeq ($(IMPORT_BINARY_PLUGS),true) + SUBDIRS = snmp + endif +else + SUBDIRS = snmp +endif all build: $(SUBDIRS-loop) diff --git a/jdk/make/common/Defs-linux.gmk b/jdk/make/common/Defs-linux.gmk index 28d58376fe2..591b6ccae31 100644 --- a/jdk/make/common/Defs-linux.gmk +++ b/jdk/make/common/Defs-linux.gmk @@ -94,6 +94,9 @@ ifndef OPTIMIZATION_LEVEL OPTIMIZATION_LEVEL = LOWER endif endif +ifndef FASTDEBUG_OPTIMIZATION_LEVEL + FASTDEBUG_OPTIMIZATION_LEVEL = LOWER +endif CC_OPT/NONE = CC_OPT/LOWER = -O2 @@ -116,6 +119,14 @@ LDFLAGS_COMMON_sparc += -m32 -mcpu=v9 CFLAGS_REQUIRED = $(CFLAGS_REQUIRED_$(ARCH)) LDFLAGS_COMMON += $(LDFLAGS_COMMON_$(ARCH)) +# If this is a --hash-style=gnu system, use --hash-style=both +# The gnu .hash section won't work on some Linux systems like SuSE 10. +_HAS_HASH_STYLE_GNU:=$(shell $(CC) -dumpspecs | $(GREP) -- '--hash-style=gnu') +ifneq ($(_HAS_HASH_STYLE_GNU),) + LDFLAGS_HASH_STYLE = -Wl,--hash-style=both +endif +LDFLAGS_COMMON += $(LDFLAGS_HASH_STYLE) + # # Selection of warning messages # @@ -165,8 +176,8 @@ CXXFLAGS_COMMON += $(CFLAGS_REQUIRED) # FASTDEBUG: Optimize the code in the -g versions, gives us a faster debug java ifeq ($(FASTDEBUG), true) - CFLAGS_DBG += $(CC_OPT/LOWER) - CXXFLAGS_DBG += $(CC_OPT/LOWER) + CFLAGS_DBG += $(CC_OPT/$(FASTDEBUG_OPTIMIZATION_LEVEL)) + CXXFLAGS_DBG += $(CC_OPT/$(FASTDEBUG_OPTIMIZATION_LEVEL)) endif CPPFLAGS_COMMON = -D$(ARCH) -DARCH='"$(ARCH)"' -DLINUX $(VERSION_DEFINES) \ diff --git a/jdk/make/common/Defs-solaris.gmk b/jdk/make/common/Defs-solaris.gmk index 9b5cc8b721b..5b1d237caae 100644 --- a/jdk/make/common/Defs-solaris.gmk +++ b/jdk/make/common/Defs-solaris.gmk @@ -93,6 +93,9 @@ ifndef OPTIMIZATION_LEVEL OPTIMIZATION_LEVEL = LOWER endif endif +ifndef FASTDEBUG_OPTIMIZATION_LEVEL + FASTDEBUG_OPTIMIZATION_LEVEL = LOWER +endif # # If -Xa is in CFLAGS_COMMON it will end up ahead of $(CC_OPT) for the @@ -143,8 +146,8 @@ endif # Performance/size of files should be about the same, maybe smaller. # ifeq ($(FASTDEBUG), true) - CFLAGS_DEBUG_OPTION = -g $(CC_OPT/LOWER) - CXXFLAGS_DEBUG_OPTION = -g0 $(CXX_OPT/LOWER) + CFLAGS_DEBUG_OPTION = -g $(CC_OPT/$(FASTDEBUG_OPTIMIZATION_LEVEL)) + CXXFLAGS_DEBUG_OPTION = -g0 $(CXX_OPT/$(FASTDEBUG_OPTIMIZATION_LEVEL)) endif CFLAGS_COMMON = -L$(OBJDIR) diff --git a/jdk/make/common/Defs-windows.gmk b/jdk/make/common/Defs-windows.gmk index 7b178497e12..00b8ea71e2a 100644 --- a/jdk/make/common/Defs-windows.gmk +++ b/jdk/make/common/Defs-windows.gmk @@ -70,7 +70,6 @@ PLATFORM_INCLUDE = $(INCLUDEDIR)/$(PLATFORM_INCLUDE_NAME) # not to be REBASEd, see deploy/make/common/Release.gmk. # msvcrt.dll, msvcrnn.dll [msvcr71 or msvcr80 or msvcr90] : Microsoft runtimes MS_RUNTIME_LIBRARIES = msvcrt.dll -MSVCRNN_DLL = ifeq ($(ARCH_DATA_MODEL), 32) ifeq ($(COMPILER_VERSION), VS2003) MSVCRNN_DLL = msvcr71.dll @@ -89,6 +88,13 @@ ifeq ($(ARCH_DATA_MODEL), 32) endif endif +ifeq ($(ARCH_DATA_MODEL), 64) + ifeq ($(COMPILER_VERSION), VS2008) + MSVCRNN_DLL = msvcr90.dll + MSVCPNN_DLL = msvcp90.dll + MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) + endif +endif EXTRA_LFLAGS += /LIBPATH:$(DXSDK_LIB_PATH) @@ -105,6 +111,9 @@ ifndef OPTIMIZATION_LEVEL OPTIMIZATION_LEVEL = LOWER endif endif +ifndef FASTDEBUG_OPTIMIZATION_LEVEL + FASTDEBUG_OPTIMIZATION_LEVEL = LOWER +endif ifeq ($(CC_VERSION),msvc) # Visual Studio .NET 2003 or VS2003 compiler option definitions: @@ -344,17 +353,12 @@ CFLAGS_COMMON += -Fd$(OBJDIR)/$(basename $(@F)).pdb -Fm$(OBJDIR)/$(basename $(@F COMPILER_WARNINGS_TO_IGNORE = 4800 CFLAGS_COMMON += $(COMPILER_WARNINGS_TO_IGNORE:%=-wd%) -# -# Add warnings and extra on 64bit issues -# -ifeq ($(ARCH_DATA_MODEL), 64) - CFLAGS_COMMON += -Wp64 -endif - # # Treat compiler warnings as errors, if requested # CFLAGS_COMMON += -W$(COMPILER_WARNING_LEVEL) +# Turn off security warnings about using the standard C library function strcpy +CFLAGS_COMMON += -D _CRT_SECURE_NO_DEPRECATE ifeq ($(COMPILER_WARNINGS_FATAL),true) CFLAGS_COMMON += -WX endif @@ -398,16 +402,7 @@ ifeq ($(ARCH), ia64) # SA will never be supported here. INCLUDE_SA = false else - # Hopefully, SA will be supported here one of these days, - # and these will be changed to true. Until then, - # to build SA on windows, do a control build with - # BUILD_WIN_SA=1 - # on the make command. - ifdef BUILD_WIN_SA - INCLUDE_SA = true - else - INCLUDE_SA = false - endif + INCLUDE_SA = true endif # Settings for the VERSIONINFO tap on windows. diff --git a/jdk/make/common/Defs.gmk b/jdk/make/common/Defs.gmk index 33eedad16a4..d959123fdae 100644 --- a/jdk/make/common/Defs.gmk +++ b/jdk/make/common/Defs.gmk @@ -145,6 +145,11 @@ endif # 2. ALT_BINARY_PLUGS_PATH overrides all locations of classes and libraries # 3. ALT_BUILD_BINARY_PLUGS_PATH is used to find a ALT_BINARY_PLUGS_PATH # 4. ALT_CLOSED_JDK_IMPORT_PATH is used to locate classes and libraries +# Note: If any of the ALT_ variables are modified here, it is assumed +# that the build should be done with IMPORT_BINARY_PLUGS=true as +# well. Otherwise the default will be IMPORT_BINARY_PLUGS=false. +# Lastly, setting IMPORT_BINARY_PLUGS=false on the command line +# will override this logic, and plugs will not be imported. # # Always needed, defines the name of the imported/exported jarfile @@ -155,9 +160,11 @@ ifdef OPENJDK CLOSED_JDK_IMPORT_PATH = $(ALT_CLOSED_JDK_IMPORT_PATH) BINARY_PLUGS_PATH = $(CLOSED_JDK_IMPORT_PATH) BINARY_PLUGS_JARFILE = $(CLOSED_JDK_IMPORT_PATH)/jre/lib/rt.jar + IMPORT_BINARY_PLUGS=true endif ifdef ALT_BUILD_BINARY_PLUGS_PATH BUILD_BINARY_PLUGS_PATH = $(ALT_BUILD_BINARY_PLUGS_PATH) + IMPORT_BINARY_PLUGS=true else BUILD_BINARY_PLUGS_PATH = $(SLASH_JAVA)/re/jdk/$(JDK_VERSION)/promoted/latest/openjdk/binaryplugs endif @@ -166,9 +173,11 @@ ifdef OPENJDK ifdef ALT_BINARY_PLUGS_PATH BINARY_PLUGS_PATH = $(ALT_BINARY_PLUGS_PATH) BINARY_PLUGS_JARFILE = $(BINARY_PLUGS_PATH)/jre/lib/$(BINARY_PLUGS_JARNAME) + IMPORT_BINARY_PLUGS=true endif ifdef ALT_BINARY_PLUGS_JARFILE BINARY_PLUGS_JARFILE = $(ALT_BINARY_PLUGS_JARFILE) + IMPORT_BINARY_PLUGS=true endif endif # OPENJDK diff --git a/jdk/make/common/shared/Compiler-gcc.gmk b/jdk/make/common/shared/Compiler-gcc.gmk index 27501956368..29b8c0a80a4 100644 --- a/jdk/make/common/shared/Compiler-gcc.gmk +++ b/jdk/make/common/shared/Compiler-gcc.gmk @@ -27,8 +27,6 @@ # GCC Compiler settings # -COMPILER_NAME=GCC - ifeq ($(PLATFORM), windows) # Settings specific to Windows, pretty stale, hasn't been used @@ -68,24 +66,6 @@ ifeq ($(PLATFORM), linux) else CXX = $(COMPILER_PATH)g++ endif - ifneq ("$(findstring sparc,$(ARCH))", "") - # sparc or sparcv9 - REQUIRED_CC_VER = 4.0 - REQUIRED_GCC_VER = 4.0.* - else - REQUIRED_CC_VER = 3.2 - ifeq ($(ARCH_DATA_MODEL), 32) - REQUIRED_GCC_VER = 3.2.1* - REQUIRED_GCC_VER_INT = 3.2.1-7a - else - ifeq ($(ARCH), amd64) - REQUIRED_GCC_VER = 3.2.* - endif - ifeq ($(ARCH), ia64) - REQUIRED_GCC_VER = 2.9[56789].* - endif - endif - endif # Option used to create a shared library SHARED_LIBRARY_FLAG = -shared -mimpure-text SUN_COMP_VER := $(shell $(CC) --verbose 2>&1 ) @@ -98,21 +78,17 @@ ifeq ($(PLATFORM), solaris) CC = $(COMPILER_PATH)gcc CPP = $(COMPILER_PATH)gcc -E CXX = $(COMPILER_PATH)g++ - REQUIRED_CC_VER = 3.2 # Option used to create a shared library SHARED_LIBRARY_FLAG = -G - # But gcc is still needed no matter what on 32bit - ifeq ($(ARCH_DATA_MODEL), 32) - REQUIRED_GCC_VER = 2.95 - GCC =$(GCC_COMPILER_PATH)gcc - _GCC_VER :=$(shell $(GCC) -dumpversion 2>&1 ) - GCC_VER :=$(call GetVersion,"$(_GCC_VER)") - endif - + endif # Get gcc version _CC_VER :=$(shell $(CC) -dumpversion 2>&1 ) CC_VER :=$(call GetVersion,"$(_CC_VER)") +# Name of compiler +COMPILER_NAME = GCC$(call MajorVersion,$(CC_VER)) +COMPILER_VERSION = $(COMPILER_NAME) + diff --git a/jdk/make/common/shared/Compiler-msvc.gmk b/jdk/make/common/shared/Compiler-msvc.gmk index d23529f3935..ade430ad9ea 100644 --- a/jdk/make/common/shared/Compiler-msvc.gmk +++ b/jdk/make/common/shared/Compiler-msvc.gmk @@ -41,8 +41,6 @@ ifeq ($(PLATFORM), windows) # Fill in unknown values COMPILER_NAME=Unknown MSVC Compiler COMPILER_VERSION= - REQUIRED_CC_VER= - REQUIRED_LINK_VER= # unset any GNU Make settings of MFLAGS and MAKEFLAGS which may mess up nmake NMAKE = MFLAGS= MAKEFLAGS= $(COMPILER_PATH)nmake -nologo @@ -56,8 +54,6 @@ ifeq ($(PLATFORM), windows) CC_MAJORVER :=$(call MajorVersion,$(CC_VER)) ifeq ($(CC_MAJORVER), 13) # This should be: CC_VER=13.10.3077 LINK_VER=7.10.3077 - REQUIRED_CC_VER = 13.10.3077 - REQUIRED_LINK_VER = 7.10.3077 COMPILER_NAME=Visual Studio .NET 2003 Professional C++ COMPILER_VERSION=VS2003 REBASE = $(COMPILER_PATH)../../Common7/Tools/Bin/rebase @@ -67,9 +63,6 @@ ifeq ($(PLATFORM), windows) endif endif ifeq ($(CC_MAJORVER), 14) - # This should be: CC_VER=14.00.50727.42 LINK_VER=8.00.50727.42 - REQUIRED_CC_VER = 14.00.50727.42 - REQUIRED_LINK_VER = 8.00.50727.42 COMPILER_NAME=Visual Studio 8 COMPILER_VERSION=VS2005 REBASE = $(COMPILER_PATH)../../Common8/Tools/Bin/rebase @@ -80,9 +73,6 @@ ifeq ($(PLATFORM), windows) endif endif ifeq ($(CC_MAJORVER), 15) - # This should be: CC_VER=15.00.21022.08 LINK_VER=9.00.21022.08 - REQUIRED_CC_VER = 15.00.21022.08 - REQUIRED_LINK_VER = 9.00.21022.08 COMPILER_NAME=Visual Studio 9 COMPILER_VERSION=VS2008 #rebase and midl moved out of Visual Studio into the SDK: @@ -99,14 +89,6 @@ ifeq ($(PLATFORM), windows) CC_MAJORVER :=$(call MajorVersion,$(CC_VER)) CC_MINORVER :=$(call MinorVersion,$(CC_VER)) CC_MICROVER :=$(call MicroVersion,$(CC_VER)) - ifeq ($(ARCH), ia64) - REQUIRED_CC_VER = 13.00.9337.7 - REQUIRED_LINK_VER = 7.00.9337.7 - endif - ifeq ($(ARCH), amd64) - REQUIRED_CC_VER = 14.00.40310.41 - REQUIRED_LINK_VER = 8.00.40310.39 - endif ifeq ($(CC_MAJORVER), 13) ifeq ($(ARCH), ia64) # This should be: CC_VER=13.00.9337.7 LINK_VER=7.00.9337.7 @@ -130,6 +112,12 @@ ifeq ($(PLATFORM), windows) endif endif endif + ifeq ($(CC_MAJORVER), 15) + COMPILER_NAME=Microsoft Windows SDK with Visual Studio 9 (6001.18000.367) + COMPILER_VERSION=VS2008 + RC = $(MSSDK61)/Bin/X64/rc.exe + MT = $(MSSDK61)/Bin/X64/mt.exe + endif # This will cause problems if ALT_COMPILER_PATH is defined to "" # which is a directive to use the PATH. REBASE = $(COMPILER_PATH)../REBASE diff --git a/jdk/make/common/shared/Compiler-sun.gmk b/jdk/make/common/shared/Compiler-sun.gmk index b3c4e2a90b1..8bbd16f21f8 100644 --- a/jdk/make/common/shared/Compiler-sun.gmk +++ b/jdk/make/common/shared/Compiler-sun.gmk @@ -27,32 +27,20 @@ # Sun Studio Compiler settings # -COMPILER_NAME=Sun Studio - # Sun Studio Compiler settings specific to Solaris ifeq ($(PLATFORM), solaris) - COMPILER_VERSION=SS12 - REQUIRED_CC_VER=5.9 CC = $(COMPILER_PATH)cc CPP = $(COMPILER_PATH)cc -E CXX = $(COMPILER_PATH)CC LINT = $(COMPILER_PATH)lint # Option used to create a shared library SHARED_LIBRARY_FLAG = -G - # But gcc is still needed no matter what on 32bit - ifeq ($(ARCH_DATA_MODEL), 32) - REQUIRED_GCC_VER = 2.95 - GCC =$(GCC_COMPILER_PATH)gcc - _GCC_VER :=$(shell $(GCC) -dumpversion 2>&1 ) - GCC_VER :=$(call GetVersion,"$(_GCC_VER)") - endif + GCC =$(GCC_COMPILER_PATH)gcc endif # Sun Studio Compiler settings specific to Linux ifeq ($(PLATFORM), linux) # This has not been tested - COMPILER_VERSION=SS12 - REQUIRED_CC_VER=5.9 CC = $(COMPILER_PATH)cc CPP = $(COMPILER_PATH)cc -E CXX = $(COMPILER_PATH)CC @@ -74,6 +62,18 @@ endif _CC_VER :=$(shell $(CC) -V 2>&1 | $(HEAD) -n 1) CC_VER :=$(call GetVersion,"$(_CC_VER)") +# Name of compilers being used +COMPILER_VERSION-5.7 = SS10 +COMPILER_NAME-5.7 = Sun Studio 10 +COMPILER_VERSION-5.8 = SS11 +COMPILER_NAME-5.8 = Sun Studio 11 +COMPILER_VERSION-5.9 = SS12 +COMPILER_NAME-5.9 = Sun Studio 12 +COMPILER_VERSION-5.10 = SS13 +COMPILER_NAME-5.10 = Sun Studio 13 +COMPILER_VERSION = $(COMPILER_VERSION-$(CC_VER)) +COMPILER_NAME = $(COMPILER_NAME-$(CC_VER)) + # Arch specific settings (determines type of .o files and instruction set) # Starting in SS12 (5.9), the arch options changed. # The assembler /usr/ccs/bin/as wants older SS11 (5.8) style options. diff --git a/jdk/make/common/shared/Defs-java.gmk b/jdk/make/common/shared/Defs-java.gmk index 9bfb96da453..78f87294fbe 100644 --- a/jdk/make/common/shared/Defs-java.gmk +++ b/jdk/make/common/shared/Defs-java.gmk @@ -59,7 +59,15 @@ else ADD_CLIENT_VM_OPTION = true endif endif -JAVA_JVM_FLAGS = + +# Options for hotspot to turn off printing of options with fastdebug version +# and creating the hotspot.log file. +JAVA_HOTSPOT_DISABLE_PRINT_VMOPTIONS = \ + -XX:-PrintVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-LogVMOutput + +# JVM options +JAVA_JVM_FLAGS = $(JAVA_HOTSPOT_DISABLE_PRINT_VMOPTIONS) + ifeq ($(ADD_CLIENT_VM_OPTION), true) JAVA_JVM_FLAGS += -client endif @@ -129,6 +137,9 @@ JAVACFLAGS += $(OTHER_JAVACFLAGS) # Needed for javah JAVAHFLAGS += -bootclasspath $(CLASSBINDIR) +# Needed for JAVADOC and BOOT_JAVACFLAGS +NO_PROPRIETARY_API_WARNINGS = -XDignore.symbol.file=true + # Langtools ifdef LANGTOOLS_DIST JAVAC_JAR = $(LANGTOOLS_DIST)/bootstrap/lib/javac.jar @@ -192,6 +203,8 @@ endif BOOT_JAVACFLAGS += -encoding ascii BOOT_JAR_JFLAGS += $(JAR_JFLAGS) +BOOT_JAVACFLAGS += $(NO_PROPRIETARY_API_WARNINGS) + BOOT_JAVA_CMD = $(BOOTDIR)/bin/java $(JAVA_TOOLS_FLAGS) BOOT_JAVAC_CMD = $(BOOTDIR)/bin/javac $(JAVAC_JVM_FLAGS) $(BOOT_JAVACFLAGS) BOOT_JAR_CMD = $(BOOTDIR)/bin/jar diff --git a/jdk/make/common/shared/Defs-solaris.gmk b/jdk/make/common/shared/Defs-solaris.gmk index b3630bac34b..8da2d61dc2c 100644 --- a/jdk/make/common/shared/Defs-solaris.gmk +++ b/jdk/make/common/shared/Defs-solaris.gmk @@ -91,14 +91,14 @@ endif ifneq "$(origin ALT_COMPILER_PATH)" "undefined" COMPILER_PATH :=$(call PrefixPath,$(ALT_COMPILER_PATH)) else - # Careful here, COMPILER_VERSION may not be defined yet (see Compiler.gmk) + # Careful here, REQUIRED_COMPILER_VERSION may not be defined yet (see Defs-versions.gmk) # If the place where we keep a set of Sun Studio compilers doesn't exist, # try and use /opt/SUNWspro, the default location for the SS compilers. # (DirExists checks for this path twice, an automount double check) _SUNSTUDIO_SET_ROOT=$(JDK_DEVTOOLS_DIR)/$(ARCH_FAMILY)/SUNWspro SUNSTUDIO_SET_ROOT:=$(call DirExists,$(_SUNSTUDIO_SET_ROOT),$(_SUNSTUDIO_SET_ROOT),) ifneq ($(SUNSTUDIO_SET_ROOT),) - COMPILER_PATH =$(SUNSTUDIO_SET_ROOT)/$(COMPILER_VERSION)/bin/ + COMPILER_PATH =$(SUNSTUDIO_SET_ROOT)/$(REQUIRED_COMPILER_VERSION)/bin/ else COMPILER_PATH =/opt/SUNWspro/bin/ endif diff --git a/jdk/make/common/shared/Defs-versions.gmk b/jdk/make/common/shared/Defs-versions.gmk new file mode 100644 index 00000000000..0fc1bab4617 --- /dev/null +++ b/jdk/make/common/shared/Defs-versions.gmk @@ -0,0 +1,199 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# WARNING: This file is shared with other workspaces. +# + +# This file needs these set: CC_VERSION, PLATFORM, ARCH_FAMILY, and ARCH_DATA_MODEL. + +########################################################################## +# +# List of JDK official minimum, expected, or required versions: +# +# REQUIRED_ALSA_VERSION +# Linux only: The ALSA sound library version expected. +# +# REQUIRED_ANT_VER +# The minimum 'ant' version. +# +# REQUIRED_BOOT_VER +# The minimum boot jdk version. +# +# REQUIRED_CC_VER +# The primary C compiler version expected. +# +# REQUIRED_COMPILER_NAME +# The long descriptive name of the compiler we should use +# +# REQUIRED_COMPILER_VERSION +# The one word name that identifies the compilers being used. +# +# REQUIRED_CYGWIN_VER +# Windows only: If CYGWIN is used, the minimum CYGWIN version. +# +# REQUIRED_DXSDK_VER +# Windows only: The version of DirectX SDK expected. +# +# REQUIRED_FREE_SPACE +# The minimum disk space needed as determined by running 'du -sk' on a fully +# built workspace. +# +# REQUIRED_FREETYPE_VERSION +# If we are using freetype, the freetype version expected. +# +# REQUIRED_GCC_VER +# Solaris and Linux only. The required version of gcc/g++ for the plugin. +# +# REQUIRED_LINK_VER +# Windows only: The version of link.exe expected. +# +# REQUIRED_MAKE_VER +# The minimum version of GNU make. +# +# REQUIRED_MKS_VER +# Windows only: If MKS used instead of CYGWIN, the minimum version of MKS. +# +# REQUIRED_OS_VARIANT_NAME +# The OS variation name required. +# Solaris: Solaris or OpenSolaris +# Windows: Windows2000, WindowsXP, Windows2003, etc. +# Linux: Fedora, RedHat, SuSE, Ubuntu, etc. +# +# REQUIRED_OS_VARIANT_VERSION +# The version number associated with the above OS variant name. +# Solaris: output of uname -r +# Windows: 5.0 for Windows2000, 5.1 for WindowsXP, 5.2 for Windows2003, etc. +# Linux: number for the variant, e.g. 9 for Fedora 9 +# +# REQUIRED_OS_VERSION +# The formal OS version number. +# Solaris & Windows: same as REQUIRED_OS_VARIANT_VERSION +# Linux: the kernel version, or output of uname -r +# +# REQUIRED_UNZIP_VER +# The minimum version of unzip. +# +# REQUIRED_ZIP_VER +# The minimum version of unzip. +# +########### +# +# Differences in the build platform from these versions may trigger warnings +# messages during the sanity checking when building the JDK. +# +# When building the OpenJDK most of these required or expected versions are +# ignored or allowed to vary widely to accomodate the many build situations +# of the OpenJDK. +# +########################################################################## + +# Solaris specific +ifeq ($(PLATFORM), solaris) + REQUIRED_OS_VERSION = 5.10 + REQUIRED_OS_VARIANT_NAME = Solaris + REQUIRED_OS_VARIANT_VERSION = $(REQUIRED_OS_VERSION) + ifeq ($(ARCH_FAMILY), sparc) + REQUIRED_FREE_SPACE = 1300000 + else + REQUIRED_FREE_SPACE = 1040000 + endif + REQUIRED_COMPILER_NAME = Sun Studio 12 + REQUIRED_COMPILER_VERSION = SS12 + ifeq ($(CC_VERSION),sun) + REQUIRED_CC_VER = 5.9 + endif + ifeq ($(CC_VERSION),gcc) + REQUIRED_CC_VER = 3.4.3 + endif + REQUIRED_GCC_VER = 2.95.2 +endif + +# Linux specific +ifeq ($(PLATFORM), linux) + REQUIRED_OS_VERSION = 2.6 + REQUIRED_OS_VARIANT_NAME = Fedora + REQUIRED_OS_VARIANT_VERSION = 9 + REQUIRED_FREE_SPACE = 1460000 + REQUIRED_ALSA_VERSION = 0.9.1 + REQUIRED_COMPILER_NAME = GCC4 + REQUIRED_COMPILER_VERSION = GCC4 + REQUIRED_GCC_VER = 2.95 + ifeq ($(CC_VERSION),gcc) + REQUIRED_CC_VER = 4.3.0 + endif + ifeq ($(CC_VERSION),sun) + REQUIRED_CC_VER = 5.9 + endif +endif + +# Windows specific +ifeq ($(PLATFORM), windows) + ifeq ($(ARCH_DATA_MODEL),64) + REQUIRED_OS_VERSION = 5.2 + REQUIRED_OS_VARIANT_NAME = Windows2003 + else + REQUIRED_OS_VERSION = 5.1 + REQUIRED_OS_VARIANT_NAME = WindowsXP + endif + REQUIRED_OS_VARIANT_VERSION = $(REQUIRED_OS_VERSION) + REQUIRED_CYGWIN_VER = 4.0 + REQUIRED_MKS_VER = 6.1 + REQUIRED_FREE_SPACE = 500000 + REQUIRED_DXSDK_VER = 0x0900 + ifeq ($(CC_VERSION),msvc) + ifeq ($(ARCH_DATA_MODEL), 32) + REQUIRED_COMPILER_NAME = Visual Studio 9 + REQUIRED_COMPILER_VERSION = VS2008 + REQUIRED_CC_VER = 15.00.21022.08 + REQUIRED_LINK_VER = 9.00.21022.08 + else + ifeq ($(ARCH), ia64) + REQUIRED_COMPILER_NAME = Microsoft Platform SDK - November 2001 Edition + REQUIRED_COMPILER_VERSION = VS2003 + REQUIRED_CC_VER = 13.00.9337.7 + REQUIRED_LINK_VER = 7.00.9337.7 + endif + ifeq ($(ARCH), amd64) + REQUIRED_COMPILER_NAME = Microsoft Windows SDK with Visual Studio 9 (6001.18000.367) + REQUIRED_COMPILER_VERSION = VS2008 + REQUIRED_CC_VER = 15.00.21022.08 + REQUIRED_LINK_VER = 9.00.21022.08 + endif + endif + endif + ifeq ($(CC_VERSION),gcc) + REQUIRED_CC_VER = 3.4.3 + endif +endif + +# Generic +REQUIRED_ANT_VER = 1.6.3 +REQUIRED_BOOT_VER = 1.5 +REQUIRED_FREETYPE_VERSION = 2.3.0 +REQUIRED_MAKE_VER = 3.78 +REQUIRED_UNZIP_VER = 5.12 +REQUIRED_ZIP_VER = 2.2 + diff --git a/jdk/make/common/shared/Defs-windows.gmk b/jdk/make/common/shared/Defs-windows.gmk index 1ceb017b2f9..abaa6a1807e 100644 --- a/jdk/make/common/shared/Defs-windows.gmk +++ b/jdk/make/common/shared/Defs-windows.gmk @@ -136,10 +136,7 @@ endif UNIXCOMMAND_PATH:=$(call AltCheckSpaces,UNIXCOMMAND_PATH) # Get version of MKS or CYGWIN -ifdef USING_CYGWIN -_CYGWIN_VER :=$(shell $(UNAME)) -CYGWIN_VER :=$(call GetVersion,$(_CYGWIN_VER)) -else # MKS +ifndef USING_CYGWIN _MKS_VER :=$(shell $(MKSINFO) 2>&1 | $(GREP) Release | $(TAIL) -1 | $(SED) -e 's@.*\(Release.*\)@\1@') MKS_VER :=$(call GetVersion,$(_MKS_VER)) # At this point, we can re-define FullPath to use DOSNAME_CMD @@ -202,6 +199,7 @@ else endif ifeq ($(ARCH_DATA_MODEL), 32) _program_files :=$(call FullPath,$(xPROGRAMFILES)) + _program_files32 :=$(_program_files) else ifdef PROGRAMW6432 xPROGRAMW6432 :="$(subst \,/,$(PROGRAMW6432))" @@ -255,39 +253,51 @@ ifeq ($(ARCH_DATA_MODEL), 32) _vs90tools :=$(call FullPath,$(xVS90COMNTOOLS)) endif ifneq ($(_vs90tools),) - _msvc_dir :=$(_vs90tools)/../../Vc - _redist_sdk :=$(_msvc_dir)/../SDK/v3.5/Bin - endif - ifdef VS80COMNTOOLS # /Common/Tools directory, use ../../Vc - xVS80COMNTOOLS :="$(subst \,/,$(VS80COMNTOOLS))" - _vs80tools :=$(call FullPath,$(xVS80COMNTOOLS)) - endif - ifneq ($(_vs80tools),) - _msvc_dir :=$(_vs80tools)/../../Vc - _redist_sdk :=$(_msvc_dir)/../SDK/v2.0/Bin - endif - ifdef VS71COMNTOOLS # /Common/Tools directory, use ../../Vc7 - xVS71COMNTOOLS :="$(subst \,/,$(VS71COMNTOOLS))" - _vs71tools :=$(call FullPath,$(xVS71COMNTOOLS)) - endif - ifneq ($(_vs71tools),) - _msvc_dir :=$(_vs71tools)/../../Vc7 - _redist_sdk :=$(_vs71tools)/../.. + _msvc_dir :=$(_vs90tools)/../../Vc + else + ifdef VS80COMNTOOLS # /Common/Tools directory, use ../../Vc + xVS80COMNTOOLS :="$(subst \,/,$(VS80COMNTOOLS))" + _vs80tools :=$(call FullPath,$(xVS80COMNTOOLS)) + endif + ifneq ($(_vs80tools),) + _msvc_dir :=$(_vs80tools)/../../Vc + else + ifdef VS71COMNTOOLS # /Common/Tools directory, use ../../Vc7 + xVS71COMNTOOLS :="$(subst \,/,$(VS71COMNTOOLS))" + _vs71tools :=$(call FullPath,$(xVS71COMNTOOLS)) + endif + ifneq ($(_vs71tools),) + _msvc_dir :=$(_vs71tools)/../../Vc7 + endif + endif endif endif ifneq ($(_msvc_dir),) _compiler_bin :=$(_msvc_dir)/Bin - _ms_sdk :=$(_msvc_dir)/PlatformSDK + # Assume PlatformSDK is in VS71 (will be empty if VS90) + _ms_sdk :=$(call FullPath,$(_msvc_dir)/PlatformSDK) + # Assume VS90, then VS80, then VS71 + _redist_sdk :=$(call FullPath,$(_msvc_dir)/../SDK/v3.5/Bin) + ifeq ($(_redist_sdk),) + _redist_sdk :=$(call FullPath,$(_msvc_dir)/../SDK/v2.0/Bin) + ifeq ($(_redist_sdk),) + _redist_sdk :=$(call FullPath,$(_msvc_dir)/../SDK/v1.1/Bin) + endif + endif endif endif # The Microsoft Platform SDK installed by itself ifneq ($(_program_files),) - xPSDK :="$(_program_files)/Microsoft Platform SDK" - _psdk :=$(call FullPath,$(xPSDK)) + _PSDK :="$(_program_files)/Microsoft SDKs/Windows/v6.1/" + _psdk :=$(call FullPath,$(xMSSDK61)) ifeq ($(_psdk),) - xPSDK :="$(_program_files)/Microsoft SDK" - _psdk :=$(call FullPath,$(xMSSDK)) + xPSDK :="$(_program_files)/Microsoft Platform SDK" + _psdk :=$(call FullPath,$(xPSDK)) + ifeq ($(_psdk),) + xPSDK :="$(_program_files)/Microsoft SDK" + _psdk :=$(call FullPath,$(xMSSDK)) + endif endif endif @@ -308,13 +318,22 @@ endif # Compilers for 64bit are from SDK ifeq ($(ARCH_DATA_MODEL), 64) - ifneq ($(_ms_sdk),) - ifeq ($(ARCH), ia64) - _compiler_bin :=$(_ms_sdk)/Bin/Win64 - endif - ifeq ($(ARCH), amd64) - _compiler_bin :=$(_ms_sdk)/Bin/Win64/x86/$(ARCH) - _redist_sdk :=$(_ms_sdk)/redist/win64/AMD64 + xVS2008 :="$(_program_files32)/Microsoft Visual Studio 9.0/" + VS2008 :=$(call FullPath,$(xVS2008)) + ifneq ($(VS2008),) + _compiler_bin :=$(VS2008)/VC/Bin/$(ARCH) + xMSSDK61 :="$(_program_files)/Microsoft SDKs/Windows/v6.1/" + MSSDK61 :=$(call FullPath,$(xMSSDK61)) + _redist_sdk :=$(VS2008)/VC/redist/x86/Microsoft.VC90.CRT + else + ifneq ($(_ms_sdk),) + ifeq ($(ARCH), ia64) + _compiler_bin :=$(_ms_sdk)/Bin/Win64 + endif + ifeq ($(ARCH), amd64) + _compiler_bin :=$(_ms_sdk)/Bin/Win64/x86/$(ARCH) + _redist_sdk :=$(_ms_sdk)/redist/win64/AMD64 + endif endif endif endif @@ -417,70 +436,39 @@ ifndef ALT_BOOTDIR _BOOTDIR2 =$(USRJDKINSTANCES_PATH)/jdk$(PREVIOUS_JDK_VERSION) endif -# See if SDK area has a msvcrt.dll file, directory may exist w/o msvcr* files -_REDIST_SDK_EXISTS := $(shell \ - if [ -f "$(_redist_sdk)/msvcrt.dll" ]; then \ - echo "true"; \ - else \ - echo "false"; \ - fi) -_REDISTNN_SDK_EXISTS := $(shell \ - if [ -f "$(_redist_sdk)/$(MSVCRNN_DLL)" ]; then \ - echo "true"; \ - else \ - echo "false"; \ - fi) +# 32 bit always needs 2 runtimes, 64 bit usually does too -# 32 bit needs 2 runtimes +# MSVCRT_DLL_PATH: location of msvcrt.dll that will be re-distributed +ifdef ALT_MSVCRT_DLL_PATH + xALT_MSVCRT_DLL_PATH :="$(subst \,/,$(ALT_MSVCRT_DLL_PATH))" + MSVCRT_DLL_PATH :=$(call FullPath,$(xALT_MSVCRT_DLL_PATH)) +else + MSVCRT_DLL_PATH :=$(call FullPath,$(_system_root)/system32/) +endif +MSVCRT_DLL_PATH:=$(call AltCheckSpaces,MSVCRT_DLL_PATH) +MSVCRT_DLL_PATH:=$(call AltCheckValue,MSVCRT_DLL_PATH) + +# 32bit always needs the MSVCRNN runtime, 64bit does when using VS2008 ifeq ($(ARCH_DATA_MODEL), 32) - - # MSVCRT_DLL_PATH: location of msvcrt.dll that will be re-distributed - ifdef ALT_MSVCRT_DLL_PATH - xALT_MSVCRT_DLL_PATH :="$(subst \,/,$(ALT_MSVCRT_DLL_PATH))" - MSVCRT_DLL_PATH :=$(call FullPath,$(xALT_MSVCRT_DLL_PATH)) + _NEEDS_MSVCRNN = true +else + ifeq ($(VS2008),) + _NEEDS_MSVCRNN = false else - ifeq ($(_REDIST_SDK_EXISTS), true) - xREDIST_DIR :=$(_redist_sdk) - else - xREDIST_DIR :=$(_system_root)/system32 - endif - MSVCRT_DLL_PATH :=$(call FullPath,$(xREDIST_DIR)) + _NEEDS_MSVCRNN = true endif - MSVCRT_DLL_PATH:=$(call AltCheckSpaces,MSVCRT_DLL_PATH) - MSVCRT_DLL_PATH:=$(call AltCheckValue,MSVCRT_DLL_PATH) - +endif + +ifeq ($(_NEEDS_MSVCRNN), true) # MSVCRNN_DLL_PATH: location of msvcrnn.dll that will be re-distributed ifdef ALT_MSVCRNN_DLL_PATH xALT_MSVCRNN_DLL_PATH :="$(subst \,/,$(ALT_MSVCRNN_DLL_PATH))" MSVCRNN_DLL_PATH :=$(call FullPath,$(xALT_MSVCRNN_DLL_PATH)) else - ifeq ($(_REDISTNN_SDK_EXISTS), true) - xREDISTNN_DIR :=$(_redist_sdk) - else - xREDISTNN_DIR :=$(_system_root)/system32 - endif - MSVCRNN_DLL_PATH :=$(call FullPath,$(xREDISTNN_DIR)) + MSVCRNN_DLL_PATH :=$(_redist_sdk) endif MSVCRNN_DLL_PATH :=$(call AltCheckSpaces,MSVCRNN_DLL_PATH) MSVCRNN_DLL_PATH:=$(call AltCheckValue,MSVCRNN_DLL_PATH) - -else - - # MSVCRT_DLL_PATH: location of msvcrt.dll that will be re-distributed - ifdef ALT_MSVCRT_DLL_PATH - xALT_MSVCRT_DLL_PATH :="$(subst \,/,$(ALT_MSVCRT_DLL_PATH))" - MSVCRT_DLL_PATH :=$(call FullPath,$(xALT_MSVCRT_DLL_PATH)) - else - ifeq ($(_REDIST_SDK_EXISTS), true) - xREDIST_DIR :=$(_redist_sdk) - else - xREDIST_DIR :=$(_system_root)/SysWOW64 - endif - MSVCRT_DLL_PATH :=$(call FullPath,$(xREDIST_DIR)) - endif - MSVCRT_DLL_PATH:=$(call AltCheckSpaces,MSVCRT_DLL_PATH) - MSVCRT_DLL_PATH:=$(call AltCheckValue,MSVCRT_DLL_PATH) - endif # DXSDK_PATH: path to Microsoft DirectX SDK Include and Lib @@ -539,7 +527,7 @@ ifdef ALT_INSTALL_MSIVAL2 xALT_INSTALL_MSIVAL2 :="$(subst \,/,$(ALT_INSTALL_MSIVAL2))" INSTALL_MSIVAL2 :=$(call FullPath,$(xALT_INSTALL_MSIVAL2)) else - INSTALL_MSIVAL2 :=$(_program_files)/MsiVal2 + INSTALL_MSIVAL2 :=$(_program_files32)/MsiVal2 endif INSTALL_MSIVAL2:=$(call AltCheckSpaces,INSTALL_MSIVAL2) diff --git a/jdk/make/common/shared/Defs.gmk b/jdk/make/common/shared/Defs.gmk index 638cd363696..5da4a29047e 100644 --- a/jdk/make/common/shared/Defs.gmk +++ b/jdk/make/common/shared/Defs.gmk @@ -116,9 +116,9 @@ $(shell \ fi) endef -# Given a line of text, get the major.minor version number from it +# Given a line of text, get the version number from it define GetVersion -$(shell echo $1 | sed -e 's@[^1-9]*\([1-9][0-9]*\.[0-9][0-9]*\).*@\1@' ) +$(shell echo $1 | sed -e 's@[^0-9]*\([0-9][0-9]*\.[0-9][.0-9]*\).*@\1@' ) endef # Given a major.minor.micro version, return the major, minor, or micro number @@ -133,26 +133,26 @@ $(if $(word 3, $(subst ., ,$1)),$(word 3, $(subst ., ,$1)),0) endef # Macro that returns missing, same, newer, or older $1=version $2=required -# (currently does not check the micro number) define CheckVersions $(shell \ if [ "$1" = "" -o "$2" = "" ]; then \ echo missing; \ + elif [ "$1" = "$2" ]; then \ + echo same; \ + elif [ $(call MajorVersion,$1) -lt $(call MajorVersion,$2) ] ; then \ + echo older; \ + elif [ $(call MajorVersion,$1) -gt $(call MajorVersion,$2) ] ; then \ + echo newer; \ + elif [ $(call MinorVersion,$1) -lt $(call MinorVersion,$2) ]; then \ + echo older; \ + elif [ $(call MinorVersion,$1) -gt $(call MinorVersion,$2) ]; then \ + echo newer; \ + elif [ $(call MicroVersion,$1) -lt $(call MicroVersion,$2) ]; then \ + echo older; \ + elif [ $(call MicroVersion,$1) -gt $(call MicroVersion,$2) ]; then \ + echo newer; \ else \ - if [ "$1" = "$2" ]; then \ - echo same; \ - else \ - if [ $(call MajorVersion,$1) -lt $(call MajorVersion,$2) ] ; then \ - echo older; \ - else \ - if [ $(call MajorVersion,$1) -eq $(call MajorVersion,$2) -a \ - $(call MinorVersion,$1) -lt $(call MinorVersion,$2) ]; then \ - echo older; \ - else \ - echo newer; \ - fi; \ - fi; \ - fi; \ + echo same; \ fi) endef @@ -558,6 +558,24 @@ else COPYRIGHT_YEAR = $(shell $(DATE) '+%Y') endif -# Get shared compiler settings -include $(JDK_MAKE_SHARED_DIR)/Compiler.gmk +# Windows uses Microsoft compilers by default +ifeq ($(PLATFORM), windows) + override CC_VERSION = msvc +endif + +# Solaris uses Sun Studio compilers by default +ifeq ($(PLATFORM), solaris) + override CC_VERSION = sun +endif + +# Linux uses GNU compilers by default +ifeq ($(PLATFORM), linux) + override CC_VERSION = gcc +endif + +# Get the REQUIRED versions (needs CC_VERSION set) +include $(JDK_MAKE_SHARED_DIR)/Defs-versions.gmk + +# Get the compiler specific settings +include $(JDK_MAKE_SHARED_DIR)/Compiler-$(CC_VERSION).gmk diff --git a/jdk/make/common/shared/Platform.gmk b/jdk/make/common/shared/Platform.gmk index 8da23c83fc4..e07de2499fb 100644 --- a/jdk/make/common/shared/Platform.gmk +++ b/jdk/make/common/shared/Platform.gmk @@ -51,9 +51,6 @@ PLATFORM_SHARED=done # USER login name of user (minus blanks) # PLATFORM windows, solaris, or linux # VARIANT OPT or DBG, OPT is the default -# OS_NAME solaris, linux, or nt -# OS_VERSION specific version of os, 5.10, 2.4.9-e.3, etc. -# OS_VENDOR company name # TEMP_DISK /tmp or C:/temp # ARCH_DATA_MODEL 32 or 64 # ARCH sparc, sparcv9, i586, amd64, or ia64 @@ -72,29 +69,11 @@ PLATFORM_SHARED=done # ISA_DIR solaris only: /sparcv9 or /amd64 # LIBARCH32 solaris only: sparc or i386 # LIBARCH64 solaris only: sparcv9 or amd64 -# REQUIRED_WINDOWS_VERSION windows only: specific version of windows # USING_CYGWIN windows only: true or false -# WINDOWS_NT_VERSION_STRING windows only: long version name -# REQUIRED_OS_VERSION required OS version, e.g. 5.10, 2.4 -# REQUIRED_FREE_SPACE minimum disk space needed for outputdir # ISHIELD_TEMP_MIN windows only: minimum disk space in temp area -# REQUIRED_ZIP_VER required version of zip -# REQUIRED_UNZIP_VER required version of unzip -# REQUIRED_DXSDK_VER windows only: required version of DirectX -# LINUX_VERSION_INFO linux only: location of linux release file -# REQUIRED_LINUX_VER linux only: required version of linux -# REQUIRED_LINUX_FULLVER linux only: required full version of linux -# REQUIRED_ALSA_VERSION linux only: required version of ALSA -# REQUIRED_FREETYPE_VERSION openjdk only: required version of freetype SYSTEM_UNAME := $(shell uname) -# Normal boot jdk is previous release, but a hard requirement is a 1.5 boot -REQUIRED_BOOT_VER = 1.5 - -# If we are using freetype, this is the required version -REQUIRED_FREETYPE_VERSION=2.3.0 - # # Prune out all known SCM (Source Code Management) directories # so they will not be included when copying directory trees @@ -113,8 +92,6 @@ endif # Platform settings specific to Solaris ifeq ($(SYSTEM_UNAME), SunOS) PLATFORM = solaris - OS_NAME = solaris - OS_VERSION := $(shell uname -r) # Solaris sparc build can be either 32-bit or 64-bit. # Default to 32, but allow explicit setting to 32 or 64. ifndef ARCH_DATA_MODEL @@ -166,16 +143,6 @@ ifeq ($(SYSTEM_UNAME), SunOS) endif # Suffix for file bundles used in previous release BUNDLE_FILE_SUFFIX=.tar - OS_VENDOR = Sun Microsystems - # Required Solaris version - REQUIRED_OS_VERSION = 5.10 - # Minimum disk space needed as determined by running 'du -sk' on - # a fully built workspace. - ifeq ($(ARCH_FAMILY), sparc) - REQUIRED_FREE_SPACE=1300000 - else - REQUIRED_FREE_SPACE=1040000 - endif # How much RAM does this machine have: MB_OF_MEMORY=$(shell /etc/prtconf | fgrep 'Memory size:' | expand | cut -d' ' -f3) endif @@ -183,8 +150,6 @@ endif # Platform settings specific to Linux ifeq ($(SYSTEM_UNAME), Linux) PLATFORM = linux - OS_NAME = linux - OS_VERSION := $(shell uname -r) # Arch and OS name/version mach := $(shell uname -m) archExpr = case "$(mach)" in \ @@ -242,32 +207,6 @@ ifeq ($(SYSTEM_UNAME), Linux) # Suffix for file bundles used in previous release BUNDLE_FILE_SUFFIX=.tar.gz - # Minimum disk space needed as determined by running 'du -sk' on - # a fully built workspace. - REQUIRED_FREE_SPACE=1460000 - LINUX_VERSION_INFO = /etc/redhat-release - OS_VENDOR = Red Hat - ifeq ($(ARCH_DATA_MODEL), 32) - REQUIRED_LINUX_VER = Advanced Server - REQUIRED_LINUX_FULLVER = Advanced Server release 2.1AS - REQUIRED_OS_VERSION = 2.4.9-e.3 - else - ifeq ($(ARCH), amd64) - LINUX_VERSION_INFO = /etc/SuSE-release - OS_VENDOR = SuSE Enterprise - REQUIRED_LINUX_VER = 8.1 - REQUIRED_LINUX_FULLVER = $(REQUIRED_LINUX_VER) SLSE AMD64 - REQUIRED_OS_VERSION = 2.4.19-SMP - else - REQUIRED_LINUX_VER = Advanced Server - REQUIRED_LINUX_FULLVER = Advanced Server release 2.1AS 64 bit - REQUIRED_OS_VERSION = 2.4.19-SMP - endif - endif - ifneq ($(ARCH), ia64) - # ALSA 0.9.1 and above - REQUIRED_ALSA_VERSION = ^((0[.]9[.][1-9])|(1[.]0[.][0-9]))[0-9]* - endif # How much RAM does this machine have: MB_OF_MEMORY := $(shell free -m | fgrep Mem: | awk '{print $$2;}' ) endif @@ -275,34 +214,34 @@ endif # Windows with and without CYGWIN will be slightly different ifeq ($(SYSTEM_UNAME), Windows_NT) PLATFORM = windows - OS_VERSION := $(shell uname -r) - WINDOWS_NT_VERSION_STRING=Windows_NT - REQUIRED_MKS_VER=6.1 endif ifneq (,$(findstring CYGWIN,$(SYSTEM_UNAME))) PLATFORM = windows - OS_VERSION := 5 USING_CYGWIN = true export USING_CYGWIN - WINDOWS_NT_VERSION_STRING=CYGWIN_NT - REQUIRED_CYGWIN_VER=4.0 endif # Platform settings specific to Windows ifeq ($(PLATFORM), windows) - OS_NAME = nt - REQUIRED_OS_VERSION=5 # Windows builds default to the appropriate for the underlaying # architecture. # Temporary disk area TEMP_DISK=C:/temp # GNU Make or MKS overrides $(PROCESSOR_ARCHITECTURE) to always # return "x86". Use the first word of $(PROCESSOR_IDENTIFIER) instead. + PROC_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) + PROC_ARCH:=$(subst x86,X86,$(PROC_ARCH)) + PROC_ARCH:=$(subst Intel64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst em64t,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst EM64T,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst amd64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst AMD64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst ia64,IA64,$(PROC_ARCH)) ifndef ARCH_DATA_MODEL - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64) + ifeq ($(PROC_ARCH),IA64) ARCH_DATA_MODEL=64 else - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),AMD64) + ifeq ($(PROC_ARCH),X64) ARCH_DATA_MODEL=64 else ARCH_DATA_MODEL=32 @@ -314,18 +253,17 @@ ifeq ($(PLATFORM), windows) # If the user wants to perform a cross compile build then they must # - set ARCH_DATA_MODEL=64 and either # + set ARCH to ia64 or amd64, or - REQUIRED_WINDOWS_VERSION=Server 2003 Enterprise x64 Edition - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)), AMD64) + ifeq ($(PROC_ARCH),X64) ARCH=amd64 else - ARCH=ia64 + ifeq ($(PROC_ARCH),IA64) + ARCH=ia64 + endif endif LIBARCH=$(ARCH) # Value of Java os.arch property ARCHPROP=$(LIBARCH) else - REQUIRED_WINDOWS_VERSION=2000 or Unknown - #REQUIRED_WINDOWS_VERSION=XP Professional # LIBARCH is used to preserve the jre/lib/i386 directory name for 32-bit intel ARCH=i586 LIBARCH=i386 @@ -364,14 +302,9 @@ ifeq ($(PLATFORM), windows) ARCH_VM_SUBDIR=jre/bin # Suffix for file bundles used in previous release BUNDLE_FILE_SUFFIX=.tar - # Minimum disk space needed as determined by running 'du -sk' on - # a fully built workspace. - REQUIRED_FREE_SPACE=500000 # ISHIELD_TEMP_MIN is the difference of an empty C:\TEMP vs. one after a # bundles build on windows. ISHIELD_TEMP_MIN=250000 - REQUIRED_DXSDK_VER = 0x0900 - OS_VENDOR = Microsoft # How much RAM does this machine have: ifeq ($(JDK_HAS_MEM_INFO),) ifeq ($(USING_CYGWIN),true) @@ -410,10 +343,6 @@ ifeq ($(PLATFORM), windows) endif endif -REQUIRED_ZIP_VER = 2.2 -REQUIRED_UNZIP_VER = 5.12 -REQUIRED_MAKE_VER = 3.78 - # Unix type settings (same for all unix platforms) ifneq ($(PLATFORM), windows) # Temporary disk area diff --git a/jdk/make/common/shared/Sanity-Settings.gmk b/jdk/make/common/shared/Sanity-Settings.gmk index f3ea2b35a79..b64e3b52a13 100644 --- a/jdk/make/common/shared/Sanity-Settings.gmk +++ b/jdk/make/common/shared/Sanity-Settings.gmk @@ -97,7 +97,7 @@ ifeq ($(PLATFORM),solaris) endif ifeq ($(PLATFORM),windows) ALL_SETTINGS+=$(call addAltSetting,MSVCRT_DLL_PATH) - ifeq ($(ARCH_DATA_MODEL), 32) + ifneq ($(MSVCRNN_DLL),) ALL_SETTINGS+=$(call addAltSetting,MSVCRNN_DLL_PATH) endif ALL_SETTINGS+=$(call addAltSetting,MSDEVTOOLS_PATH) @@ -167,8 +167,6 @@ ALL_SETTINGS+=$(call addRequiredSetting,ARCHPROP) ifeq ($(PLATFORM),windows) ALL_SETTINGS+=$(call addRequiredSetting,PROCESSOR_ARCHITECTURE) ALL_SETTINGS+=$(call addRequiredSetting,PROCESSOR_IDENTIFIER) - ALL_SETTINGS+=$(call addRequiredSetting,WINDOWS_VERSION) - ALL_SETTINGS+=$(call addRequiredSetting,WINDOWS_NT_VERSION_STRING) ifdef USING_CYGWIN ALL_SETTINGS+=$(call addRequiredSetting,USING_CYGWIN) ALL_SETTINGS+=$(call addRequiredVersionSetting,CYGWIN_VER) @@ -179,13 +177,11 @@ ifeq ($(PLATFORM),windows) endif endif ifeq ($(PLATFORM),linux) - ALL_SETTINGS+=$(call addRequiredSetting,LINUX_VERSION) - ifneq ($(ARCH), ia64) - ALL_SETTINGS+=$(call addRequiredSetting,ALSA_VERSION) - endif + ALL_SETTINGS+=$(call addRequiredSetting,ALSA_VERSION) endif ALL_SETTINGS+=$(call addRequiredVersionSetting,OS_VERSION) -ALL_SETTINGS+=$(call addRequiredSetting,OS_NAME) +ALL_SETTINGS+=$(call addOptionalSetting,OS_VARIANT_NAME) +ALL_SETTINGS+=$(call addOptionalSetting,OS_VARIANT_VERSION) ALL_SETTINGS+=$(call addRequiredSetting,TEMP_FREE_SPACE) ALL_SETTINGS+=$(call addRequiredSetting,FREE_SPACE) ALL_SETTINGS+=$(call addRequiredSetting,MB_OF_MEMORY) @@ -249,6 +245,7 @@ ifdef OPENJDK ALL_SETTINGS+=$(call addAltSetting,FREETYPE_HEADERS_PATH) ALL_SETTINGS+=$(call addAltSetting,FREETYPE_LIB_PATH) ALL_SETTINGS+=$(call addHeading,OPENJDK Import Binary Plug Settings) + ALL_SETTINGS+=$(call addOptionalSetting,IMPORT_BINARY_PLUGS) ALL_SETTINGS+=$(call addAltSetting,BINARY_PLUGS_JARFILE) ALL_SETTINGS+=$(call addAltSetting,BINARY_PLUGS_PATH) ALL_SETTINGS+=$(call addAltSetting,BUILD_BINARY_PLUGS_PATH) diff --git a/jdk/make/common/shared/Sanity.gmk b/jdk/make/common/shared/Sanity.gmk index 997e848904a..180e52196a9 100644 --- a/jdk/make/common/shared/Sanity.gmk +++ b/jdk/make/common/shared/Sanity.gmk @@ -38,60 +38,106 @@ SANITY_FILES = $(ERROR_FILE) $(WARNING_FILE) $(MESSAGE_FILE) # How to say "The Release Engineering people use this" -THE_OFFICIAL_USES=The official $(PLATFORM) builds use +THE_OFFICIAL_USES=The official builds on $(PLATFORM) use # How to say "You are using:" YOU_ARE_USING=You appear to be using +# Error message +define SanityError +$(ECHO) "ERROR: $1\n" >> $(ERROR_FILE) +endef + +# Warning message +define SanityWarning +$(ECHO) "WARNING: $1\n" >> $(WARNING_FILE) +endef + +# Official version error message: name version required_version +define OfficialErrorMessage +$(call SanityError,\ +$(THE_OFFICIAL_USES) $1 $3. Your $1 $(if $2,undefined,$2) will not work.) +endef + +# Official version warning message: name version required_version +define OfficialWarningMessage +$(call SanityWarning,\ +$(THE_OFFICIAL_USES) $1 $3. $(YOU_ARE_USING) $1 $2.) +endef + + # Settings and rules to validate the JDK build environment. ifeq ($(PLATFORM), solaris) FREE_SPACE := $(shell $(DF) -b $(OUTPUTDIR) | $(TAIL) -1 | $(NAWK) '{print $$2;}') TEMP_FREE_SPACE := $(shell $(DF) -b $(TEMP_DISK) | $(TAIL) -1 | $(NAWK) '{print $$2;}') + # What kind of system we are using (Variations are Solaris and OpenSolaris) + OS_VERSION := $(shell uname -r) + OS_VARIANT_NAME := $(strip $(shell head -1 /etc/release | awk '{print $$1;}') ) + OS_VARIANT_VERSION := $(OS_VERSION) REQ_PATCH_LIST = $(JDK_TOPDIR)/make/PatchList.solaris ifeq ($(ARCH_FAMILY), sparc) PATCH_POSITION = $$4 else PATCH_POSITION = $$6 endif + ifndef OPENJDK + _GCC_VER :=$(shell $(GCC) -dumpversion 2>&1 ) + GCC_VER :=$(call GetVersion,"$(_GCC_VER)") + endif endif ifeq ($(PLATFORM), linux) FREE_SPACE := $(shell $(DF) --sync -kP $(OUTPUTDIR) | $(TAIL) -1 | $(NAWK) '{print $$4;}') TEMP_FREE_SPACE := $(shell $(DF) --sync -kP $(TEMP_DISK) | $(TAIL) -1 | $(NAWK) '{print $$4;}') - ifeq ($(ARCH), amd64) - LINUX_VERSION := $(shell \ - if [ -r "$(LINUX_VERSION_INFO)" ] ; then \ - $(CAT) $(LINUX_VERSION_INFO) | $(TAIL) -1 | $(NAWK) '{ print $$3; }';\ - else \ - $(ECHO) "Unknown linux"; \ - fi ) - else - LINUX_VERSION := $(shell \ - if [ -r "$(LINUX_VERSION_INFO)" ] ; then \ - $(NAWK) '{ print $$4" "$$5; }' $(LINUX_VERSION_INFO) ; \ - else \ - $(ECHO) "Unknown linux"; \ - fi ) - endif - ifneq ($(ARCH), ia64) - # dummy program that outputs ALSA's version (created in target sane-alsa-versioncheck) - ALSA_VERSION_CHECK = $(TEMPDIR)/alsaversioncheck - ALSA_VERSION = `if [ -f "$(ALSA_VERSION_CHECK)" ] ; then $(ALSA_VERSION_CHECK) ; fi` - endif + # What kind of system we are using (Variation is the Linux vendor) + OS_VERSION := $(shell uname -r) + OS_VARIANT_NAME := $(shell \ + if [ -f /etc/fedora-release ] ; then \ + echo "Fedora"; \ + elif [ -f /etc/redhat-release ] ; then \ + echo "RedHat"; \ + elif [ -f /etc/SuSE-release ] ; then \ + echo "SuSE"; \ + else \ + echo "Unknown"; \ + fi) + OS_VARIANT_VERSION := $(shell \ + if [ "$(OS_VARIANT_NAME)" = "Fedora" ] ; then \ + $(CAT) /etc/fedora-release | $(HEAD) -1 | $(NAWK) '{ print $$3; }' ; \ + fi) + ALSA_INCLUDE=/usr/include/alsa/version.h + ALSA_LIBRARY=/usr/lib/libasound.so + _ALSA_VERSION := $(shell $(EGREP) SND_LIB_VERSION_STR $(ALSA_INCLUDE) | \ + $(SED) -e 's@.*\"\(.*\)\".*@\1@' ) + ALSA_VERSION := $(call GetVersion,$(_ALSA_VERSION)) endif ifeq ($(PLATFORM), windows) FREE_SPACE := $(shell $(DF) -kP $(OUTPUTDIR) | $(TAIL) -1 | $(NAWK) '{print $$4;}') TEMP_FREE_SPACE := $(shell $(DF) -kP $(TEMP_DISK) | $(TAIL) -1 | $(NAWK) '{print $$4;}') - # Localized systeminfo has localized labels, but not localized values. - _WINDOWS_VERSION := \ - $(shell systeminfo 2> $(DEV_NULL) | grep 'Microsoft' | grep 'Windows' | \ - cut -d':' -f2) - ifeq ($(_WINDOWS_VERSION),) - _WINDOWS_VERSION := Windows 2000 or Unknown (no systeminfo utility) + # Windows 2000 is 5.0, Windows XP is 5.1, Windows 2003 is 5.2 + # Assume 5.0 (Windows 2000) if systeminfo does not help + WINDOWS_MAPPING-5.0 := Windows2000 + WINDOWS_MAPPING-5.1 := WindowsXP + WINDOWS_MAPPING-5.2 := Windows2003 + # What kind of system we are using (Variation is the common name) + _OS_VERSION := \ + $(shell systeminfo 2> $(DEV_NULL) | \ + egrep '^OS Version:' | \ + awk '{print $$3;}' ) + ifeq ($(_OS_VERSION),) + OS_VERSION = 5.0 + else + OS_VERSION = $(call MajorVersion,$(_OS_VERSION)).$(call MinorVersion,$(_OS_VERSION)) + endif + OS_VARIANT_NAME := $(WINDOWS_MAPPING-$(OS_VERSION)) + OS_VARIANT_VERSION := $(OS_VERSION) + ifdef USING_CYGWIN + # CYGWIN version + _CYGWIN_VER := $(SYSTEM_UNAME) + CYGWIN_VER :=$(call GetVersion,$(_CYGWIN_VER)) endif - WINDOWS_VERSION := $(strip $(_WINDOWS_VERSION)) DXSDK_VER := $(shell $(EGREP) DIRECT3D_VERSION $(DXSDK_INCLUDE_PATH)/d3d9.h 2>&1 | \ $(EGREP) "\#define" | $(NAWK) '{print $$3}') endif @@ -106,7 +152,6 @@ ZIP_VER :=$(call GetVersion,"$(_ZIP_VER)") UNZIP_VER :=$(call GetVersion,"$(_UNZIP_VER)") BOOT_VER :=$(call GetVersion,"$(_BOOT_VER)") -REQUIRED_ANT_VER := 1.6.3 _ANT_VER:=$(shell $(ANT) -version 2>&1 ) ANT_VER:=$(call GetVersion,"$(_ANT_VER)") @@ -167,7 +212,6 @@ include $(JDK_MAKE_SHARED_DIR)/Sanity-Settings.gmk sane-compiler \ sane-link \ sane-cacerts \ - sane-alsa-versioncheck \ sane-alsa-headers \ sane-ant_version \ sane-zip_version \ @@ -239,35 +283,29 @@ sane-arch_data_model: # generate a fatal sanity error, and a warning about the official # build platform just becomes clutter. ###################################################### -OS_CHECK :=$(call CheckVersions,$(OS_VERSION),$(REQUIRED_OS_VERSION)) +ifndef OPENJDK + OS_VERSION_CHECK := \ + $(call CheckVersions,$(OS_VERSION),$(REQUIRED_OS_VERSION)) + ifeq ($(OS_VARIANT_NAME),$(REQUIRED_OS_VARIANT_NAME)) + OS_VARIANT_VERSION_CHECK := \ + $(call CheckVersions,$(OS_VARIANT_VERSION),$(REQUIRED_OS_VARIANT_VERSION)) + endif +endif sane-os_version:: sane-arch_data_model sane-memory_check sane-locale sane-os_patch_level ifndef OPENJDK - @if [ "$(OS_CHECK)" = "missing" ]; then \ - $(ECHO) "ERROR: The $(PLATFORM) OS version is undefined (Try: uname -r). \n" \ - "" >> $(ERROR_FILE) ; \ - fi - @if [ "$(OS_CHECK)" != "same" ]; then \ - $(ECHO) "WARNING: $(THE_OFFICIAL_USES) OS version $(REQUIRED_OS_VERSION). \n" \ - " $(YOU_ARE_USING) OS version $(OS_VERSION). \n" \ - "" >> $(WARNING_FILE) ; \ - fi - ifeq ($(PLATFORM), windows) - @if [ "$(findstring $(REQUIRED_WINDOWS_VERSION),$(WINDOWS_VERSION))" = "" ]; then \ - $(ECHO) "WARNING: $(YOU_ARE_USING) an unknown version of Windows. \n" \ - " The required version is $(REQUIRED_WINDOWS_VERSION). \n" \ - " $(YOU_ARE_USING) $(WINDOWS_VERSION) \n" \ - "" >> $(WARNING_FILE) ; \ - fi - endif # windows - ifeq ($(PLATFORM), linux) - @if [ `$(ECHO) "$(LINUX_VERSION)" | $(EGREP) -c '$(REQUIRED_LINUX_VER)'` -ne 1 ]; then \ - $(ECHO) "WARNING: The build is being done on Linux $(LINUX_VERSION). \n" \ - " $(THE_OFFICIAL_USES) Linux $(REQUIRED_LINUX_VER), \n" \ - " specifically Linux $(REQUIRED_LINUX_FULLVER). \n" \ - " The version found was '$(OS_VERSION)'. \n" \ - "" >> $(WARNING_FILE) ; \ - fi - endif # linux + ifneq ($(OS_VARIANT_NAME),$(REQUIRED_OS_VARIANT_NAME)) + ifeq ($(OS_VERSION_CHECK),missing) + @$(call OfficialErrorMessage,OS version,$(OS_VERSION),$(REQUIRED_OS_VERSION)) + endif + ifneq ($(OS_VERSION_CHECK),same) + @$(call OfficialWarningMessage,OS version,$(OS_VERSION),$(REQUIRED_OS_VERSION)) + endif + @$(call OfficialWarningMessage,OS variant,$(OS_VARIANT_NAME),$(REQUIRED_OS_VARIANT_NAME)) + else + ifneq ($(OS_VARIANT_VERSION_CHECK),same) + @$(call OfficialWarningMessage,$(OS_VARIANT_NAME) version,$(OS_VARIANT_VERSION),$(REQUIRED_OS_VARIANT_VERSION)) + endif + endif endif # OPENJDK ifeq ($(PLATFORM), windows) @@ -308,16 +346,12 @@ ifeq ($(PLATFORM), windows) CYGWIN_CHECK :=$(call CheckVersions,$(CYGWIN_VER),$(REQUIRED_CYGWIN_VER)) sane-cygwin: ifdef USING_CYGWIN - @if [ "$(CYGWIN_CHECK)" = "missing" ]; then \ - $(ECHO) "ERROR: The CYGWIN version is undefined. \n" \ - " $(THE_OFFICIAL_USES) CYGWIN $(REQUIRED_CYGWIN_VER). \n" \ - "" >> $(ERROR_FILE) ; \ - fi - @if [ "$(CYGWIN_CHECK)" = "older" ]; then \ - $(ECHO) "ERROR: The build cannot be done on CYGWIN $(CYGWIN_VER). \n" \ - " Use CYGWIN $(REQUIRED_CYGWIN_VER) or higher. \n" \ - "" >> $(ERROR_FILE) ; \ - fi + ifeq ($(CYGWIN_CHECK),missing) + @$(call OfficialErrorMessage,CYGWIN version,$(CYGWIN_VER),$(REQUIRED_CYGWIN_VER)) + endif + ifeq ($(CYGWIN_CHECK),older) + @$(call OfficialWarningMessage,CYGWIN version,$(CYGWIN_VER),$(REQUIRED_CYGWIN_VER)) + endif endif endif @@ -345,16 +379,12 @@ ifeq ($(PLATFORM), windows) MKS_CHECK :=$(call CheckVersions,$(MKS_VER),$(REQUIRED_MKS_VER)) sane-mks: ifndef USING_CYGWIN - @if [ "$(MKS_CHECK)" = "missing" ]; then \ - $(ECHO) "ERROR: The MKS version is undefined. \n" \ - " $(THE_OFFICIAL_USES) MKS $(REQUIRED_MKS_VER). \n" \ - "" >> $(ERROR_FILE) ; \ - fi - @if [ "$(MKS_CHECK)" = "older" ]; then \ - $(ECHO) "ERROR: The build cannot be done on MKS $(MKS_VER). \n" \ - " Use MKS $(REQUIRED_MKS_VER) or higher. \n" \ - "" >> $(ERROR_FILE) ; \ - fi + ifeq ($(MKS_CHECK),missing) + @$(call OfficialErrorMessage,MKS version,$(MKS_VER),$(REQUIRED_MKS_VER)) + endif + ifeq ($(MKS_CHECK),older) + @$(call OfficialErrorMessage,MKS version,$(MKS_VER),$(REQUIRED_MKS_VER)) + endif endif endif @@ -472,13 +502,15 @@ endif ###################################################### ifdef OPENJDK sane-binary-plugs: + ifeq ($(IMPORT_BINARY_PLUGS),true) @if [ ! -d "$(BINARY_PLUGS_PATH)" ]; then \ - $(ECHO) "ERROR: Can't locate pre-built libraries. \n" \ + $(ECHO) "WARNING: Can't locate pre-built libraries. \n" \ " Please check your access to \n" \ " $(BINARY_PLUGS_PATH) \n" \ " and/or check your value of ALT_BINARY_PLUGS_PATH. \n" \ - "" >> $(ERROR_FILE); \ + "" >> $(WARNING_FILE); \ fi + endif endif ###################################################### @@ -834,7 +866,7 @@ ifeq ($(PLATFORM), windows) " and/or check your value of ALT_MSVCRT_DLL_PATH. \n" \ "" >> $(ERROR_FILE) ; \ fi - ifeq ($(ARCH_DATA_MODEL), 32) + ifneq ($(MSVCRNN_DLL),) @if [ ! -r "$(MSVCRNN_DLL_PATH)/$(MSVCRNN_DLL)" ]; then \ $(ECHO) "ERROR: You do not have access to $(MSVCRNN_DLL). \n" \ " Please check your access to \n" \ @@ -1284,8 +1316,8 @@ ifdef LINK_VER fi @if [ "$(LINK_CHECK)" != "same" ]; then \ $(ECHO) "WARNING: To build Java 2 SDK $(JDK_VERSION) you need : \n" \ - " $(COMPILER_VERSION) - link.exe version \"$(REQUIRED_LINK_VER)\" \n" \ - " Specifically the $(COMPILER_NAME) link.exe. \n " \ + " $(REQUIRED_COMPILER_VERSION) - link.exe version \"$(REQUIRED_LINK_VER)\" \n" \ + " Specifically the $(REQUIRED_COMPILER_NAME) link.exe. \n " \ " $(YOU_ARE_USING) Linker version \"$(LINK_VER)\" \n" \ "" >> $(WARNING_FILE) ; \ fi @@ -1295,11 +1327,6 @@ endif # Check the compiler version(s) ###################################################### CC_CHECK :=$(call CheckVersions,$(CC_VER),$(REQUIRED_CC_VER)) -ifeq ($(PLATFORM), solaris) - ifeq ($(ARCH_DATA_MODEL), 32) - GCC_CHECK :=$(call CheckVersions,$(GCC_VER),$(REQUIRED_GCC_VER)) - endif -endif sane-compiler: sane-link @if [ "$(CC_CHECK)" = "missing" ]; then \ $(ECHO) "ERROR: The Compiler version is undefined. \n" \ @@ -1307,69 +1334,36 @@ sane-compiler: sane-link fi ifndef OPENJDK @if [ "$(CC_CHECK)" != "same" ]; then \ - $(ECHO) "WARNING: The $(PLATFORM) compiler is not version $(COMPILER_VERSION) $(REQUIRED_CC_VER) \n" \ - " Specifically the $(COMPILER_NAME) compiler. \n " \ - " $(YOU_ARE_USING) compiler version: $(CC_VER) \n" \ + $(ECHO) "WARNING: The $(PLATFORM) compiler is not version $(REQUIRED_COMPILER_VERSION) $(REQUIRED_CC_VER) \n" \ + " Specifically the $(REQUIRED_COMPILER_NAME) compiler. \n " \ + " $(YOU_ARE_USING) $(COMPILER_VERSION): $(CC_VER) \n" \ " The compiler was obtained from the following location: \n" \ " $(COMPILER_PATH) \n" \ "" >> $(WARNING_FILE) ; \ fi - ifdef GCC_CHECK - @if [ "$(GCC_CHECK)" != "same" ]; then \ - $(ECHO) "WARNING: The $(PLATFORM) GCC compiler must be version $(REQUIRED_GCC_VER) \n" \ - " $(YOU_ARE_USING) compiler version: $(GCC_VER) \n" \ - " The compiler was obtained from the following location: \n" \ - " $(GCC_COMPILER_PATH) \n" \ - " Please change your compiler. \n" \ - "" >> $(WARNING_FILE) ; \ - fi - endif - ifeq ($(PLATFORM), windows) - ifeq ($(ARCH_DATA_MODEL), 64) - ifneq ($(COMPILER_VERSION), VS2005) - @$(ECHO) "WARNING: Should be using VS2005 compiler on 64bit platform. \n" \ - "" >> $(WARNING_FILE) - endif - endif - endif endif ###################################################### # Check that ALSA headers and libs are installed and # that the header has the right version. We only -# need /usr/include/alsa/*.h and /usr/lib/libasound.so +# need /usr/include/alsa/version.h and /usr/lib/libasound.so ###################################################### -ifdef ALSA_VERSION_CHECK -$(ALSA_VERSION_CHECK): $(ALSA_VERSION_CHECK).c - @$(prep-target) - @$(CC) -lasound -o $@ $< - -$(ALSA_VERSION_CHECK).c: - @$(prep-target) - @$(ECHO) "#include \n" \ - "#include \n" \ - "int main(int argc, char** argv) {\n" \ - " printf(\"%s\", SND_LIB_VERSION_STR);\n" \ - " return 0;\n" \ - "}\n" \ - > $@ +ifdef REQUIRED_ALSA_VERSION + ALSA_CHECK := $(call CheckVersions,$(ALSA_VERSION),$(REQUIRED_ALSA_VERSION)) endif - -sane-alsa-versioncheck: $(ALSA_VERSION_CHECK) -sane-alsa-headers: sane-alsa-versioncheck -ifdef ALSA_VERSION_CHECK - @if [ -f "$(ALSA_VERSION_CHECK)" ]; then \ - if [ `$(ALSA_VERSION_CHECK) | $(EGREP) -c '$(REQUIRED_ALSA_VERSION)'` -ne 1 ] ; then \ - $(ECHO) "ERROR: The ALSA version must be 0.9.1 or higher. \n" \ - " You have the following ALSA version installed: $(ALSA_VERSION) \n" \ +sane-alsa-headers: +ifdef REQUIRED_ALSA_VERSION + if [ "$(ALSA_CHECK)" != "same" -a "$(ALSA_CHECK)" != "newer" ] ; then \ + $(ECHO) "ERROR: The ALSA version must be $(REQUIRED_ALSA_VERSION) or higher. \n" \ + " You have the following ALSA version installed: $${alsa_version) \n" \ " Please reinstall ALSA (drivers and lib). You can download \n" \ " the source distribution from http://www.alsa-project.org \n" \ " or go to http://www.freshrpms.net/docs/alsa/ for precompiled RPM packages. \n" \ "" >> $(ERROR_FILE) ; \ fi \ else \ - $(ECHO) "ERROR: You seem to not have installed ALSA 0.9.1 or higher. \n" \ + $(ECHO) "ERROR: You seem to not have installed ALSA $(REQUIRED_ALSA_VERSION) or higher. \n" \ " Please install ALSA (drivers and lib). You can download the \n" \ " source distribution from http://www.alsa-project.org or go to \n" \ " http://www.freshrpms.net/docs/alsa/ for precompiled RPM packages. \n" \ @@ -1384,7 +1378,7 @@ $(SANITY_FILES): ###################################################### # dump out the variable settings... ###################################################### -sane-settings:: sane-alsa-versioncheck +sane-settings:: @$(ECHO) >> $(MESSAGE_FILE) @$(ECHO) $(ALL_SETTINGS) >> $(MESSAGE_FILE) @$(ECHO) >> $(MESSAGE_FILE) @@ -1453,8 +1447,8 @@ sane-gcc-compiler: ifeq ($(PLATFORM), solaris) ifndef OPENJDK @if [ -r $(GCC_COMPILER_PATH) ]; then \ - if [ ! "$(GCC_VER)" = 2.95.2 ]; then \ - $(ECHO) "ERROR: The Solaris GCC compiler version must be 2.95.2. \n" \ + if [ ! "$(GCC_VER)" = $(REQUIRED_GCC_VERSION) ]; then \ + $(ECHO) "ERROR: The Solaris GCC compiler version must be $(REQUIRED_GCC_VERSION). \n" \ " You are using the following compiler version: $(GCC_VER) \n" \ " The compiler was obtained from the following location: \n" \ " $(GCC_COMPILER_PATH) \n" \ diff --git a/jdk/make/docs/CORE_PKGS.gmk b/jdk/make/docs/CORE_PKGS.gmk index 4a41a2005bf..f9b9ee59cc1 100644 --- a/jdk/make/docs/CORE_PKGS.gmk +++ b/jdk/make/docs/CORE_PKGS.gmk @@ -1,5 +1,5 @@ # -# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -110,6 +110,9 @@ CORE_PKGS = \ java.nio.channels.spi \ java.nio.charset \ java.nio.charset.spi \ + java.nio.file \ + java.nio.file.attribute \ + java.nio.file.spi \ java.rmi \ java.rmi.activation \ java.rmi.dgc \ diff --git a/jdk/make/docs/Makefile b/jdk/make/docs/Makefile index 07fe50e6416..301acde0826 100644 --- a/jdk/make/docs/Makefile +++ b/jdk/make/docs/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ endif DOCSTMPDIR = $(TEMPDIR)/doctmp COMMON_JAVADOCFLAGS = \ + $(NO_PROPRIETARY_API_WARNINGS) \ -source 1.5 \ -quiet \ -use \ @@ -203,6 +204,9 @@ JDI_DOCTITLE = "Java$(TRADEMARK) Debug Interface" JDI_HEADER = "Java Debug Interface" # JDI_PKGS is located in NON_CORE_PKGS.gmk +# Variables used by security components +SECURITYAPI_JAVADOCBOTTOM = 'Report a bug or request a feature.
Copyright $(THIS_YEAR) Sun Microsystems, Inc. All Rights Reserved. Use is subject to license terms.
' + # # Variables used by JAAS target # @@ -220,6 +224,7 @@ JAAS_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ -windowtitle $(JAAS_WINDOWTITLE) \ -doctitle $(JAAS_DOCTITLE) \ -header $(JAAS_JAVADOCHEADER) \ + -bottom $(SECURITYAPI_JAVADOCBOTTOM) \ -linkoffline ../../../../../api $(DOCSDIR)/api/ \ -overview $(TOPDIR)/src/share/classes/com/sun/security/auth/jaas-overview.html JAAS_WINDOWTITLE = "Java Authentication and Authorization Service " @@ -242,6 +247,7 @@ JGSS_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ -windowtitle $(JGSS_WINDOWTITLE) \ -doctitle $(JGSS_DOCTITLE) \ -header $(JGSS_JAVADOCHEADER) \ + -bottom $(SECURITYAPI_JAVADOCBOTTOM) \ -linkoffline ../../../../../api $(DOCSDIR)/api/ \ -overview $(JGSS_SOURCEPATH)/com/sun/security/jgss/jgss-overview.html @@ -265,6 +271,7 @@ SMARTCARDIO_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ -windowtitle $(SMARTCARDIO_WINDOWTITLE) \ -doctitle $(SMARTCARDIO_DOCTITLE) \ -header $(SMARTCARDIO_JAVADOCHEADER) \ + -bottom $(SECURITYAPI_JAVADOCBOTTOM) \ -linkoffline ../../../../../api $(DOCSDIR)/api/ SMARTCARDIO_WINDOWTITLE = "Java Smart Card I/O" diff --git a/jdk/make/docs/NON_CORE_PKGS.gmk b/jdk/make/docs/NON_CORE_PKGS.gmk index ccf7a0f79a8..6028a85da34 100644 --- a/jdk/make/docs/NON_CORE_PKGS.gmk +++ b/jdk/make/docs/NON_CORE_PKGS.gmk @@ -1,5 +1,5 @@ # -# Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,8 @@ OLD_JSSE_PKGS = com.sun.net.ssl HTTPSERVER_PKGS = com.sun.net.httpserver \ com.sun.net.httpserver.spi +NIO_PKGS = com.sun.nio.file + DOCLETAPI_PKGS = com.sun.javadoc TAGLETAPI_FILE = com/sun/tools/doclets/Taglet.java @@ -92,6 +94,7 @@ NON_CORE_PKGS = $(DOMAPI_PKGS) \ $(MGMT_PKGS) \ $(JAAS_PKGS) \ $(JGSS_PKGS) \ + $(NIO_PKGS) \ $(OLD_JSSE_PKGS) \ $(HTTPSERVER_PKGS) \ $(SMARTCARDIO_PKGS) \ diff --git a/jdk/make/java/fdlibm/Makefile b/jdk/make/java/fdlibm/Makefile index eeb5e744f41..739eaf4403f 100644 --- a/jdk/make/java/fdlibm/Makefile +++ b/jdk/make/java/fdlibm/Makefile @@ -45,6 +45,7 @@ FDLIBM_SRC = $(SHARE_SRC)/native/java/lang/fdlibm ifeq ($(PLATFORM),windows) # Turn all optimizations off OPTIMIZATION_LEVEL = NONE + FASTDEBUG_OPTIMIZATION_LEVEL = NONE OTHER_CFLAGS = CPPFLAGS_DBG += -DLOGGING endif @@ -56,6 +57,7 @@ endif ifeq ($(PLATFORM),linux) # Turn all optimizations off OPTIMIZATION_LEVEL = NONE + FASTDEBUG_OPTIMIZATION_LEVEL = NONE endif # diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index 3117af8461f..83f3af7d968 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -449,7 +449,6 @@ JAVA_JAVA_java = \ sun/misc/Service.java \ sun/misc/JavaLangAccess.java \ sun/misc/JavaIOAccess.java \ - sun/misc/JavaIODeleteOnExitAccess.java \ sun/misc/JavaIOFileDescriptorAccess.java \ sun/misc/JavaNioAccess.java diff --git a/jdk/make/java/java/mapfile-vers b/jdk/make/java/java/mapfile-vers index 77a78301af7..a9231b4d648 100644 --- a/jdk/make/java/java/mapfile-vers +++ b/jdk/make/java/java/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -135,7 +135,8 @@ SUNWprivate_1.1 { Java_java_lang_ClassLoader_00024NativeLibrary_find; Java_java_lang_ClassLoader_00024NativeLibrary_load; Java_java_lang_ClassLoader_00024NativeLibrary_unload; - Java_java_lang_ClassLoader_registerNatives; + Java_java_lang_ClassLoader_getCaller; + Java_java_lang_ClassLoader_registerNatives; Java_java_lang_Compiler_registerNatives; Java_java_lang_Double_longBitsToDouble; Java_java_lang_Double_doubleToRawLongBits; diff --git a/jdk/make/java/management/Makefile b/jdk/make/java/management/Makefile index 466d2212afe..f579e10c105 100644 --- a/jdk/make/java/management/Makefile +++ b/jdk/make/java/management/Makefile @@ -46,6 +46,8 @@ include $(BUILDDIR)/common/Mapfile-vers.gmk # include FILES_c.gmk +# We don't need snmp here. +AUTO_JAVA_PRUNE = snmp AUTO_FILES_JAVA_DIRS = java/lang/management com/sun/management sun/management include Exportedfiles.gmk diff --git a/jdk/make/java/net/FILES_c.gmk b/jdk/make/java/net/FILES_c.gmk index 2eb4daa2cbb..0e638816d10 100644 --- a/jdk/make/java/net/FILES_c.gmk +++ b/jdk/make/java/net/FILES_c.gmk @@ -39,6 +39,10 @@ FILES_c = \ ResolverConfigurationImpl.c \ DefaultProxySelector.c +ifeq ($(PLATFORM), solaris) + FILES_c += SdpProvider.c +endif + ifeq ($(PLATFORM), linux) FILES_c += linux_close.c endif diff --git a/jdk/make/java/net/Makefile b/jdk/make/java/net/Makefile index b9a3defdb8c..203b059a388 100644 --- a/jdk/make/java/net/Makefile +++ b/jdk/make/java/net/Makefile @@ -108,11 +108,24 @@ CLASSES.export += java.lang.Integer java.io.FileDescriptor java.net.InetAddressI # LOCALE_SET_DEFINITION = jre -properties: $(LIBDIR) $(LIBDIR)/net.properties +MISC_FILES = $(LIBDIR) $(LIBDIR)/net.properties $(LIBDIR)/net.properties: $(SHARE_SRC)/lib/net.properties @$(RM) $@ $(CP) $< $@ -build: properties +# +# SDP configuration template +# +ifeq ($(PLATFORM), solaris) +SDP_PATH = sdp/sdp.conf.template +SDP_CONF = $(LIBDIR)/$(SDP_PATH) +$(SDP_CONF): $(PLATFORM_SRC)/lib/$(SDP_PATH) + @$(RM) $* + $(install-file) + +MISC_FILES += $(SDP_CONF) +endif + +build: $(MISC_FILES) diff --git a/jdk/make/java/net/mapfile-vers b/jdk/make/java/net/mapfile-vers index d9803f8f944..c30803cbfef 100644 --- a/jdk/make/java/net/mapfile-vers +++ b/jdk/make/java/net/mapfile-vers @@ -90,6 +90,7 @@ SUNWprivate_1.1 { Java_sun_net_dns_ResolverConfigurationImpl_fallbackDomain0; Java_sun_net_spi_DefaultProxySelector_init; Java_sun_net_spi_DefaultProxySelector_getSystemProxy; + Java_sun_net_spi_SdpProvider_convert; NET_AllocSockaddr; NET_SockaddrToInetAddress; NET_SockaddrEqualsInetAddress; diff --git a/jdk/make/java/nio/Exportedfiles.gmk b/jdk/make/java/nio/Exportedfiles.gmk index 49c4e24ac3f..fd8b73f64b9 100644 --- a/jdk/make/java/nio/Exportedfiles.gmk +++ b/jdk/make/java/nio/Exportedfiles.gmk @@ -1,5 +1,5 @@ # -# Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ FILES_export = \ sun/nio/ch/DatagramChannelImpl.java \ sun/nio/ch/DatagramDispatcher.java \ sun/nio/ch/FileChannelImpl.java \ - sun/nio/ch/FileDispatcher.java \ + sun/nio/ch/FileDispatcherImpl.java \ sun/nio/ch/FileKey.java \ sun/nio/ch/FileLockImpl.java \ sun/nio/ch/IOStatus.java \ diff --git a/jdk/make/java/nio/FILES_c.gmk b/jdk/make/java/nio/FILES_c.gmk index 6f7c3ff3f74..b1670c20dfe 100644 --- a/jdk/make/java/nio/FILES_c.gmk +++ b/jdk/make/java/nio/FILES_c.gmk @@ -1,5 +1,5 @@ # -# Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ FILES_c = \ DatagramChannelImpl.c \ DatagramDispatcher.c \ FileChannelImpl.c \ - FileDispatcher.c \ + FileDispatcherImpl.c \ FileKey.c \ IOUtil.c \ MappedByteBuffer.c \ diff --git a/jdk/make/java/nio/FILES_java.gmk b/jdk/make/java/nio/FILES_java.gmk index 29f1f8f42c4..637b8dc4f96 100644 --- a/jdk/make/java/nio/FILES_java.gmk +++ b/jdk/make/java/nio/FILES_java.gmk @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,19 +31,29 @@ FILES_src = \ java/nio/MappedByteBuffer.java \ java/nio/StringCharBuffer.java \ \ + java/nio/channels/AsynchronousByteChannel.java \ + java/nio/channels/AsynchronousChannel.java \ + java/nio/channels/AsynchronousChannelGroup.java \ + java/nio/channels/AsynchronousDatagramChannel.java \ + java/nio/channels/AsynchronousFileChannel.java \ + java/nio/channels/AsynchronousServerSocketChannel.java \ + java/nio/channels/AsynchronousSocketChannel.java \ java/nio/channels/ByteChannel.java \ java/nio/channels/Channel.java \ java/nio/channels/Channels.java \ + java/nio/channels/CompletionHandler.java \ java/nio/channels/DatagramChannel.java \ java/nio/channels/FileChannel.java \ java/nio/channels/FileLock.java \ java/nio/channels/GatheringByteChannel.java \ java/nio/channels/InterruptibleChannel.java \ + java/nio/channels/Pipe.java \ java/nio/channels/MembershipKey.java \ java/nio/channels/MulticastChannel.java \ java/nio/channels/NetworkChannel.java \ java/nio/channels/ReadableByteChannel.java \ java/nio/channels/ScatteringByteChannel.java \ + java/nio/channels/SeekableByteChannel.java \ java/nio/channels/SelectableChannel.java \ java/nio/channels/Selector.java \ java/nio/channels/SelectionKey.java \ @@ -55,6 +65,7 @@ FILES_src = \ java/nio/channels/spi/AbstractSelectableChannel.java \ java/nio/channels/spi/AbstractSelectionKey.java \ java/nio/channels/spi/AbstractSelector.java \ + java/nio/channels/spi/AsynchronousChannelProvider.java \ java/nio/channels/spi/SelectorProvider.java \ \ java/nio/charset/Charset.java \ @@ -66,21 +77,117 @@ FILES_src = \ \ java/nio/charset/spi/CharsetProvider.java \ \ + java/nio/file/AccessDeniedException.java \ + java/nio/file/AccessMode.java \ + java/nio/file/AtomicMoveNotSupportedException.java \ + java/nio/file/ClosedDirectoryStreamException.java \ + java/nio/file/ClosedFileSystemException.java \ + java/nio/file/ClosedWatchServiceException.java \ + java/nio/file/CopyOption.java \ + java/nio/file/DirectoryNotEmptyException.java \ + java/nio/file/DirectoryStream.java \ + java/nio/file/DirectoryStreamFilters.java \ + java/nio/file/FileAction.java \ + java/nio/file/FileAlreadyExistsException.java \ + java/nio/file/FileRef.java \ + java/nio/file/FileStore.java \ + java/nio/file/FileSystem.java \ + java/nio/file/FileSystemAlreadyExistsException.java \ + java/nio/file/FileSystemException.java \ + java/nio/file/FileSystemNotFoundException.java \ + java/nio/file/FileSystems.java \ + java/nio/file/FileTreeWalker.java \ + java/nio/file/FileVisitOption.java \ + java/nio/file/FileVisitResult.java \ + java/nio/file/FileVisitor.java \ + java/nio/file/Files.java \ + java/nio/file/InvalidPathException.java \ + java/nio/file/LinkOption.java \ + java/nio/file/LinkPermission.java \ + java/nio/file/NoSuchFileException.java \ + java/nio/file/NotDirectoryException.java \ + java/nio/file/NotLinkException.java \ + java/nio/file/OpenOption.java \ + java/nio/file/Path.java \ + java/nio/file/PathMatcher.java \ + java/nio/file/Paths.java \ + java/nio/file/ProviderMismatchException.java \ + java/nio/file/ProviderNotFoundException.java \ + java/nio/file/ReadOnlyFileSystemException.java \ + java/nio/file/SecureDirectoryStream.java \ + java/nio/file/SimpleFileVisitor.java \ + java/nio/file/StandardCopyOption.java \ + java/nio/file/StandardOpenOption.java \ + java/nio/file/StandardWatchEventKind.java \ + java/nio/file/WatchEvent.java \ + java/nio/file/WatchKey.java \ + java/nio/file/WatchService.java \ + java/nio/file/Watchable.java \ + \ + java/nio/file/attribute/AclEntry.java \ + java/nio/file/attribute/AclEntryFlag.java \ + java/nio/file/attribute/AclEntryPermission.java \ + java/nio/file/attribute/AclEntryType.java \ + java/nio/file/attribute/AclFileAttributeView.java \ + java/nio/file/attribute/AttributeView.java \ + java/nio/file/attribute/Attributes.java \ + java/nio/file/attribute/BasicFileAttributeView.java \ + java/nio/file/attribute/BasicFileAttributes.java \ + java/nio/file/attribute/DosFileAttributeView.java \ + java/nio/file/attribute/DosFileAttributes.java \ + java/nio/file/attribute/FileAttribute.java \ + java/nio/file/attribute/FileAttributeView.java \ + java/nio/file/attribute/FileOwnerAttributeView.java \ + java/nio/file/attribute/FileStoreAttributeView.java \ + java/nio/file/attribute/FileStoreSpaceAttributeView.java \ + java/nio/file/attribute/FileStoreSpaceAttributes.java \ + java/nio/file/attribute/GroupPrincipal.java \ + java/nio/file/attribute/UserDefinedFileAttributeView.java \ + java/nio/file/attribute/PosixFileAttributeView.java \ + java/nio/file/attribute/PosixFileAttributes.java \ + java/nio/file/attribute/PosixFilePermission.java \ + java/nio/file/attribute/PosixFilePermissions.java \ + java/nio/file/attribute/UserPrincipal.java \ + java/nio/file/attribute/UserPrincipalLookupService.java \ + java/nio/file/attribute/UserPrincipalNotFoundException.java \ + \ + java/nio/file/spi/AbstractPath.java \ + java/nio/file/spi/FileSystemProvider.java \ + java/nio/file/spi/FileTypeDetector.java \ + \ + com/sun/nio/file/ExtendedCopyOption.java \ + com/sun/nio/file/ExtendedOpenOption.java \ + com/sun/nio/file/ExtendedWatchEventModifier.java \ + com/sun/nio/file/SensitivityWatchEventModifier.java \ + \ sun/nio/ByteBuffered.java \ \ + sun/nio/ch/AbstractFuture.java \ sun/nio/ch/AbstractPollArrayWrapper.java \ sun/nio/ch/AllocatedNativeObject.java \ + sun/nio/ch/AsynchronousChannelGroupImpl.java \ + sun/nio/ch/AsynchronousFileChannelImpl.java \ + sun/nio/ch/AsynchronousServerSocketChannelImpl.java \ + sun/nio/ch/AsynchronousSocketChannelImpl.java \ + sun/nio/ch/Cancellable.java \ sun/nio/ch/ChannelInputStream.java \ + sun/nio/ch/CompletedFuture.java \ sun/nio/ch/DatagramChannelImpl.java \ sun/nio/ch/DatagramDispatcher.java \ sun/nio/ch/DatagramSocketAdaptor.java \ + sun/nio/ch/DefaultAsynchronousChannelProvider.java \ sun/nio/ch/DefaultSelectorProvider.java \ sun/nio/ch/DirectBuffer.java \ sun/nio/ch/ExtendedSocketOption.java \ sun/nio/ch/FileChannelImpl.java \ sun/nio/ch/FileDispatcher.java \ + sun/nio/ch/FileDispatcherImpl.java \ sun/nio/ch/FileKey.java \ + sun/nio/ch/FileLockImpl.java \ + sun/nio/ch/FileLockTable.java \ + sun/nio/ch/Groupable.java \ sun/nio/ch/Interruptible.java \ + sun/nio/ch/Invoker.java \ sun/nio/ch/IOUtil.java \ sun/nio/ch/IOStatus.java \ sun/nio/ch/IOVecWrapper.java \ @@ -92,6 +199,7 @@ FILES_src = \ sun/nio/ch/NativeThreadSet.java \ sun/nio/ch/Net.java \ sun/nio/ch/OptionKey.java \ + sun/nio/ch/PendingFuture.java \ sun/nio/ch/PipeImpl.java \ sun/nio/ch/PollArrayWrapper.java \ sun/nio/ch/Reflect.java \ @@ -101,15 +209,19 @@ FILES_src = \ sun/nio/ch/SelChImpl.java \ sun/nio/ch/ServerSocketAdaptor.java \ sun/nio/ch/ServerSocketChannelImpl.java \ + sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java \ sun/nio/ch/SinkChannelImpl.java \ sun/nio/ch/SocketAdaptor.java \ sun/nio/ch/SocketChannelImpl.java \ sun/nio/ch/SocketDispatcher.java \ sun/nio/ch/SocketOptionRegistry.java \ sun/nio/ch/SourceChannelImpl.java \ + sun/nio/ch/ThreadPool.java \ sun/nio/ch/Util.java \ \ sun/nio/cs/AbstractCharsetProvider.java \ + sun/nio/cs/ArrayDecoder.java \ + sun/nio/cs/ArrayEncoder.java \ sun/nio/cs/FastCharsetProvider.java \ sun/nio/cs/HistoricallyNamedCharset.java \ sun/nio/cs/ISO_8859_1.java \ @@ -134,6 +246,25 @@ FILES_src = \ sun/nio/cs/UTF_32LE_BOM.java \ sun/nio/cs/UTF_32Coder.java \ \ + sun/nio/fs/AbstractAclFileAttributeView.java \ + sun/nio/fs/AbstractBasicFileAttributeView.java \ + sun/nio/fs/AbstractFileStoreSpaceAttributeView.java \ + sun/nio/fs/AbstractFileTypeDetector.java \ + sun/nio/fs/AbstractPoller.java \ + sun/nio/fs/AbstractUserDefinedFileAttributeView.java \ + sun/nio/fs/AbstractWatchKey.java \ + sun/nio/fs/AbstractWatchService.java \ + sun/nio/fs/BasicFileAttributesHolder.java \ + sun/nio/fs/Cancellable.java \ + sun/nio/fs/DefaultFileSystemProvider.java \ + sun/nio/fs/DefaultFileTypeDetector.java \ + sun/nio/fs/FileOwnerAttributeViewImpl.java \ + sun/nio/fs/Globs.java \ + sun/nio/fs/MimeType.java \ + sun/nio/fs/NativeBuffer.java \ + sun/nio/fs/NativeBuffers.java \ + sun/nio/fs/Reflect.java \ + \ java/net/DatagramSocket.java \ java/net/DatagramSocketImpl.java \ java/net/PlainSocketImpl.java \ @@ -244,24 +375,31 @@ FILES_gen_ex = \ java/nio/InvalidMarkException.java \ java/nio/ReadOnlyBufferException.java \ \ + java/nio/channels/AcceptPendingException.java \ java/nio/channels/AlreadyBoundException.java \ java/nio/channels/AlreadyConnectedException.java \ java/nio/channels/AsynchronousCloseException.java \ + java/nio/channels/CancelledKeyException.java \ java/nio/channels/ClosedByInterruptException.java \ java/nio/channels/ClosedChannelException.java \ java/nio/channels/ClosedSelectorException.java \ java/nio/channels/ConnectionPendingException.java \ java/nio/channels/FileLockInterruptionException.java \ java/nio/channels/IllegalBlockingModeException.java \ + java/nio/channels/IllegalChannelGroupException.java \ java/nio/channels/IllegalSelectorException.java \ + java/nio/channels/InterruptedByTimeoutException.java \ java/nio/channels/NoConnectionPendingException.java \ java/nio/channels/NonReadableChannelException.java \ java/nio/channels/NonWritableChannelException.java \ java/nio/channels/NotYetBoundException.java \ java/nio/channels/NotYetConnectedException.java \ java/nio/channels/OverlappingFileLockException.java \ + java/nio/channels/ReadPendingException.java \ + java/nio/channels/ShutdownChannelGroupException.java \ java/nio/channels/UnresolvedAddressException.java \ java/nio/channels/UnsupportedAddressTypeException.java \ + java/nio/channels/WritePendingException.java \ \ java/nio/charset/CharacterCodingException.java \ java/nio/charset/IllegalCharsetNameException.java \ diff --git a/jdk/make/java/nio/Makefile b/jdk/make/java/nio/Makefile index bf7bc2e0236..f85cc69e525 100644 --- a/jdk/make/java/nio/Makefile +++ b/jdk/make/java/nio/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -56,56 +56,214 @@ FILES_java += \ sun/nio/ch/DevPollSelectorProvider.java \ sun/nio/ch/InheritedChannel.java \ sun/nio/ch/PollSelectorProvider.java \ - sun/nio/ch/PollSelectorImpl.java + sun/nio/ch/PollSelectorImpl.java \ + sun/nio/ch/Port.java \ + sun/nio/ch/SimpleAsynchronousFileChannelImpl.java \ + sun/nio/ch/SolarisAsynchronousChannelProvider.java \ + sun/nio/ch/SolarisEventPort.java \ + sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \ + sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \ + \ + sun/nio/fs/GnomeFileTypeDetector.java \ + sun/nio/fs/PollingWatchService.java \ + sun/nio/fs/SolarisAclFileAttributeView.java \ + sun/nio/fs/SolarisFileStore.java \ + sun/nio/fs/SolarisFileSystem.java \ + sun/nio/fs/SolarisFileSystemProvider.java \ + sun/nio/fs/SolarisUserDefinedFileAttributeView.java \ + sun/nio/fs/SolarisNativeDispatcher.java \ + sun/nio/fs/SolarisWatchService.java \ + sun/nio/fs/UnixChannelFactory.java \ + sun/nio/fs/UnixCopyFile.java \ + sun/nio/fs/UnixDirectoryStream.java \ + sun/nio/fs/UnixException.java \ + sun/nio/fs/UnixFileAttributeViews.java \ + sun/nio/fs/UnixFileAttributes.java \ + sun/nio/fs/UnixFileKey.java \ + sun/nio/fs/UnixFileModeAttribute.java \ + sun/nio/fs/UnixFileStore.java \ + sun/nio/fs/UnixFileStoreAttributes.java \ + sun/nio/fs/UnixFileSystem.java \ + sun/nio/fs/UnixFileSystemProvider.java \ + sun/nio/fs/UnixMountEntry.java \ + sun/nio/fs/UnixNativeDispatcher.java \ + sun/nio/fs/UnixPath.java \ + sun/nio/fs/UnixSecureDirectoryStream.java \ + sun/nio/fs/UnixUriUtils.java \ + sun/nio/fs/UnixUserPrincipals.java FILES_c += \ DevPollArrayWrapper.c \ InheritedChannel.c \ NativeThread.c \ - PollArrayWrapper.c + PollArrayWrapper.c \ + SolarisEventPort.c \ + UnixAsynchronousServerSocketChannelImpl.c \ + UnixAsynchronousSocketChannelImpl.c \ + \ + GnomeFileTypeDetector.c \ + SolarisNativeDispatcher.c \ + SolarisWatchService.c \ + UnixCopyFile.c \ + UnixNativeDispatcher.c FILES_export += \ sun/nio/ch/DevPollArrayWrapper.java \ sun/nio/ch/InheritedChannel.java \ - sun/nio/ch/NativeThread.java + sun/nio/ch/NativeThread.java \ + sun/nio/ch/SolarisEventPort.java \ + sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \ + sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \ + \ + sun/nio/fs/GnomeFileTypeDetector.java \ + sun/nio/fs/SolarisNativeDispatcher.java \ + sun/nio/fs/SolarisWatchService.java \ + sun/nio/fs/UnixCopyFile.java \ + sun/nio/fs/UnixNativeDispatcher.java + +FILES_gen += \ + sun/nio/fs/SolarisConstants.java \ + sun/nio/fs/UnixConstants.java endif # PLATFORM = solaris ifeq ($(PLATFORM), windows) FILES_java += \ + sun/nio/ch/Iocp.java \ + sun/nio/ch/PendingIoCache.java \ + sun/nio/ch/WindowsAsynchronousChannelProvider.java \ + sun/nio/ch/WindowsAsynchronousFileChannelImpl.java \ + sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java \ + sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java \ sun/nio/ch/WindowsSelectorImpl.java \ - sun/nio/ch/WindowsSelectorProvider.java + sun/nio/ch/WindowsSelectorProvider.java \ + \ + sun/nio/fs/RegistryFileTypeDetector.java \ + sun/nio/fs/WindowsAclFileAttributeView.java \ + sun/nio/fs/WindowsChannelFactory.java \ + sun/nio/fs/WindowsConstants.java \ + sun/nio/fs/WindowsDirectoryStream.java \ + sun/nio/fs/WindowsException.java \ + sun/nio/fs/WindowsFileAttributeViews.java \ + sun/nio/fs/WindowsFileAttributes.java \ + sun/nio/fs/WindowsFileCopy.java \ + sun/nio/fs/WindowsFileStore.java \ + sun/nio/fs/WindowsFileSystem.java \ + sun/nio/fs/WindowsFileSystemProvider.java \ + sun/nio/fs/WindowsLinkSupport.java \ + sun/nio/fs/WindowsUserDefinedFileAttributeView.java \ + sun/nio/fs/WindowsNativeDispatcher.java \ + sun/nio/fs/WindowsPath.java \ + sun/nio/fs/WindowsPathParser.java \ + sun/nio/fs/WindowsPathType.java \ + sun/nio/fs/WindowsSecurity.java \ + sun/nio/fs/WindowsSecurityDescriptor.java \ + sun/nio/fs/WindowsUriSupport.java \ + sun/nio/fs/WindowsUserPrincipals.java \ + sun/nio/fs/WindowsWatchService.java FILES_c += \ + Iocp.c \ + RegistryFileTypeDetector.c \ + WindowsAsynchronousFileChannelImpl.c \ + WindowsAsynchronousServerSocketChannelImpl.c \ + WindowsAsynchronousSocketChannelImpl.c \ + WindowsNativeDispatcher.c \ WindowsSelectorImpl.c FILES_export += \ - sun/nio/ch/WindowsSelectorImpl.java + sun/nio/ch/Iocp.java \ + sun/nio/ch/WindowsAsynchronousFileChannelImpl.java \ + sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java \ + sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java \ + sun/nio/ch/WindowsSelectorImpl.java \ + sun/nio/fs/WindowsNativeDispatcher.java \ + sun/nio/fs/RegistryFileTypeDetector.java endif # PLATFORM = windows ifeq ($(PLATFORM), linux) FILES_java += \ sun/nio/ch/AbstractPollSelectorImpl.java \ + sun/nio/ch/EPoll.java \ sun/nio/ch/EPollArrayWrapper.java \ + sun/nio/ch/EPollPort.java \ sun/nio/ch/EPollSelectorProvider.java \ sun/nio/ch/EPollSelectorImpl.java \ sun/nio/ch/InheritedChannel.java \ + sun/nio/ch/LinuxAsynchronousChannelProvider.java \ sun/nio/ch/PollSelectorProvider.java \ - sun/nio/ch/PollSelectorImpl.java + sun/nio/ch/PollSelectorImpl.java \ + sun/nio/ch/Port.java \ + sun/nio/ch/SimpleAsynchronousFileChannelImpl.java \ + sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \ + sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \ + \ + sun/nio/fs/GnomeFileTypeDetector.java \ + sun/nio/fs/LinuxDosFileAttributeView.java \ + sun/nio/fs/LinuxFileStore.java \ + sun/nio/fs/LinuxFileSystem.java \ + sun/nio/fs/LinuxFileSystemProvider.java \ + sun/nio/fs/LinuxUserDefinedFileAttributeView.java \ + sun/nio/fs/LinuxNativeDispatcher.java \ + sun/nio/fs/LinuxWatchService.java \ + sun/nio/fs/PollingWatchService.java \ + sun/nio/fs/UnixChannelFactory.java \ + sun/nio/fs/UnixCopyFile.java \ + sun/nio/fs/UnixDirectoryStream.java \ + sun/nio/fs/UnixException.java \ + sun/nio/fs/UnixFileAttributeViews.java \ + sun/nio/fs/UnixFileAttributes.java \ + sun/nio/fs/UnixFileKey.java \ + sun/nio/fs/UnixFileModeAttribute.java \ + sun/nio/fs/UnixFileStore.java \ + sun/nio/fs/UnixFileStoreAttributes.java \ + sun/nio/fs/UnixFileSystem.java \ + sun/nio/fs/UnixFileSystemProvider.java \ + sun/nio/fs/UnixMountEntry.java \ + sun/nio/fs/UnixNativeDispatcher.java \ + sun/nio/fs/UnixPath.java \ + sun/nio/fs/UnixSecureDirectoryStream.java \ + sun/nio/fs/UnixUriUtils.java \ + sun/nio/fs/UnixUserPrincipals.java FILES_c += \ + EPoll.c \ EPollArrayWrapper.c \ + EPollPort.c \ InheritedChannel.c \ NativeThread.c \ - PollArrayWrapper.c + PollArrayWrapper.c \ + UnixAsynchronousServerSocketChannelImpl.c \ + UnixAsynchronousSocketChannelImpl.c \ + \ + GnomeFileTypeDetector.c \ + LinuxNativeDispatcher.c \ + LinuxWatchService.c \ + UnixCopyFile.c \ + UnixNativeDispatcher.c FILES_export += \ + sun/nio/ch/EPoll.java \ sun/nio/ch/EPollArrayWrapper.java \ + sun/nio/ch/EPollPort.java \ sun/nio/ch/InheritedChannel.java \ - sun/nio/ch/NativeThread.java + sun/nio/ch/NativeThread.java \ + sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \ + sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \ + \ + sun/nio/fs/GnomeFileTypeDetector.java \ + sun/nio/fs/LinuxNativeDispatcher.java \ + sun/nio/fs/LinuxWatchService.java \ + sun/nio/fs/UnixCopyFile.java \ + sun/nio/fs/UnixNativeDispatcher.java + +FILES_gen += \ + sun/nio/fs/UnixConstants.java endif # PLATFORM = linux +# # Find platform-specific C source files # +vpath %.c $(PLATFORM_SRC)/native/sun/nio/fs vpath %.c $(PLATFORM_SRC)/native/sun/nio/ch vpath %.c $(SHARE_SRC)/native/sun/nio/ch @@ -175,12 +333,14 @@ CH_SRC=$(NIO_SRC)/channels CS_SRC=$(NIO_SRC)/charset SCH_SRC=$(SNIO_SRC)/ch SCS_SRC=$(SNIO_SRC)/cs +SFS_SRC=$(SNIO_SRC)/fs BUF_GEN=$(NIO_GEN) CH_GEN=$(NIO_GEN)/channels CS_GEN=$(NIO_GEN)/charset SCH_GEN=$(SNIO_GEN)/ch SCS_GEN=$(SNIO_GEN)/cs +SFS_GEN=$(SNIO_GEN)/fs FILES_gensbcs_out = $(FILES_gen_sbcs:%.java=$(GENSRCDIR)/%.java) @@ -670,4 +830,40 @@ $(FILES_gensbcs_out): $(GENCSSRC)/SingleByte-X.java $(GENCSSRC)/sbcs $(BOOT_JAVA_CMD) -cp $(CHARSETMAPPING_JARFILE) build.tools.charsetmapping.GenerateSBCS \ $(GENCSSRC) $(SCS_GEN) sbcs +# +# Generated file system implementation classes (Unix only) +# + +GENUC_SRC = $(PLATFORM_SRC)/native/sun/nio/fs/genUnixConstants.c + +GENUC_EXE = $(TEMPDIR)/genUnixConstants + +GENUC_COPYRIGHT_YEARS = $(shell $(CAT) $(GENUC_SRC) | \ + $(NAWK) '/^.*Copyright.*Sun/ { print $$3 }') + +$(GENUC_EXE) : $(GENUC_SRC) + $(prep-target) + $(CC) $(CPPFLAGS) -o $@ $(GENUC_SRC) + +$(SFS_GEN)/UnixConstants.java: $(GENUC_EXE) + $(prep-target) + NAWK="$(NAWK)" SH="$(SH)" $(SH) -e addNotices.sh $(GENUC_COPYRIGHT_YEARS) > $@ + $(GENUC_EXE) >> $@ + +GENSC_SRC = $(PLATFORM_SRC)/native/sun/nio/fs/genSolarisConstants.c + +GENSC_EXE = $(TEMPDIR)/genSolarisConstants + +GENSC_COPYRIGHT_YEARS = $(shell $(CAT) $(GENSC_SRC) | \ + $(NAWK) '/^.*Copyright.*Sun/ { print $$3 }') + +$(GENSC_EXE) : $(GENSC_SRC) + $(prep-target) + $(CC) $(CPPFLAGS) -o $@ $(GENSC_SRC) + +$(SFS_GEN)/SolarisConstants.java: $(GENSC_EXE) + $(prep-target) + NAWK="$(NAWK)" SH="$(SH)" $(SH) -e addNotices.sh $(GENSC_COPYRIGHT_YEARS) > $@ + $(GENSC_EXE) >> $@ + .PHONY: sources diff --git a/jdk/make/java/nio/mapfile-linux b/jdk/make/java/nio/mapfile-linux index 3fb47b0eb7c..0bd240811c5 100644 --- a/jdk/make/java/nio/mapfile-linux +++ b/jdk/make/java/nio/mapfile-linux @@ -1,5 +1,5 @@ # -# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -44,27 +44,38 @@ SUNWprivate_1.1 { Java_sun_nio_ch_EPollArrayWrapper_interrupt; Java_sun_nio_ch_EPollArrayWrapper_offsetofData; Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent; + Java_sun_nio_ch_EPoll_init; + Java_sun_nio_ch_EPoll_eventSize; + Java_sun_nio_ch_EPoll_eventsOffset; + Java_sun_nio_ch_EPoll_dataOffset; + Java_sun_nio_ch_EPoll_epollCreate; + Java_sun_nio_ch_EPoll_epollCtl; + Java_sun_nio_ch_EPoll_epollWait; + Java_sun_nio_ch_EPollPort_close0; + Java_sun_nio_ch_EPollPort_drain1; + Java_sun_nio_ch_EPollPort_interrupt; + Java_sun_nio_ch_EPollPort_socketpair; Java_sun_nio_ch_FileChannelImpl_close0; - Java_sun_nio_ch_FileChannelImpl_force0; Java_sun_nio_ch_FileChannelImpl_initIDs; - Java_sun_nio_ch_FileChannelImpl_lock0; Java_sun_nio_ch_FileChannelImpl_map0; Java_sun_nio_ch_FileChannelImpl_position0; - Java_sun_nio_ch_FileChannelImpl_release0; - Java_sun_nio_ch_FileChannelImpl_size0; Java_sun_nio_ch_FileChannelImpl_transferTo0; - Java_sun_nio_ch_FileChannelImpl_truncate0; Java_sun_nio_ch_FileChannelImpl_unmap0; - Java_sun_nio_ch_FileDispatcher_close0; - Java_sun_nio_ch_FileDispatcher_closeIntFD; - Java_sun_nio_ch_FileDispatcher_init; - Java_sun_nio_ch_FileDispatcher_preClose0; - Java_sun_nio_ch_FileDispatcher_pread0; - Java_sun_nio_ch_FileDispatcher_pwrite0; - Java_sun_nio_ch_FileDispatcher_read0; - Java_sun_nio_ch_FileDispatcher_readv0; - Java_sun_nio_ch_FileDispatcher_write0; - Java_sun_nio_ch_FileDispatcher_writev0; + Java_sun_nio_ch_FileDispatcherImpl_close0; + Java_sun_nio_ch_FileDispatcherImpl_closeIntFD; + Java_sun_nio_ch_FileDispatcherImpl_force0; + Java_sun_nio_ch_FileDispatcherImpl_init; + Java_sun_nio_ch_FileDispatcherImpl_lock0; + Java_sun_nio_ch_FileDispatcherImpl_preClose0; + Java_sun_nio_ch_FileDispatcherImpl_pread0; + Java_sun_nio_ch_FileDispatcherImpl_pwrite0; + Java_sun_nio_ch_FileDispatcherImpl_read0; + Java_sun_nio_ch_FileDispatcherImpl_readv0; + Java_sun_nio_ch_FileDispatcherImpl_release0; + Java_sun_nio_ch_FileDispatcherImpl_size0; + Java_sun_nio_ch_FileDispatcherImpl_truncate0; + Java_sun_nio_ch_FileDispatcherImpl_write0; + Java_sun_nio_ch_FileDispatcherImpl_writev0; Java_sun_nio_ch_FileKey_init; Java_sun_nio_ch_FileKey_initIDs; Java_sun_nio_ch_InheritedChannel_close0; @@ -108,6 +119,76 @@ SUNWprivate_1.1 { Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_initIDs; Java_sun_nio_ch_SocketChannelImpl_checkConnect; + Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0; + Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs; + Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect; + Java_sun_nio_fs_GnomeFileTypeDetector_initializeGio; + Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGio; + Java_sun_nio_fs_GnomeFileTypeDetector_initializeGnomeVfs; + Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGnomeVfs; + Java_sun_nio_fs_LinuxWatchService_init; + Java_sun_nio_fs_LinuxWatchService_eventSize; + Java_sun_nio_fs_LinuxWatchService_eventOffsets; + Java_sun_nio_fs_LinuxWatchService_inotifyInit; + Java_sun_nio_fs_LinuxWatchService_inotifyAddWatch; + Java_sun_nio_fs_LinuxWatchService_inotifyRmWatch; + Java_sun_nio_fs_LinuxWatchService_configureBlocking; + Java_sun_nio_fs_LinuxWatchService_socketpair; + Java_sun_nio_fs_LinuxWatchService_poll; + Java_sun_nio_fs_LinuxNativeDispatcher_init; + Java_sun_nio_fs_LinuxNativeDispatcher_fgetxattr0; + Java_sun_nio_fs_LinuxNativeDispatcher_flistxattr; + Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0; + Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0; + Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0; + Java_sun_nio_fs_LinuxNativeDispatcher_endmntent; + Java_sun_nio_fs_UnixNativeDispatcher_initIDs; + Java_sun_nio_fs_UnixNativeDispatcher_getcwd; + Java_sun_nio_fs_UnixNativeDispatcher_strerror; + Java_sun_nio_fs_UnixNativeDispatcher_dup; + Java_sun_nio_fs_UnixNativeDispatcher_access0; + Java_sun_nio_fs_UnixNativeDispatcher_stat0; + Java_sun_nio_fs_UnixNativeDispatcher_lstat0; + Java_sun_nio_fs_UnixNativeDispatcher_fstat; + Java_sun_nio_fs_UnixNativeDispatcher_fstatat0; + Java_sun_nio_fs_UnixNativeDispatcher_chmod0; + Java_sun_nio_fs_UnixNativeDispatcher_fchmod; + Java_sun_nio_fs_UnixNativeDispatcher_chown0; + Java_sun_nio_fs_UnixNativeDispatcher_lchown0; + Java_sun_nio_fs_UnixNativeDispatcher_fchown; + Java_sun_nio_fs_UnixNativeDispatcher_utimes0; + Java_sun_nio_fs_UnixNativeDispatcher_futimes; + Java_sun_nio_fs_UnixNativeDispatcher_open0; + Java_sun_nio_fs_UnixNativeDispatcher_openat0; + Java_sun_nio_fs_UnixNativeDispatcher_close; + Java_sun_nio_fs_UnixNativeDispatcher_read; + Java_sun_nio_fs_UnixNativeDispatcher_write; + Java_sun_nio_fs_UnixNativeDispatcher_fopen0; + Java_sun_nio_fs_UnixNativeDispatcher_fclose; + Java_sun_nio_fs_UnixNativeDispatcher_opendir0; + Java_sun_nio_fs_UnixNativeDispatcher_fdopendir; + Java_sun_nio_fs_UnixNativeDispatcher_readdir; + Java_sun_nio_fs_UnixNativeDispatcher_closedir; + Java_sun_nio_fs_UnixNativeDispatcher_link0; + Java_sun_nio_fs_UnixNativeDispatcher_unlink0; + Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0; + Java_sun_nio_fs_UnixNativeDispatcher_rename0; + Java_sun_nio_fs_UnixNativeDispatcher_renameat0; + Java_sun_nio_fs_UnixNativeDispatcher_mkdir0; + Java_sun_nio_fs_UnixNativeDispatcher_rmdir0; + Java_sun_nio_fs_UnixNativeDispatcher_symlink0; + Java_sun_nio_fs_UnixNativeDispatcher_readlink0; + Java_sun_nio_fs_UnixNativeDispatcher_realpath0; + Java_sun_nio_fs_UnixNativeDispatcher_statvfs0; + Java_sun_nio_fs_UnixNativeDispatcher_pathconf0; + Java_sun_nio_fs_UnixNativeDispatcher_fpathconf; + Java_sun_nio_fs_UnixNativeDispatcher_mknod0; + Java_sun_nio_fs_UnixNativeDispatcher_getpwuid; + Java_sun_nio_fs_UnixNativeDispatcher_getgrgid; + Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0; + Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0; + Java_sun_nio_fs_UnixNativeDispatcher_getextmntent; + Java_sun_nio_fs_UnixCopyFile_transfer; local: *; diff --git a/jdk/make/java/nio/mapfile-solaris b/jdk/make/java/nio/mapfile-solaris index 6e109e2faba..2192a5a7751 100644 --- a/jdk/make/java/nio/mapfile-solaris +++ b/jdk/make/java/nio/mapfile-solaris @@ -1,5 +1,5 @@ # -# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -43,26 +43,26 @@ SUNWprivate_1.1 { Java_sun_nio_ch_DevPollArrayWrapper_register; Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple; Java_sun_nio_ch_FileChannelImpl_close0; - Java_sun_nio_ch_FileChannelImpl_force0; Java_sun_nio_ch_FileChannelImpl_initIDs; - Java_sun_nio_ch_FileChannelImpl_lock0; Java_sun_nio_ch_FileChannelImpl_map0; Java_sun_nio_ch_FileChannelImpl_position0; - Java_sun_nio_ch_FileChannelImpl_release0; - Java_sun_nio_ch_FileChannelImpl_size0; Java_sun_nio_ch_FileChannelImpl_transferTo0; - Java_sun_nio_ch_FileChannelImpl_truncate0; Java_sun_nio_ch_FileChannelImpl_unmap0; - Java_sun_nio_ch_FileDispatcher_close0; - Java_sun_nio_ch_FileDispatcher_closeIntFD; - Java_sun_nio_ch_FileDispatcher_init; - Java_sun_nio_ch_FileDispatcher_preClose0; - Java_sun_nio_ch_FileDispatcher_pread0; - Java_sun_nio_ch_FileDispatcher_pwrite0; - Java_sun_nio_ch_FileDispatcher_read0; - Java_sun_nio_ch_FileDispatcher_readv0; - Java_sun_nio_ch_FileDispatcher_write0; - Java_sun_nio_ch_FileDispatcher_writev0; + Java_sun_nio_ch_FileDispatcherImpl_close0; + Java_sun_nio_ch_FileDispatcherImpl_closeIntFD; + Java_sun_nio_ch_FileDispatcherImpl_force0; + Java_sun_nio_ch_FileDispatcherImpl_init; + Java_sun_nio_ch_FileDispatcherImpl_lock0; + Java_sun_nio_ch_FileDispatcherImpl_preClose0; + Java_sun_nio_ch_FileDispatcherImpl_pread0; + Java_sun_nio_ch_FileDispatcherImpl_pwrite0; + Java_sun_nio_ch_FileDispatcherImpl_read0; + Java_sun_nio_ch_FileDispatcherImpl_readv0; + Java_sun_nio_ch_FileDispatcherImpl_release0; + Java_sun_nio_ch_FileDispatcherImpl_size0; + Java_sun_nio_ch_FileDispatcherImpl_truncate0; + Java_sun_nio_ch_FileDispatcherImpl_write0; + Java_sun_nio_ch_FileDispatcherImpl_writev0; Java_sun_nio_ch_FileKey_init; Java_sun_nio_ch_FileKey_initIDs; Java_sun_nio_ch_InheritedChannel_close0; @@ -106,6 +106,75 @@ SUNWprivate_1.1 { Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_initIDs; Java_sun_nio_ch_SocketChannelImpl_checkConnect; + Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0; + Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs; + Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect; + Java_sun_nio_ch_SolarisEventPort_init; + Java_sun_nio_ch_SolarisEventPort_portCreate; + Java_sun_nio_ch_SolarisEventPort_portClose; + Java_sun_nio_ch_SolarisEventPort_portAssociate; + Java_sun_nio_ch_SolarisEventPort_portGet; + Java_sun_nio_ch_SolarisEventPort_portGetn; + Java_sun_nio_ch_SolarisEventPort_portSend; + Java_sun_nio_fs_GnomeFileTypeDetector_initializeGio; + Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGio; + Java_sun_nio_fs_GnomeFileTypeDetector_initializeGnomeVfs; + Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGnomeVfs; + Java_sun_nio_fs_UnixNativeDispatcher_initIDs; + Java_sun_nio_fs_UnixNativeDispatcher_getcwd; + Java_sun_nio_fs_UnixNativeDispatcher_strerror; + Java_sun_nio_fs_UnixNativeDispatcher_dup; + Java_sun_nio_fs_UnixNativeDispatcher_access0; + Java_sun_nio_fs_UnixNativeDispatcher_stat0; + Java_sun_nio_fs_UnixNativeDispatcher_lstat0; + Java_sun_nio_fs_UnixNativeDispatcher_fstat; + Java_sun_nio_fs_UnixNativeDispatcher_fstatat0; + Java_sun_nio_fs_UnixNativeDispatcher_chmod0; + Java_sun_nio_fs_UnixNativeDispatcher_fchmod; + Java_sun_nio_fs_UnixNativeDispatcher_chown0; + Java_sun_nio_fs_UnixNativeDispatcher_lchown0; + Java_sun_nio_fs_UnixNativeDispatcher_fchown; + Java_sun_nio_fs_UnixNativeDispatcher_utimes0; + Java_sun_nio_fs_UnixNativeDispatcher_futimes; + Java_sun_nio_fs_UnixNativeDispatcher_open0; + Java_sun_nio_fs_UnixNativeDispatcher_openat0; + Java_sun_nio_fs_UnixNativeDispatcher_close; + Java_sun_nio_fs_UnixNativeDispatcher_read; + Java_sun_nio_fs_UnixNativeDispatcher_write; + Java_sun_nio_fs_UnixNativeDispatcher_fopen0; + Java_sun_nio_fs_UnixNativeDispatcher_fclose; + Java_sun_nio_fs_UnixNativeDispatcher_opendir0; + Java_sun_nio_fs_UnixNativeDispatcher_fdopendir; + Java_sun_nio_fs_UnixNativeDispatcher_readdir; + Java_sun_nio_fs_UnixNativeDispatcher_closedir; + Java_sun_nio_fs_UnixNativeDispatcher_link0; + Java_sun_nio_fs_UnixNativeDispatcher_unlink0; + Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0; + Java_sun_nio_fs_UnixNativeDispatcher_rename0; + Java_sun_nio_fs_UnixNativeDispatcher_renameat0; + Java_sun_nio_fs_UnixNativeDispatcher_mkdir0; + Java_sun_nio_fs_UnixNativeDispatcher_rmdir0; + Java_sun_nio_fs_UnixNativeDispatcher_symlink0; + Java_sun_nio_fs_UnixNativeDispatcher_readlink0; + Java_sun_nio_fs_UnixNativeDispatcher_realpath0; + Java_sun_nio_fs_UnixNativeDispatcher_statvfs0; + Java_sun_nio_fs_UnixNativeDispatcher_pathconf0; + Java_sun_nio_fs_UnixNativeDispatcher_fpathconf; + Java_sun_nio_fs_UnixNativeDispatcher_mknod0; + Java_sun_nio_fs_UnixNativeDispatcher_getpwuid; + Java_sun_nio_fs_UnixNativeDispatcher_getgrgid; + Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0; + Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0; + Java_sun_nio_fs_UnixNativeDispatcher_getextmntent; + Java_sun_nio_fs_UnixCopyFile_transfer; + Java_sun_nio_fs_SolarisNativeDispatcher_init; + Java_sun_nio_fs_SolarisNativeDispatcher_facl; + Java_sun_nio_fs_SolarisWatchService_init; + Java_sun_nio_fs_SolarisWatchService_portCreate; + Java_sun_nio_fs_SolarisWatchService_portAssociate; + Java_sun_nio_fs_SolarisWatchService_portDissociate; + Java_sun_nio_fs_SolarisWatchService_portSend; + Java_sun_nio_fs_SolarisWatchService_portGetn; local: *; diff --git a/jdk/make/java/redist/Makefile b/jdk/make/java/redist/Makefile index 159c247b3f3..9ab884dd247 100644 --- a/jdk/make/java/redist/Makefile +++ b/jdk/make/java/redist/Makefile @@ -251,9 +251,11 @@ endif # INCLUDE_SA # ifdef OPENJDK -include $(BUILDDIR)/common/internal/BinaryPlugs.gmk + ifeq ($(IMPORT_BINARY_PLUGS),true) + include $(BUILDDIR)/common/internal/BinaryPlugs.gmk -build: import-binary-plugs + build: import-binary-plugs + endif else # !OPENJDK diff --git a/jdk/make/java/text/FILES_java.gmk b/jdk/make/java/text/FILES_java.gmk index 67b4c19c66e..88dc12903cc 100644 --- a/jdk/make/java/text/FILES_java.gmk +++ b/jdk/make/java/text/FILES_java.gmk @@ -92,11 +92,11 @@ FILES_java = \ sun/text/normalizer/SymbolTable.java \ sun/text/normalizer/Trie.java \ sun/text/normalizer/TrieIterator.java \ + sun/text/normalizer/UBiDiProps.java \ sun/text/normalizer/UCharacter.java \ sun/text/normalizer/UCharacterIterator.java \ sun/text/normalizer/UCharacterProperty.java \ sun/text/normalizer/UCharacterPropertyReader.java \ - sun/text/normalizer/UProperty.java \ sun/text/normalizer/UTF16.java \ sun/text/normalizer/UnicodeMatcher.java \ sun/text/normalizer/UnicodeSet.java \ diff --git a/jdk/make/java/text/Makefile b/jdk/make/java/text/Makefile index 76955e22d81..4db338926f3 100644 --- a/jdk/make/java/text/Makefile +++ b/jdk/make/java/text/Makefile @@ -64,7 +64,8 @@ BIFILES = $(TEXT_CLASSDIR)/CharacterBreakIteratorData \ $(TEXT_CLASSDIR)/SentenceBreakIteratorData ICU_FILES = $(TEXT_CLASSDIR)/unorm.icu \ - $(TEXT_CLASSDIR)/uprops.icu + $(TEXT_CLASSDIR)/uprops.icu \ + $(TEXT_CLASSDIR)/ubidi.icu # builder GENERATEBREAKITERATORDATA_JARFILE = \ @@ -89,7 +90,7 @@ $(BIFILES): $(GENERATEBREAKITERATORDATA_JARFILE) \ build: $(BIFILES) $(ICU_FILES) # -# Extra rules to copy unorm.icu and uprops.icu +# Extra rules to copy unorm.icu, uprops.icu, and ubidi.icu # $(TEXT_CLASSDIR)/unorm.icu: $(TEXT_SRCDIR)/unorm.icu $(install-file) @@ -97,6 +98,9 @@ $(TEXT_CLASSDIR)/unorm.icu: $(TEXT_SRCDIR)/unorm.icu $(TEXT_CLASSDIR)/uprops.icu: $(TEXT_SRCDIR)/uprops.icu $(install-file) +$(TEXT_CLASSDIR)/ubidi.icu: $(TEXT_SRCDIR)/ubidi.icu + $(install-file) + clean clobber:: $(RM) -r $(TEXT_CLASSES) $(RM) -r $(BIFILES) diff --git a/jdk/make/javax/management/Makefile b/jdk/make/javax/management/Makefile index 2085e38a88b..02527ec2d21 100644 --- a/jdk/make/javax/management/Makefile +++ b/jdk/make/javax/management/Makefile @@ -35,6 +35,7 @@ include $(BUILDDIR)/common/Defs.gmk # # Files to compile # +AUTO_JAVA_PRUNE = snmp AUTO_FILES_JAVA_DIRS = javax/management com/sun/jmx com/sun/management/jmx # diff --git a/jdk/make/javax/swing/beaninfo/SwingBeans.gmk b/jdk/make/javax/swing/beaninfo/SwingBeans.gmk index 66f16aae1a1..cae9873e0c3 100644 --- a/jdk/make/javax/swing/beaninfo/SwingBeans.gmk +++ b/jdk/make/javax/swing/beaninfo/SwingBeans.gmk @@ -47,7 +47,7 @@ swing-1.2-beans-debug: LOCAL_JAVADOC = $(JAVADOC_CMD) $(JAVADOCFLAGS) # get the absolute path to the jar command. PREFIX = 1.2 -JAVADOCFLAGS = $(LANGUAGE_VERSION) +JAVADOCFLAGS = $(NO_PROPRIETARY_API_WARNINGS) $(LANGUAGE_VERSION) SWINGPKG = javax/swing LOCAL_JAVAC_FLAGS = $(OTHER_JAVACFLAGS) diff --git a/jdk/make/jdk_generic_profile.sh b/jdk/make/jdk_generic_profile.sh index 32dd86197ef..125198301ca 100644 --- a/jdk/make/jdk_generic_profile.sh +++ b/jdk/make/jdk_generic_profile.sh @@ -174,7 +174,8 @@ else # Check CYGWIN (should have already been done) # Assumption here is that you are in a shell window via cygwin. - if [ "$(echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64)" != "" ] ; then + proc_arch=`echo "$(PROCESSOR_IDENTIFIER)" | expand | cut -d' ' -f1 | sed -e 's@x86@X86@g' -e 's@Intel64@X64@g' -e 's@em64t@X64@g' -e 's@EM64T@X64@g' -e 's@amd64@X64@g' -e 's@AMD64@X64@g' -e 's@ia64@IA64@g'` + if [ "${proc_arch}" = "X64" ] ; then windows_arch=amd64 else windows_arch=i586 diff --git a/jdk/make/jprt.config b/jdk/make/jprt.config deleted file mode 100644 index d720475cecd..00000000000 --- a/jdk/make/jprt.config +++ /dev/null @@ -1,363 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# OPENJDK -# Windows Only: -# PATH -# VS71COMNTOOLS -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# compiler_path Path to compiler bin directory -# compiler_name Unique name of this compiler -# -# Output environment variables: -# PATH -# ALT_COMPILER_PATH -# OPENJDK only: -# ALT_CLOSED_JDK_IMPORT_PATH -# ALT_JDK_DEVTOOLS_DIR -# Windows Only: -# ALT_MSDEVTOOLS_PATH -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# LIB -# INCLUDE -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -# On Windows AMD64, if MSSDK is not set, assumes Platform SDK is installed at: -# C:/Program Files/Microsoft Platform SDK -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# The /java/devtools items -jdk_devtools="${slashjava}/devtools" -share="${jdk_devtools}/share" - -# Needed for langtools, maybe other parts of the build -ANT_HOME="${share}/ant/latest" -export ANT_HOME - -# The 3 bin directories in common to all platforms -sharebin="${share}/bin" -antbin="${ANT_HOME}/bin" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH -dirMustExist "${ANT_HOME}" ANT_HOME - -# Use the JDK import for now (FIXME: use the binary plugs?) -if [ "${OPENJDK}" = true ] ; then - ALT_CLOSED_JDK_IMPORT_PATH="${jdk_import}" - export ALT_CLOSED_JDK_IMPORT_PATH -fi - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Get the compilers into path (make sure it matches ALT setting) - if [ "${JPRT_SOLARIS_COMPILER_NAME}" != "" ] ; then - compiler_name=${JPRT_SOLARIS_COMPILER_NAME} - else - compiler_name=SS12 - fi - compiler_path=${jdk_devtools}/${solaris_arch}/SUNWspro/${compiler_name}/bin - ALT_COMPILER_PATH="${compiler_path}" - export ALT_COMPILER_PATH - dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin} - - # Add basic solaris system paths - path4sdk=${path4sdk}:/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${jdk_devtools}/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Get the compilers into path (make sure it matches ALT setting) - compiler_path=/usr/bin - compiler_name=usr_bin - ALT_COMPILER_PATH="${compiler_path}" - export ALT_COMPILER_PATH - dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin} - - # Add basic paths - path4sdk=${path4sdk}:/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - - # Linux platform may be old, use motif files from the devtools area - if [ "${OPENJDK}" = true ] ; then - ALT_JDK_DEVTOOLS_DIR="${jdk_devtools}" - export ALT_JDK_DEVTOOLS_DIR - fi - - -else - - # Windows: Differs on CYGWIN vs. MKS, and the compiler available. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${sharebin};${antbin};${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${jdk_devtools}/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${sharebin};${antbin};${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Compiler setup (nasty part) - # NOTE: You can use vcvars32.bat to set PATH, LIB, and INCLUDE. - # NOTE: CYGWIN has a link.exe too, make sure the compilers are first - if [ "${windows_arch}" = i586 ] ; then - # 32bit Windows compiler settings - # VisualStudio .NET 2003 VC++ 7.1 (VS71COMNTOOLS should be defined) - vs_root=`${dosname} "${VS71COMNTOOLS}/../.."` - # Fill in PATH, LIB, and INCLUDE (unset all others to make sure) - msdev_root="${vs_root}/Common7/Tools" - msdevtools_path="${msdev_root}/bin" - vc7_root="${vs_root}/Vc7" - compiler_path="${vc7_root}/bin" - compiler_name=VS2003 - platform_sdk="${vc7_root}/PlatformSDK" - # LIB and INCLUDE must use ; as a separator - include4sdk="${vc7_root}/atlmfc/include" - include4sdk="${include4sdk};${vc7_root}/include" - include4sdk="${include4sdk};${platform_sdk}/include/prerelease" - include4sdk="${include4sdk};${platform_sdk}/include" - include4sdk="${include4sdk};${vs_root}/SDK/v1.1/include" - lib4sdk="${vc7_root}/atlmfc/lib" - lib4sdk="${lib4sdk};${vc7_root}/lib" - lib4sdk="${lib4sdk};${platform_sdk}/lib/prerelease" - lib4sdk="${lib4sdk};${platform_sdk}/lib" - lib4sdk="${lib4sdk};${vs_root}/SDK/v1.1/lib" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${vs_root}/Common7/Tools/bin;${path4sdk}" - path4sdk="${vs_root}/SDK/v1.1/bin;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools/bin/prerelease;${path4sdk}" - path4sdk="${vs_root}/Common7/IDE;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - elif [ "${windows_arch}" = amd64 ] ; then - # AMD64 64bit Windows compiler settings - if [ "${MSSDK}" != "" ] ; then - platform_sdk="${MSSDK}" - else - platform_sdk=`${dosname} "C:/Program Files/Microsoft Platform SDK/"` - fi - compiler_path="${platform_sdk}/Bin/win64/x86/AMD64" - compiler_name=VS2005_PSDK - msdevtools_path="${platform_sdk}/Bin" - # LIB and INCLUDE must use ; as a separator - include4sdk="${platform_sdk}/Include" - include4sdk="${include4sdk};${platform_sdk}/Include/crt/sys" - include4sdk="${include4sdk};${platform_sdk}/Include/mfc" - include4sdk="${include4sdk};${platform_sdk}/Include/atl" - include4sdk="${include4sdk};${platform_sdk}/Include/crt" - lib4sdk="${platform_sdk}/Lib/AMD64" - lib4sdk="${lib4sdk};${platform_sdk}/Lib/AMD64/atlmfc" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${platform_sdk}/bin;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - fi - # Export LIB and INCLUDE - unset lib - unset Lib - LIB="${lib4sdk}" - export LIB - unset include - unset Include - INCLUDE="${include4sdk}" - export INCLUDE - # Set the ALT variable - ALT_COMPILER_PATH=`${dosname} "${compiler_path}"` - export ALT_COMPILER_PATH - dirMustExist "${compiler_path}" ALT_COMPILER_PATH - ALT_MSDEVTOOLS_PATH=`${dosname} "${msdevtools_path}"` - export ALT_MSDEVTOOLS_PATH - dirMustExist "${msdevtools_path}" ALT_MSDEVTOOLS_PATH - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - - # Set special windows ALT variables - ALT_ISHIELDDIR="C:/ishield802" - export ALT_ISHIELDDIR - - # Sponsors binaries - ALT_SPONSOR1DIR=C:/sponsor_binaries - export ALT_SPONSOR1DIR - ALT_SPONSOR2DIR=C:/sponsor_binaries - export ALT_SPONSOR2DIR - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - diff --git a/jdk/make/jprt.properties b/jdk/make/jprt.properties index c909f36aa3c..a1e7e5100ba 100644 --- a/jdk/make/jprt.properties +++ b/jdk/make/jprt.properties @@ -53,6 +53,19 @@ jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 # Standard list of jprt test targets for this workspace jprt.test.targets=*-*-*-jvm98 +jprt.regression.test.targets= \ + *-*-*-java/lang, \ + *-*-*-java/security, \ + *-*-*-java/text, \ + *-*-*-java/util + +#jprt.regression.test.targets= \ +# *-*-*-java/awt, \ +# *-*-*-java/beans, \ +# *-*-*-java/io, \ +# *-*-*-java/net, \ +# *-*-*-java/nio, \ +# *-*-*-java/rmi, \ # Directories needed to build jprt.bundle.exclude.src.dirs=build diff --git a/jdk/make/mksample/nio/Makefile b/jdk/make/mksample/nio/Makefile index e05106293bb..5fcfd03a783 100644 --- a/jdk/make/mksample/nio/Makefile +++ b/jdk/make/mksample/nio/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ BUILDDIR = ../.. PRODUCT = java include $(BUILDDIR)/common/Defs.gmk -SUBDIRS = multicast server +SUBDIRS = file multicast server all build clean clobber:: $(SUBDIRS-loop) diff --git a/jdk/make/mksample/nio/file/Makefile b/jdk/make/mksample/nio/file/Makefile new file mode 100644 index 00000000000..f7159de83a3 --- /dev/null +++ b/jdk/make/mksample/nio/file/Makefile @@ -0,0 +1,56 @@ +# +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# Makefile for the nio/file sample code +# + +BUILDDIR = ../../.. + +PRODUCT = java + +include $(BUILDDIR)/common/Defs.gmk + +SAMPLE_SRC_DIR = $(SHARE_SRC)/sample/nio/file +SAMPLE_DST_DIR = $(SAMPLEDIR)/nio/file + +SAMPLE_FILES = \ + $(SAMPLE_DST_DIR)/AclEdit.java \ + $(SAMPLE_DST_DIR)/Chmod.java \ + $(SAMPLE_DST_DIR)/Copy.java \ + $(SAMPLE_DST_DIR)/DiskUsage.java \ + $(SAMPLE_DST_DIR)/FileType.java \ + $(SAMPLE_DST_DIR)/WatchDir.java \ + $(SAMPLE_DST_DIR)/Xdd.java + +all build: $(SAMPLE_FILES) + +$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/% + $(install-file) + +clean clobber: + $(RM) -r $(SAMPLE_DST_DIR) + +.PHONY: all build clean clobber diff --git a/jdk/make/sun/awt/Makefile b/jdk/make/sun/awt/Makefile index cd89650a597..c3c1745ff54 100644 --- a/jdk/make/sun/awt/Makefile +++ b/jdk/make/sun/awt/Makefile @@ -340,8 +340,7 @@ ifeq ($(PLATFORM), windows) FONTCONFIGS_SRC = $(PLATFORM_SRC)/classes/sun/awt/windows _FONTCONFIGS = \ - fontconfig.properties \ - fontconfig.98.properties + fontconfig.properties FONTCONFIGS_SRC_PREFIX = diff --git a/jdk/make/sun/management/Makefile b/jdk/make/sun/management/Makefile index 6ae5d85d817..bb7ad8935c9 100644 --- a/jdk/make/sun/management/Makefile +++ b/jdk/make/sun/management/Makefile @@ -35,7 +35,16 @@ MGMT_LIB_SRC = $(SHARE_SRC)/lib/management all build:: properties aclfile jmxremotefiles -SUBDIRS = snmp jmxremote +# When building the openjdk, build snmp only if importing binary plugs, +ifdef OPENJDK + ifeq ($(IMPORT_BINARY_PLUGS),true) + SUBDIRS = snmp + endif +else + SUBDIRS = snmp +endif +SUBDIRS += jmxremote + all build clean clobber:: $(SUBDIRS-loop) diff --git a/jdk/make/sun/net/FILES_java.gmk b/jdk/make/sun/net/FILES_java.gmk index 55b6477fc26..1ab771a37f1 100644 --- a/jdk/make/sun/net/FILES_java.gmk +++ b/jdk/make/sun/net/FILES_java.gmk @@ -39,6 +39,7 @@ FILES_java = \ sun/net/TransferProtocolClient.java \ sun/net/ConnectionResetException.java \ sun/net/NetProperties.java \ + sun/net/NetHooks.java \ sun/net/util/IPAddressUtil.java \ sun/net/dns/ResolverConfiguration.java \ sun/net/dns/ResolverConfigurationImpl.java \ @@ -123,3 +124,7 @@ FILES_java = \ ifeq ($(PLATFORM), windows) FILES_java += sun/net/www/protocol/http/NTLMAuthSequence.java endif + +ifeq ($(PLATFORM), solaris) + FILES_java += sun/net/spi/SdpProvider.java +endif diff --git a/jdk/make/sun/xawt/mapfile-vers b/jdk/make/sun/xawt/mapfile-vers index 8aaaef7f260..c117a097268 100644 --- a/jdk/make/sun/xawt/mapfile-vers +++ b/jdk/make/sun/xawt/mapfile-vers @@ -318,12 +318,14 @@ SUNWprivate_1.1 { Java_java_awt_FileDialog_initIDs; Java_sun_awt_X11_XWindow_initIDs; + Java_sun_java2d_opengl_OGLContext_getOGLIdString; Java_sun_java2d_opengl_OGLMaskFill_maskFill; Java_sun_java2d_opengl_OGLRenderer_drawPoly; Java_sun_java2d_opengl_OGLRenderQueue_flushBuffer; Java_sun_java2d_opengl_OGLSurfaceData_initTexture; Java_sun_java2d_opengl_OGLSurfaceData_initFBObject; Java_sun_java2d_opengl_OGLSurfaceData_initFlipBackbuffer; + Java_sun_java2d_opengl_OGLSurfaceData_getTextureID; Java_sun_java2d_opengl_OGLSurfaceData_getTextureTarget; Java_sun_java2d_opengl_OGLTextRenderer_drawGlyphList; Java_sun_java2d_opengl_GLXGraphicsConfig_getGLXConfigInfo; diff --git a/jdk/make/tools/GenerateCharacter/CharacterData00.java.template b/jdk/make/tools/GenerateCharacter/CharacterData00.java.template index c790f374ef6..554c7cf57cb 100644 --- a/jdk/make/tools/GenerateCharacter/CharacterData00.java.template +++ b/jdk/make/tools/GenerateCharacter/CharacterData00.java.template @@ -144,6 +144,55 @@ class CharacterData00 extends CharacterData { case 0x1FBC : mapChar = 0x1FB3; break; case 0x1FCC : mapChar = 0x1FC3; break; case 0x1FFC : mapChar = 0x1FF3; break; + + case 0x023A : mapChar = 0x2C65; break; + case 0x023E : mapChar = 0x2C66; break; + case 0x10A0 : mapChar = 0x2D00; break; + case 0x10A1 : mapChar = 0x2D01; break; + case 0x10A2 : mapChar = 0x2D02; break; + case 0x10A3 : mapChar = 0x2D03; break; + case 0x10A4 : mapChar = 0x2D04; break; + case 0x10A5 : mapChar = 0x2D05; break; + case 0x10A6 : mapChar = 0x2D06; break; + case 0x10A7 : mapChar = 0x2D07; break; + case 0x10A8 : mapChar = 0x2D08; break; + case 0x10A9 : mapChar = 0x2D09; break; + case 0x10AA : mapChar = 0x2D0A; break; + case 0x10AB : mapChar = 0x2D0B; break; + case 0x10AC : mapChar = 0x2D0C; break; + case 0x10AD : mapChar = 0x2D0D; break; + case 0x10AE : mapChar = 0x2D0E; break; + case 0x10AF : mapChar = 0x2D0F; break; + case 0x10B0 : mapChar = 0x2D10; break; + case 0x10B1 : mapChar = 0x2D11; break; + case 0x10B2 : mapChar = 0x2D12; break; + case 0x10B3 : mapChar = 0x2D13; break; + case 0x10B4 : mapChar = 0x2D14; break; + case 0x10B5 : mapChar = 0x2D15; break; + case 0x10B6 : mapChar = 0x2D16; break; + case 0x10B7 : mapChar = 0x2D17; break; + case 0x10B8 : mapChar = 0x2D18; break; + case 0x10B9 : mapChar = 0x2D19; break; + case 0x10BA : mapChar = 0x2D1A; break; + case 0x10BB : mapChar = 0x2D1B; break; + case 0x10BC : mapChar = 0x2D1C; break; + case 0x10BD : mapChar = 0x2D1D; break; + case 0x10BE : mapChar = 0x2D1E; break; + case 0x10BF : mapChar = 0x2D1F; break; + case 0x10C0 : mapChar = 0x2D20; break; + case 0x10C1 : mapChar = 0x2D21; break; + case 0x10C2 : mapChar = 0x2D22; break; + case 0x10C3 : mapChar = 0x2D23; break; + case 0x10C4 : mapChar = 0x2D24; break; + case 0x10C5 : mapChar = 0x2D25; break; + case 0x1E9E : mapChar = 0x00DF; break; + case 0x2C62 : mapChar = 0x026B; break; + case 0x2C63 : mapChar = 0x1D7D; break; + case 0x2C64 : mapChar = 0x027D; break; + case 0x2C6D : mapChar = 0x0251; break; + case 0x2C6E : mapChar = 0x0271; break; + case 0x2C6F : mapChar = 0x0250; break; + case 0xA77D : mapChar = 0x1D79; break; // default mapChar is already set, so no // need to redo it here. // default : mapChar = ch; @@ -196,6 +245,54 @@ class CharacterData00 extends CharacterData { case 0x1FB3 : mapChar = 0x1FBC; break; case 0x1FC3 : mapChar = 0x1FCC; break; case 0x1FF3 : mapChar = 0x1FFC; break; + + case 0x0250 : mapChar = 0x2C6F; break; + case 0x0251 : mapChar = 0x2C6D; break; + case 0x026B : mapChar = 0x2C62; break; + case 0x0271 : mapChar = 0x2C6E; break; + case 0x027D : mapChar = 0x2C64; break; + case 0x1D79 : mapChar = 0xA77D; break; + case 0x1D7D : mapChar = 0x2C63; break; + case 0x2C65 : mapChar = 0x023A; break; + case 0x2C66 : mapChar = 0x023E; break; + case 0x2D00 : mapChar = 0x10A0; break; + case 0x2D01 : mapChar = 0x10A1; break; + case 0x2D02 : mapChar = 0x10A2; break; + case 0x2D03 : mapChar = 0x10A3; break; + case 0x2D04 : mapChar = 0x10A4; break; + case 0x2D05 : mapChar = 0x10A5; break; + case 0x2D06 : mapChar = 0x10A6; break; + case 0x2D07 : mapChar = 0x10A7; break; + case 0x2D08 : mapChar = 0x10A8; break; + case 0x2D09 : mapChar = 0x10A9; break; + case 0x2D0A : mapChar = 0x10AA; break; + case 0x2D0B : mapChar = 0x10AB; break; + case 0x2D0C : mapChar = 0x10AC; break; + case 0x2D0D : mapChar = 0x10AD; break; + case 0x2D0E : mapChar = 0x10AE; break; + case 0x2D0F : mapChar = 0x10AF; break; + case 0x2D10 : mapChar = 0x10B0; break; + case 0x2D11 : mapChar = 0x10B1; break; + case 0x2D12 : mapChar = 0x10B2; break; + case 0x2D13 : mapChar = 0x10B3; break; + case 0x2D14 : mapChar = 0x10B4; break; + case 0x2D15 : mapChar = 0x10B5; break; + case 0x2D16 : mapChar = 0x10B6; break; + case 0x2D17 : mapChar = 0x10B7; break; + case 0x2D18 : mapChar = 0x10B8; break; + case 0x2D19 : mapChar = 0x10B9; break; + case 0x2D1A : mapChar = 0x10BA; break; + case 0x2D1B : mapChar = 0x10BB; break; + case 0x2D1C : mapChar = 0x10BC; break; + case 0x2D1D : mapChar = 0x10BD; break; + case 0x2D1E : mapChar = 0x10BE; break; + case 0x2D1F : mapChar = 0x10BF; break; + case 0x2D20 : mapChar = 0x10C0; break; + case 0x2D21 : mapChar = 0x10C1; break; + case 0x2D22 : mapChar = 0x10C2; break; + case 0x2D23 : mapChar = 0x10C3; break; + case 0x2D24 : mapChar = 0x10C4; break; + case 0x2D25 : mapChar = 0x10C5; break; // ch must have a 1:M case mapping, but we // can't handle it here. Return ch. // since mapChar is already set, no need @@ -315,6 +412,12 @@ class CharacterData00 extends CharacterData { case 0x32BE: retval = 49; break; // CIRCLED NUMBER FORTY NINE case 0x32BF: retval = 50; break; // CIRCLED NUMBER FIFTY + case 0x0D71: retval = 100; break; // MALAYALAM NUMBER ONE HUNDRED + case 0x0D72: retval = 1000; break; // MALAYALAM NUMBER ONE THOUSAND + case 0x2186: retval = 50; break; // ROMAN NUMERAL FIFTY EARLY FORM + case 0x2187: retval = 50000; break; // ROMAN NUMERAL FIFTY THOUSAND + case 0x2188: retval = 100000; break; // ROMAN NUMERAL ONE HUNDRED THOUSAND + default: retval = -2; break; } break; @@ -383,6 +486,54 @@ class CharacterData00 extends CharacterData { case 0x00B5 : mapChar = 0x039C; break; case 0x017F : mapChar = 0x0053; break; case 0x1FBE : mapChar = 0x0399; break; + + case 0x0250 : mapChar = 0x2C6F; break; + case 0x0251 : mapChar = 0x2C6D; break; + case 0x026B : mapChar = 0x2C62; break; + case 0x0271 : mapChar = 0x2C6E; break; + case 0x027D : mapChar = 0x2C64; break; + case 0x1D79 : mapChar = 0xA77D; break; + case 0x1D7D : mapChar = 0x2C63; break; + case 0x2C65 : mapChar = 0x023A; break; + case 0x2C66 : mapChar = 0x023E; break; + case 0x2D00 : mapChar = 0x10A0; break; + case 0x2D01 : mapChar = 0x10A1; break; + case 0x2D02 : mapChar = 0x10A2; break; + case 0x2D03 : mapChar = 0x10A3; break; + case 0x2D04 : mapChar = 0x10A4; break; + case 0x2D05 : mapChar = 0x10A5; break; + case 0x2D06 : mapChar = 0x10A6; break; + case 0x2D07 : mapChar = 0x10A7; break; + case 0x2D08 : mapChar = 0x10A8; break; + case 0x2D09 : mapChar = 0x10A9; break; + case 0x2D0A : mapChar = 0x10AA; break; + case 0x2D0B : mapChar = 0x10AB; break; + case 0x2D0C : mapChar = 0x10AC; break; + case 0x2D0D : mapChar = 0x10AD; break; + case 0x2D0E : mapChar = 0x10AE; break; + case 0x2D0F : mapChar = 0x10AF; break; + case 0x2D10 : mapChar = 0x10B0; break; + case 0x2D11 : mapChar = 0x10B1; break; + case 0x2D12 : mapChar = 0x10B2; break; + case 0x2D13 : mapChar = 0x10B3; break; + case 0x2D14 : mapChar = 0x10B4; break; + case 0x2D15 : mapChar = 0x10B5; break; + case 0x2D16 : mapChar = 0x10B6; break; + case 0x2D17 : mapChar = 0x10B7; break; + case 0x2D18 : mapChar = 0x10B8; break; + case 0x2D19 : mapChar = 0x10B9; break; + case 0x2D1A : mapChar = 0x10BA; break; + case 0x2D1B : mapChar = 0x10BB; break; + case 0x2D1C : mapChar = 0x10BC; break; + case 0x2D1D : mapChar = 0x10BD; break; + case 0x2D1E : mapChar = 0x10BE; break; + case 0x2D1F : mapChar = 0x10BF; break; + case 0x2D20 : mapChar = 0x10C0; break; + case 0x2D21 : mapChar = 0x10C1; break; + case 0x2D22 : mapChar = 0x10C2; break; + case 0x2D23 : mapChar = 0x10C3; break; + case 0x2D24 : mapChar = 0x10C4; break; + case 0x2D25 : mapChar = 0x10C5; break; default : mapChar = Character.ERROR; break; } } diff --git a/jdk/make/tools/GenerateCharacter/CharacterData01.java.template b/jdk/make/tools/GenerateCharacter/CharacterData01.java.template index 9a228b769c1..c42f9807a18 100644 --- a/jdk/make/tools/GenerateCharacter/CharacterData01.java.template +++ b/jdk/make/tools/GenerateCharacter/CharacterData01.java.template @@ -218,6 +218,48 @@ class CharacterData01 extends CharacterData { case 0x10132: retval = 80000; break; // AEGEAN NUMBER EIGHTY THOUSAND case 0x10133: retval = 90000; break; // AEGEAN NUMBER NINETY THOUSAND case 0x10323: retval = 50; break; // OLD ITALIC NUMERAL FIFTY + + case 0x010144: retval = 50; break; // ACROPHONIC ATTIC FIFTY + case 0x010145: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED + case 0x010146: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND + case 0x010147: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND + case 0x01014A: retval = 50; break; // ACROPHONIC ATTIC FIFTY TALENTS + case 0x01014B: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED TALENTS + case 0x01014C: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED TALENTS + case 0x01014D: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND TALENTS + case 0x01014E: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND TALENTS + case 0x010151: retval = 50; break; // ACROPHONIC ATTIC FIFTY STATERS + case 0x010152: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED STATERS + case 0x010153: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED STATERS + case 0x010154: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND STATERS + case 0x010155: retval = 10000; break; // ACROPHONIC ATTIC TEN THOUSAND STATERS + case 0x010156: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND STATERS + case 0x010166: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY + case 0x010167: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM + case 0x010168: retval = 50; break; // ACROPHONIC HERMIONIAN FIFTY + case 0x010169: retval = 50; break; // ACROPHONIC THESPIAN FIFTY + case 0x01016A: retval = 100; break; // ACROPHONIC THESPIAN ONE HUNDRED + case 0x01016B: retval = 300; break; // ACROPHONIC THESPIAN THREE HUNDRED + case 0x01016C: retval = 500; break; // ACROPHONIC EPIDAUREAN FIVE HUNDRED + case 0x01016D: retval = 500; break; // ACROPHONIC TROEZENIAN FIVE HUNDRED + case 0x01016E: retval = 500; break; // ACROPHONIC THESPIAN FIVE HUNDRED + case 0x01016F: retval = 500; break; // ACROPHONIC CARYSTIAN FIVE HUNDRED + case 0x010170: retval = 500; break; // ACROPHONIC NAXIAN FIVE HUNDRED + case 0x010171: retval = 1000; break; // ACROPHONIC THESPIAN ONE THOUSAND + case 0x010172: retval = 5000; break; // ACROPHONIC THESPIAN FIVE THOUSAND + case 0x010174: retval = 50; break; // ACROPHONIC STRATIAN FIFTY MNAS + case 0x010341: retval = 90; break; // GOTHIC LETTER NINETY + case 0x01034A: retval = 900; break; // GOTHIC LETTER NINE HUNDRED + case 0x0103D5: retval = 100; break; // OLD PERSIAN NUMBER HUNDRED + case 0x010919: retval = 100; break; // PHOENICIAN NUMBER ONE HUNDRED + case 0x010A46: retval = 100; break; // KHAROSHTHI NUMBER ONE HUNDRED + case 0x010A47: retval = 1000; break; // KHAROSHTHI NUMBER ONE THOUSAND + case 0x01D36C: retval = 40; break; // COUNTING ROD TENS DIGIT FOUR + case 0x01D36D: retval = 50; break; // COUNTING ROD TENS DIGIT FIVE + case 0x01D36E: retval = 60; break; // COUNTING ROD TENS DIGIT SIX + case 0x01D36F: retval = 70; break; // COUNTING ROD TENS DIGIT SEVEN + case 0x01D370: retval = 80; break; // COUNTING ROD TENS DIGIT EIGHT + case 0x01D371: retval = 90; break; // COUNTING ROD TENS DIGIT NINE default: retval = -2; break; } diff --git a/jdk/make/tools/UnicodeData/SpecialCasing.txt b/jdk/make/tools/UnicodeData/SpecialCasing.txt index 34d1c61de37..92e70a4a3d2 100644 --- a/jdk/make/tools/UnicodeData/SpecialCasing.txt +++ b/jdk/make/tools/UnicodeData/SpecialCasing.txt @@ -1,12 +1,17 @@ -# SpecialCasing-4.0.0.txt -# Date: 2003-03-14, 20:22:04 GMT [MD] +# SpecialCasing-5.1.0.txt +# Date: 2008-03-03, 21:58:10 GMT [MD] +# +# Unicode Character Database +# Copyright (c) 1991-2008 Unicode, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# For documentation, see UCD.html # # Special Casing Properties # # This file is a supplement to the UnicodeData file. # It contains additional information about the casing of Unicode characters. # (For compatibility, the UnicodeData.txt file only contains case mappings for -# characters where they are 1-1, and does not have locale-specific mappings.) +# characters where they are 1-1, and independent of context and language. # For more information, see the discussion of Case Mappings in the Unicode Standard. # # All code points not listed in this file that do not have a simple case mappings @@ -18,31 +23,31 @@ # # ; ; ; <upper> ; (<condition_list> ;)? # <comment> # -# <code>, <lower>, <title>, and <upper> provide character values in hex. If there is more than -# one character, they are separated by spaces. Other than as used to separate elements, -# spaces are to be ignored. +# <code>, <lower>, <title>, and <upper> provide character values in hex. If there is more +# than one character, they are separated by spaces. Other than as used to separate +# elements, spaces are to be ignored. # -# The <condition_list> is optional. Where present, it consists of one or more locales or contexts, -# separated by spaces. In these conditions: +# The <condition_list> is optional. Where present, it consists of one or more language IDs +# or contexts, separated by spaces. In these conditions: # - A condition list overrides the normal behavior if all of the listed conditions are true. # - The context is always the context of the characters in the original string, # NOT in the resulting string. # - Case distinctions in the condition list are not significant. # - Conditions preceded by "Not_" represent the negation of the condition. +# The condition list is not represented in the UCD as a formal property. # -# A locale is defined as: -# <locale> := <ISO_639_code> ( "_" <ISO_3166_code> ( "_" <variant> )? )? -# <ISO_3166_code> := 2-letter ISO country code, -# <ISO_639_code> := 2-letter ISO language code +# A language ID is defined by BCP 47, with '-' and '_' treated equivalently. # -# A context is one of the following, as defined in the Unicode Standard: -# Final_Sigma, After_Soft_Dotted, More_Above, Before_Dot, Not_Before_Dot, After_I +# A context for a character C is defined by Section 3.13 Default Case +# Operations, of The Unicode Standard, Version 5.0. +# (This is identical to the context defined by Unicode 4.1.0, +# as specified in http://www.unicode.org/versions/Unicode4.1.0/) # # Parsers of this file must be prepared to deal with future additions to this format: # * Additional contexts # * Additional fields # ================================================================================ - +# @missing 0000..10FFFF; <slc>; <stc>; <suc> # ================================================================================ # Unconditional mappings # ================================================================================ @@ -170,7 +175,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH 1FF3; 1FF3; 1FFC; 03A9 0399; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI 1FFC; 1FF3; 1FFC; 03A9 0399; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI -# Some characters with YPOGEGRAMMENI are also have no corresponding titlecases +# Some characters with YPOGEGRAMMENI also have no corresponding titlecases 1FB2; 1FB2; 1FBA 0345; 1FBA 0399; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI 1FB4; 1FB4; 0386 0345; 0386 0399; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI @@ -184,7 +189,14 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH 1FF7; 1FF7; 03A9 0342 0345; 03A9 0342 0399; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI # ================================================================================ -# Conditional mappings +# Conditional Mappings +# The remainder of this file provides conditional casing data used to produce +# full case mappings. +# ================================================================================ +# Language-Insensitive Mappings +# These are characters whose full case mappings do not depend on language, but do +# depend on context (which characters come before or after). For more information +# see the header of this file and the Unicode Standard. # ================================================================================ # Special case for final form of sigma @@ -203,7 +215,10 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH # 03C2; 03C3; 03A3; 03A3; Not_Final_Sigma; # GREEK SMALL LETTER FINAL SIGMA # ================================================================================ -# Locale-sensitive mappings +# Language-Sensitive Mappings +# These are characters whose full case mappings depend on language and perhaps also +# context (which characters come before or after). For more information +# see the header of this file and the Unicode Standard. # ================================================================================ # Lithuanian @@ -254,3 +269,6 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH # Note: the following case is already in the UnicodeData file. # 0131; 0131; 0049; 0049; tr; # LATIN SMALL LETTER DOTLESS I + +# EOF + diff --git a/jdk/make/tools/UnicodeData/UnicodeData.txt b/jdk/make/tools/UnicodeData/UnicodeData.txt index 86ea1cf9f68..77db788cf29 100644 --- a/jdk/make/tools/UnicodeData/UnicodeData.txt +++ b/jdk/make/tools/UnicodeData/UnicodeData.txt @@ -41,11 +41,11 @@ 0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;; 0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;; 002A;ASTERISK;Po;0;ON;;;;;N;;;;; -002B;PLUS SIGN;Sm;0;ET;;;;;N;;;;; +002B;PLUS SIGN;Sm;0;ES;;;;;N;;;;; 002C;COMMA;Po;0;CS;;;;;N;;;;; -002D;HYPHEN-MINUS;Pd;0;ET;;;;;N;;;;; +002D;HYPHEN-MINUS;Pd;0;ES;;;;;N;;;;; 002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;; -002F;SOLIDUS;Po;0;ES;;;;;N;SLASH;;;; +002F;SOLIDUS;Po;0;CS;;;;;N;SLASH;;;; 0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; 0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;; 0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;; @@ -171,7 +171,7 @@ 00AA;FEMININE ORDINAL INDICATOR;Ll;0;L;<super> 0061;;;;N;;;;; 00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;*;;; 00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;; -00AD;SOFT HYPHEN;Cf;0;ON;;;;;N;;;;; +00AD;SOFT HYPHEN;Cf;0;BN;;;;;N;;;;; 00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;; 00AF;MACRON;Sk;0;ON;<compat> 0020 0304;;;;N;SPACING MACRON;;;; 00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;; @@ -382,7 +382,7 @@ 017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E; 017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D 017F;LATIN SMALL LETTER LONG S;Ll;0;L;<compat> 0073;;;;N;;;0053;;0053 -0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;;; +0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;0243;;0243 0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253; 0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183; 0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182 @@ -408,7 +408,7 @@ 0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268; 0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199; 0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198 -019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;;; +019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;023D;;023D 019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;;; 019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F; 019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272; @@ -565,8 +565,33 @@ 0234;LATIN SMALL LETTER L WITH CURL;Ll;0;L;;;;;N;;;;; 0235;LATIN SMALL LETTER N WITH CURL;Ll;0;L;;;;;N;;;;; 0236;LATIN SMALL LETTER T WITH CURL;Ll;0;L;;;;;N;;;;; -0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;;; -0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;;; +0237;LATIN SMALL LETTER DOTLESS J;Ll;0;L;;;;;N;;;;; +0238;LATIN SMALL LETTER DB DIGRAPH;Ll;0;L;;;;;N;;;;; +0239;LATIN SMALL LETTER QP DIGRAPH;Ll;0;L;;;;;N;;;;; +023A;LATIN CAPITAL LETTER A WITH STROKE;Lu;0;L;;;;;N;;;;2C65; +023B;LATIN CAPITAL LETTER C WITH STROKE;Lu;0;L;;;;;N;;;;023C; +023C;LATIN SMALL LETTER C WITH STROKE;Ll;0;L;;;;;N;;;023B;;023B +023D;LATIN CAPITAL LETTER L WITH BAR;Lu;0;L;;;;;N;;;;019A; +023E;LATIN CAPITAL LETTER T WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;2C66; +023F;LATIN SMALL LETTER S WITH SWASH TAIL;Ll;0;L;;;;;N;;;;; +0240;LATIN SMALL LETTER Z WITH SWASH TAIL;Ll;0;L;;;;;N;;;;; +0241;LATIN CAPITAL LETTER GLOTTAL STOP;Lu;0;L;;;;;N;;;;0242; +0242;LATIN SMALL LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;0241;;0241 +0243;LATIN CAPITAL LETTER B WITH STROKE;Lu;0;L;;;;;N;;;;0180; +0244;LATIN CAPITAL LETTER U BAR;Lu;0;L;;;;;N;;;;0289; +0245;LATIN CAPITAL LETTER TURNED V;Lu;0;L;;;;;N;;;;028C; +0246;LATIN CAPITAL LETTER E WITH STROKE;Lu;0;L;;;;;N;;;;0247; +0247;LATIN SMALL LETTER E WITH STROKE;Ll;0;L;;;;;N;;;0246;;0246 +0248;LATIN CAPITAL LETTER J WITH STROKE;Lu;0;L;;;;;N;;;;0249; +0249;LATIN SMALL LETTER J WITH STROKE;Ll;0;L;;;;;N;;;0248;;0248 +024A;LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL;Lu;0;L;;;;;N;;;;024B; +024B;LATIN SMALL LETTER Q WITH HOOK TAIL;Ll;0;L;;;;;N;;;024A;;024A +024C;LATIN CAPITAL LETTER R WITH STROKE;Lu;0;L;;;;;N;;;;024D; +024D;LATIN SMALL LETTER R WITH STROKE;Ll;0;L;;;;;N;;;024C;;024C +024E;LATIN CAPITAL LETTER Y WITH STROKE;Lu;0;L;;;;;N;;;;024F; +024F;LATIN SMALL LETTER Y WITH STROKE;Ll;0;L;;;;;N;;;024E;;024E +0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;2C6F;;2C6F +0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;2C6D;;2C6D 0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;;; 0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181 0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186 @@ -592,13 +617,13 @@ 0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;; -026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;2C62;;2C62 026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;;; 026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;; 026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;; 026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C 0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;; -0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;;; +0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;2C6E;;2C6E 0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D 0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;; 0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;; @@ -610,7 +635,7 @@ 027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;; 027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;; 027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;; -027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;;; +027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;2C64;;2C64 027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;; 027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;; 0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;*;01A6;;01A6 @@ -622,10 +647,10 @@ 0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;; 0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;;; 0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE -0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;;; +0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;0244;;0244 028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1 028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2 -028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;;; +028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;0245;;0245 028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;; 028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;; 028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;; @@ -633,7 +658,7 @@ 0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;; 0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7 0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;; -0294;LATIN LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;;; +0294;LATIN LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;; 0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;; 0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;; 0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;; @@ -659,7 +684,7 @@ 02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;; 02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; 02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; -02AE;LATIN SMALL LETTER TURNED H WITH FISHHOOK ;Ll;0;L;;;;;N;;;;; +02AE;LATIN SMALL LETTER TURNED H WITH FISHHOOK;Ll;0;L;;;;;N;;;;; 02AF;LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL;Ll;0;L;;;;;N;;;;; 02B0;MODIFIER LETTER SMALL H;Lm;0;L;<super> 0068;;;;N;;;;; 02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L;<super> 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;; @@ -721,7 +746,7 @@ 02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;; 02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; 02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; -02EC;MODIFIER LETTER VOICING;Sk;0;ON;;;;;N;;;;; +02EC;MODIFIER LETTER VOICING;Lm;0;ON;;;;;N;;;;; 02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;; 02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;; 02EF;MODIFIER LETTER LOW DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;; @@ -829,6 +854,11 @@ 0355;COMBINING RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; 0356;COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; 0357;COMBINING RIGHT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;; +0358;COMBINING DOT ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;; +0359;COMBINING ASTERISK BELOW;Mn;220;NSM;;;;;N;;;;; +035A;COMBINING DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;; +035B;COMBINING ZIGZAG ABOVE;Mn;230;NSM;;;;;N;;;;; +035C;COMBINING DOUBLE BREVE BELOW;Mn;233;NSM;;;;;N;;;;; 035D;COMBINING DOUBLE BREVE;Mn;234;NSM;;;;;N;;;;; 035E;COMBINING DOUBLE MACRON;Mn;234;NSM;;;;;N;;;;; 035F;COMBINING DOUBLE MACRON BELOW;Mn;233;NSM;;;;;N;;;;; @@ -848,9 +878,18 @@ 036D;COMBINING LATIN SMALL LETTER T;Mn;230;NSM;;;;;N;;;;; 036E;COMBINING LATIN SMALL LETTER V;Mn;230;NSM;;;;;N;;;;; 036F;COMBINING LATIN SMALL LETTER X;Mn;230;NSM;;;;;N;;;;; -0374;GREEK NUMERAL SIGN;Sk;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;Dexia keraia;;; +0370;GREEK CAPITAL LETTER HETA;Lu;0;L;;;;;N;;;;0371; +0371;GREEK SMALL LETTER HETA;Ll;0;L;;;;;N;;;0370;;0370 +0372;GREEK CAPITAL LETTER ARCHAIC SAMPI;Lu;0;L;;;;;N;;;;0373; +0373;GREEK SMALL LETTER ARCHAIC SAMPI;Ll;0;L;;;;;N;;;0372;;0372 +0374;GREEK NUMERAL SIGN;Lm;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;Dexia keraia;;; 0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;Aristeri keraia;;; +0376;GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA;Lu;0;L;;;;;N;;;;0377; +0377;GREEK SMALL LETTER PAMPHYLIAN DIGAMMA;Ll;0;L;;;;;N;;;0376;;0376 037A;GREEK YPOGEGRAMMENI;Lm;0;L;<compat> 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;; +037B;GREEK SMALL REVERSED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FD;;03FD +037C;GREEK SMALL DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FE;;03FE +037D;GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FF;;03FF 037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;Erotimatiko;;; 0384;GREEK TONOS;Sk;0;ON;<compat> 0020 0301;;;;N;GREEK SPACING TONOS;;;; 0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;; @@ -924,6 +963,7 @@ 03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C 03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E 03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F +03CF;GREEK CAPITAL KAI SYMBOL;Lu;0;L;;;;;N;;;;03D7; 03D0;GREEK BETA SYMBOL;Ll;0;L;<compat> 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392 03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398 03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L;<compat> 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;; @@ -931,7 +971,7 @@ 03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;; 03D5;GREEK PHI SYMBOL;Ll;0;L;<compat> 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6 03D6;GREEK PI SYMBOL;Ll;0;L;<compat> 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0 -03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;;; +03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;03CF;;03CF 03D8;GREEK LETTER ARCHAIC KOPPA;Lu;0;L;;;;;N;;*;;03D9; 03D9;GREEK SMALL LETTER ARCHAIC KOPPA;Ll;0;L;;;;;N;;*;03D8;;03D8 03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB; @@ -968,6 +1008,10 @@ 03F9;GREEK CAPITAL LUNATE SIGMA SYMBOL;Lu;0;L;<compat> 03A3;;;;N;;;;03F2; 03FA;GREEK CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;03FB; 03FB;GREEK SMALL LETTER SAN;Ll;0;L;;;;;N;;;03FA;;03FA +03FC;GREEK RHO WITH STROKE SYMBOL;Ll;0;L;;;;;N;;;;; +03FD;GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037B; +03FE;GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037C; +03FF;GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037D; 0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450; 0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451; 0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;Serbocroatian;;0452; @@ -1103,6 +1147,7 @@ 0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;; 0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;; 0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;; +0487;COMBINING CYRILLIC POKRYTIE;Mn;230;NSM;;;;;N;;;;; 0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;; 0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; 048A;CYRILLIC CAPITAL LETTER SHORT I WITH TAIL;Lu;0;L;;;;;N;;;;048B; @@ -1159,7 +1204,7 @@ 04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC 04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF; 04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE -04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;; +04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;04CF; 04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2; 04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1 04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4; @@ -1174,6 +1219,7 @@ 04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB 04CD;CYRILLIC CAPITAL LETTER EM WITH TAIL;Lu;0;L;;;;;N;;;;04CE; 04CE;CYRILLIC SMALL LETTER EM WITH TAIL;Ll;0;L;;;;;N;;;04CD;;04CD +04CF;CYRILLIC SMALL LETTER PALOCHKA;Ll;0;L;;;;;N;;;04C0;;04C0 04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1; 04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0 04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3; @@ -1212,8 +1258,16 @@ 04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2 04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5; 04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4 +04F6;CYRILLIC CAPITAL LETTER GHE WITH DESCENDER;Lu;0;L;;;;;N;;;;04F7; +04F7;CYRILLIC SMALL LETTER GHE WITH DESCENDER;Ll;0;L;;;;;N;;;04F6;;04F6 04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9; 04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8 +04FA;CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK;Lu;0;L;;;;;N;;;;04FB; +04FB;CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK;Ll;0;L;;;;;N;;;04FA;;04FA +04FC;CYRILLIC CAPITAL LETTER HA WITH HOOK;Lu;0;L;;;;;N;;;;04FD; +04FD;CYRILLIC SMALL LETTER HA WITH HOOK;Ll;0;L;;;;;N;;;04FC;;04FC +04FE;CYRILLIC CAPITAL LETTER HA WITH STROKE;Lu;0;L;;;;;N;;;;04FF; +04FF;CYRILLIC SMALL LETTER HA WITH STROKE;Ll;0;L;;;;;N;;;04FE;;04FE 0500;CYRILLIC CAPITAL LETTER KOMI DE;Lu;0;L;;;;;N;;;;0501; 0501;CYRILLIC SMALL LETTER KOMI DE;Ll;0;L;;;;;N;;;0500;;0500 0502;CYRILLIC CAPITAL LETTER KOMI DJE;Lu;0;L;;;;;N;;;;0503; @@ -1230,6 +1284,26 @@ 050D;CYRILLIC SMALL LETTER KOMI SJE;Ll;0;L;;;;;N;;;050C;;050C 050E;CYRILLIC CAPITAL LETTER KOMI TJE;Lu;0;L;;;;;N;;;;050F; 050F;CYRILLIC SMALL LETTER KOMI TJE;Ll;0;L;;;;;N;;;050E;;050E +0510;CYRILLIC CAPITAL LETTER REVERSED ZE;Lu;0;L;;;;;N;;;;0511; +0511;CYRILLIC SMALL LETTER REVERSED ZE;Ll;0;L;;;;;N;;;0510;;0510 +0512;CYRILLIC CAPITAL LETTER EL WITH HOOK;Lu;0;L;;;;;N;;;;0513; +0513;CYRILLIC SMALL LETTER EL WITH HOOK;Ll;0;L;;;;;N;;;0512;;0512 +0514;CYRILLIC CAPITAL LETTER LHA;Lu;0;L;;;;;N;;;;0515; +0515;CYRILLIC SMALL LETTER LHA;Ll;0;L;;;;;N;;;0514;;0514 +0516;CYRILLIC CAPITAL LETTER RHA;Lu;0;L;;;;;N;;;;0517; +0517;CYRILLIC SMALL LETTER RHA;Ll;0;L;;;;;N;;;0516;;0516 +0518;CYRILLIC CAPITAL LETTER YAE;Lu;0;L;;;;;N;;;;0519; +0519;CYRILLIC SMALL LETTER YAE;Ll;0;L;;;;;N;;;0518;;0518 +051A;CYRILLIC CAPITAL LETTER QA;Lu;0;L;;;;;N;;;;051B; +051B;CYRILLIC SMALL LETTER QA;Ll;0;L;;;;;N;;;051A;;051A +051C;CYRILLIC CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;051D; +051D;CYRILLIC SMALL LETTER WE;Ll;0;L;;;;;N;;;051C;;051C +051E;CYRILLIC CAPITAL LETTER ALEUT KA;Lu;0;L;;;;;N;;;;051F; +051F;CYRILLIC SMALL LETTER ALEUT KA;Ll;0;L;;;;;N;;;051E;;051E +0520;CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0521; +0521;CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0520;;0520 +0522;CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0523; +0523;CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0522;;0522 0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561; 0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562; 0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563; @@ -1333,6 +1407,7 @@ 059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;; 05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;; 05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;; +05A2;HEBREW ACCENT ATNAH HAFUKH;Mn;220;NSM;;;;;N;;;;; 05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;; 05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;; 05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;*;;; @@ -1356,16 +1431,20 @@ 05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;; 05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;; 05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;; +05BA;HEBREW POINT HOLAM HASER FOR VAV;Mn;19;NSM;;;;;N;;;;; 05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;; 05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;or shuruq;;; 05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;*;;; -05BE;HEBREW PUNCTUATION MAQAF;Po;0;R;;;;;N;;;;; +05BE;HEBREW PUNCTUATION MAQAF;Pd;0;R;;;;;N;;;;; 05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;; 05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;*;;; 05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;; 05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;; 05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;*;;; 05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;; +05C5;HEBREW MARK LOWER DOT;Mn;220;NSM;;;;;N;;;;; +05C6;HEBREW PUNCTUATION NUN HAFUKHA;Po;0;R;;;;;N;;;;; +05C7;HEBREW POINT QAMATS QATAN;Mn;18;NSM;;;;;N;;;;; 05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;; 05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;; 05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;; @@ -1398,10 +1477,16 @@ 05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;; 05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;; 05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;; -0600;ARABIC NUMBER SIGN;Cf;0;AL;;;;;N;;;;; -0601;ARABIC SIGN SANAH;Cf;0;AL;;;;;N;;;;; -0602;ARABIC FOOTNOTE MARKER;Cf;0;AL;;;;;N;;;;; -0603;ARABIC SIGN SAFHA;Cf;0;AL;;;;;N;;;;; +0600;ARABIC NUMBER SIGN;Cf;0;AN;;;;;N;;;;; +0601;ARABIC SIGN SANAH;Cf;0;AN;;;;;N;;;;; +0602;ARABIC FOOTNOTE MARKER;Cf;0;AN;;;;;N;;;;; +0603;ARABIC SIGN SAFHA;Cf;0;AN;;;;;N;;;;; +0606;ARABIC-INDIC CUBE ROOT;Sm;0;ON;;;;;N;;;;; +0607;ARABIC-INDIC FOURTH ROOT;Sm;0;ON;;;;;N;;;;; +0608;ARABIC RAY;Sm;0;AL;;;;;N;;;;; +0609;ARABIC-INDIC PER MILLE SIGN;Po;0;ET;;;;;N;;;;; +060A;ARABIC-INDIC PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;; +060B;AFGHANI SIGN;Sc;0;AL;;;;;N;;;;; 060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;; 060D;ARABIC DATE SEPARATOR;Po;0;AL;;;;;N;;;;; 060E;ARABIC POETIC VERSE SIGN;So;0;ON;;;;;N;;;;; @@ -1411,8 +1496,14 @@ 0612;ARABIC SIGN RAHMATULLAH ALAYHE;Mn;230;NSM;;;;;N;;;;; 0613;ARABIC SIGN RADI ALLAHOU ANHU;Mn;230;NSM;;;;;N;;;;; 0614;ARABIC SIGN TAKHALLUS;Mn;230;NSM;;;;;N;;;;; -0615;ARABIC SMALL HIGH TAH ;Mn;230;NSM;;;;;N;;;;; +0615;ARABIC SMALL HIGH TAH;Mn;230;NSM;;;;;N;;;;; +0616;ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH;Mn;230;NSM;;;;;N;;;;; +0617;ARABIC SMALL HIGH ZAIN;Mn;230;NSM;;;;;N;;;;; +0618;ARABIC SMALL FATHA;Mn;30;NSM;;;;;N;;;;; +0619;ARABIC SMALL DAMMA;Mn;31;NSM;;;;;N;;;;; +061A;ARABIC SMALL KASRA;Mn;32;NSM;;;;;N;;;;; 061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;; +061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;; 061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;; 0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;; 0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;; @@ -1440,6 +1531,11 @@ 0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;; 0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;; 063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;; +063B;ARABIC LETTER KEHEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +063C;ARABIC LETTER KEHEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +063D;ARABIC LETTER FARSI YEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +063E;ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +063F;ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;; 0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;; 0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;; @@ -1465,6 +1561,12 @@ 0656;ARABIC SUBSCRIPT ALEF;Mn;220;NSM;;;;;N;;;;; 0657;ARABIC INVERTED DAMMA;Mn;230;NSM;;;;;N;;;;; 0658;ARABIC MARK NOON GHUNNA;Mn;230;NSM;;;;;N;;;;; +0659;ARABIC ZWARAKAY;Mn;230;NSM;;;;;N;;;;; +065A;ARABIC VOWEL SIGN SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;; +065B;ARABIC VOWEL SIGN INVERTED SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;; +065C;ARABIC VOWEL SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;; +065D;ARABIC REVERSED DAMMA;Mn;230;NSM;;;;;N;;;;; +065E;ARABIC FATHA WITH TWO DOTS;Mn;230;NSM;;;;;N;;;;; 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; 0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; 0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; @@ -1590,7 +1692,7 @@ 06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;; 06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;; 06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;; -06DD;ARABIC END OF AYAH;Cf;0;AL;;;;;N;;;;; +06DD;ARABIC END OF AYAH;Cf;0;AN;;;;;N;;;;; 06DE;ARABIC START OF RUB EL HIZB;Me;0;NSM;;;;;N;;;;; 06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;; 06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;; @@ -1702,6 +1804,54 @@ 074D;SYRIAC LETTER SOGDIAN ZHAIN;Lo;0;AL;;;;;N;;;;; 074E;SYRIAC LETTER SOGDIAN KHAPH;Lo;0;AL;;;;;N;;;;; 074F;SYRIAC LETTER SOGDIAN FE;Lo;0;AL;;;;;N;;;;; +0750;ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW;Lo;0;AL;;;;;N;;;;; +0751;ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0752;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; +0753;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0754;ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +0755;ARABIC LETTER BEH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;; +0756;ARABIC LETTER BEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; +0757;ARABIC LETTER HAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0758;ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; +0759;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;; +075A;ARABIC LETTER DAL WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;; +075B;ARABIC LETTER REH WITH STROKE;Lo;0;AL;;;;;N;;;;; +075C;ARABIC LETTER SEEN WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +075D;ARABIC LETTER AIN WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +075E;ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE;Lo;0;AL;;;;;N;;;;; +075F;ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;; +0760;ARABIC LETTER FEH WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +0761;ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; +0762;ARABIC LETTER KEHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +0763;ARABIC LETTER KEHEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0764;ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; +0765;ARABIC LETTER MEEM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +0766;ARABIC LETTER MEEM WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +0767;ARABIC LETTER NOON WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +0768;ARABIC LETTER NOON WITH SMALL TAH;Lo;0;AL;;;;;N;;;;; +0769;ARABIC LETTER NOON WITH SMALL V;Lo;0;AL;;;;;N;;;;; +076A;ARABIC LETTER LAM WITH BAR;Lo;0;AL;;;;;N;;;;; +076B;ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;; +076C;ARABIC LETTER REH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; +076D;ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;; +076E;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH BELOW;Lo;0;AL;;;;;N;;;;; +076F;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;; +0770;ARABIC LETTER SEEN WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;; +0771;ARABIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;; +0772;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;; +0773;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; +0774;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; +0775;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; +0776;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; +0777;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;; +0778;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; +0779;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; +077A;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; +077B;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; +077C;ARABIC LETTER HAH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;; +077D;ARABIC LETTER SEEN WITH EXTENDED ARABIC-INDIC DIGIT FOUR ABOVE;Lo;0;AL;;;;;N;;;;; +077E;ARABIC LETTER SEEN WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +077F;ARABIC LETTER KAF WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;; 0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;; 0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;; @@ -1752,6 +1902,65 @@ 07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;; 07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;; 07B1;THAANA LETTER NAA;Lo;0;AL;;;;;N;;;;; +07C0;NKO DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;; +07C1;NKO DIGIT ONE;Nd;0;R;;1;1;1;N;;;;; +07C2;NKO DIGIT TWO;Nd;0;R;;2;2;2;N;;;;; +07C3;NKO DIGIT THREE;Nd;0;R;;3;3;3;N;;;;; +07C4;NKO DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;; +07C5;NKO DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;; +07C6;NKO DIGIT SIX;Nd;0;R;;6;6;6;N;;;;; +07C7;NKO DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;; +07C8;NKO DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;; +07C9;NKO DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; +07CA;NKO LETTER A;Lo;0;R;;;;;N;;;;; +07CB;NKO LETTER EE;Lo;0;R;;;;;N;;;;; +07CC;NKO LETTER I;Lo;0;R;;;;;N;;;;; +07CD;NKO LETTER E;Lo;0;R;;;;;N;;;;; +07CE;NKO LETTER U;Lo;0;R;;;;;N;;;;; +07CF;NKO LETTER OO;Lo;0;R;;;;;N;;;;; +07D0;NKO LETTER O;Lo;0;R;;;;;N;;;;; +07D1;NKO LETTER DAGBASINNA;Lo;0;R;;;;;N;;;;; +07D2;NKO LETTER N;Lo;0;R;;;;;N;;;;; +07D3;NKO LETTER BA;Lo;0;R;;;;;N;;;;; +07D4;NKO LETTER PA;Lo;0;R;;;;;N;;;;; +07D5;NKO LETTER TA;Lo;0;R;;;;;N;;;;; +07D6;NKO LETTER JA;Lo;0;R;;;;;N;;;;; +07D7;NKO LETTER CHA;Lo;0;R;;;;;N;;;;; +07D8;NKO LETTER DA;Lo;0;R;;;;;N;;;;; +07D9;NKO LETTER RA;Lo;0;R;;;;;N;;;;; +07DA;NKO LETTER RRA;Lo;0;R;;;;;N;;;;; +07DB;NKO LETTER SA;Lo;0;R;;;;;N;;;;; +07DC;NKO LETTER GBA;Lo;0;R;;;;;N;;;;; +07DD;NKO LETTER FA;Lo;0;R;;;;;N;;;;; +07DE;NKO LETTER KA;Lo;0;R;;;;;N;;;;; +07DF;NKO LETTER LA;Lo;0;R;;;;;N;;;;; +07E0;NKO LETTER NA WOLOSO;Lo;0;R;;;;;N;;;;; +07E1;NKO LETTER MA;Lo;0;R;;;;;N;;;;; +07E2;NKO LETTER NYA;Lo;0;R;;;;;N;;;;; +07E3;NKO LETTER NA;Lo;0;R;;;;;N;;;;; +07E4;NKO LETTER HA;Lo;0;R;;;;;N;;;;; +07E5;NKO LETTER WA;Lo;0;R;;;;;N;;;;; +07E6;NKO LETTER YA;Lo;0;R;;;;;N;;;;; +07E7;NKO LETTER NYA WOLOSO;Lo;0;R;;;;;N;;;;; +07E8;NKO LETTER JONA JA;Lo;0;R;;;;;N;;;;; +07E9;NKO LETTER JONA CHA;Lo;0;R;;;;;N;;;;; +07EA;NKO LETTER JONA RA;Lo;0;R;;;;;N;;;;; +07EB;NKO COMBINING SHORT HIGH TONE;Mn;230;NSM;;;;;N;;;;; +07EC;NKO COMBINING SHORT LOW TONE;Mn;230;NSM;;;;;N;;;;; +07ED;NKO COMBINING SHORT RISING TONE;Mn;230;NSM;;;;;N;;;;; +07EE;NKO COMBINING LONG DESCENDING TONE;Mn;230;NSM;;;;;N;;;;; +07EF;NKO COMBINING LONG HIGH TONE;Mn;230;NSM;;;;;N;;;;; +07F0;NKO COMBINING LONG LOW TONE;Mn;230;NSM;;;;;N;;;;; +07F1;NKO COMBINING LONG RISING TONE;Mn;230;NSM;;;;;N;;;;; +07F2;NKO COMBINING NASALIZATION MARK;Mn;220;NSM;;;;;N;;;;; +07F3;NKO COMBINING DOUBLE DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +07F4;NKO HIGH TONE APOSTROPHE;Lm;0;R;;;;;N;;;;; +07F5;NKO LOW TONE APOSTROPHE;Lm;0;R;;;;;N;;;;; +07F6;NKO SYMBOL OO DENNEN;So;0;ON;;;;;N;;;;; +07F7;NKO SYMBOL GBAKURUNEN;Po;0;ON;;;;;N;;;;; +07F8;NKO COMMA;Po;0;ON;;;;;N;;;;; +07F9;NKO EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +07FA;NKO LAJANYALAN;Lm;0;R;;;;;N;;;;; 0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -1857,6 +2066,13 @@ 096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +0971;DEVANAGARI SIGN HIGH SPACING DOT;Lm;0;L;;;;;N;;;;; +0972;DEVANAGARI LETTER CANDRA A;Lo;0;L;;;;;N;;;;; +097B;DEVANAGARI LETTER GGA;Lo;0;L;;;;;N;;;;; +097C;DEVANAGARI LETTER JJA;Lo;0;L;;;;;N;;;;; +097D;DEVANAGARI LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +097E;DEVANAGARI LETTER DDDA;Lo;0;L;;;;;N;;;;; +097F;DEVANAGARI LETTER BBA;Lo;0;L;;;;;N;;;;; 0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -1918,6 +2134,7 @@ 09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;; 09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;; 09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +09CE;BENGALI LETTER KHANDA TA;Lo;0;L;;;;;N;;;;; 09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;; 09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;; 09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;; @@ -2004,6 +2221,7 @@ 0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; 0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; 0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0A51;GURMUKHI SIGN UDAAT;Mn;0;NSM;;;;;N;;;;; 0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;; 0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;; 0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;; @@ -2024,6 +2242,7 @@ 0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;; 0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;; 0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;; +0A75;GURMUKHI SIGN YAKASH;Mn;0;NSM;;;;;N;;;;; 0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2164,6 +2383,7 @@ 0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0B44;ORIYA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; 0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;; 0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;; @@ -2176,6 +2396,8 @@ 0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;; 0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0B62;ORIYA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0B63;ORIYA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; 0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -2221,6 +2443,7 @@ 0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;; 0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;; 0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;; +0BB6;TAMIL LETTER SHA;Lo;0;L;;;;;N;;;;; 0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;; 0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;; 0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;; @@ -2236,7 +2459,9 @@ 0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;; 0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;; 0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0BD0;TAMIL OM;Lo;0;L;;;;;N;;;;; 0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0BE6;TAMIL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; @@ -2309,6 +2534,7 @@ 0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;; 0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;; 0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;; +0C3D;TELUGU SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; 0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; @@ -2325,8 +2551,12 @@ 0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;; 0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;; +0C58;TELUGU LETTER TSA;Lo;0;L;;;;;N;;;;; +0C59;TELUGU LETTER DZA;Lo;0;L;;;;;N;;;;; 0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0C62;TELUGU VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0C63;TELUGU VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; 0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -2337,6 +2567,14 @@ 0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0C78;TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR;No;0;ON;;;;0;N;;;;; +0C79;TELUGU FRACTION DIGIT ONE FOR ODD POWERS OF FOUR;No;0;ON;;;;1;N;;;;; +0C7A;TELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOUR;No;0;ON;;;;2;N;;;;; +0C7B;TELUGU FRACTION DIGIT THREE FOR ODD POWERS OF FOUR;No;0;ON;;;;3;N;;;;; +0C7C;TELUGU FRACTION DIGIT ONE FOR EVEN POWERS OF FOUR;No;0;ON;;;;1;N;;;;; +0C7D;TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR;No;0;ON;;;;2;N;;;;; +0C7E;TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR;No;0;ON;;;;3;N;;;;; +0C7F;TELUGU SIGN TUUMU;So;0;L;;;;;N;;;;; 0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;; @@ -2409,6 +2647,8 @@ 0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;; 0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0CE2;KANNADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0CE3;KANNADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; 0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -2419,6 +2659,8 @@ 0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0CF1;KANNADA SIGN JIHVAMULIYA;So;0;ON;;;;;N;;;;; +0CF2;KANNADA SIGN UPADHMANIYA;So;0;ON;;;;;N;;;;; 0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;; @@ -2471,12 +2713,14 @@ 0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;; 0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;; 0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;; +0D3D;MALAYALAM SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; 0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;; 0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0D44;MALAYALAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; 0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; 0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; @@ -2487,6 +2731,8 @@ 0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; 0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0D62;MALAYALAM VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0D63;MALAYALAM VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; 0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -2497,6 +2743,19 @@ 0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0D70;MALAYALAM NUMBER TEN;No;0;L;;;;10;N;;;;; +0D71;MALAYALAM NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; +0D72;MALAYALAM NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; +0D73;MALAYALAM FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; +0D74;MALAYALAM FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; +0D75;MALAYALAM FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; +0D79;MALAYALAM DATE MARK;So;0;L;;;;;N;;;;; +0D7A;MALAYALAM LETTER CHILLU NN;Lo;0;L;;;;;N;;;;; +0D7B;MALAYALAM LETTER CHILLU N;Lo;0;L;;;;;N;;;;; +0D7C;MALAYALAM LETTER CHILLU RR;Lo;0;L;;;;;N;;;;; +0D7D;MALAYALAM LETTER CHILLU L;Lo;0;L;;;;;N;;;;; +0D7E;MALAYALAM LETTER CHILLU LL;Lo;0;L;;;;;N;;;;; +0D7F;MALAYALAM LETTER CHILLU K;Lo;0;L;;;;;N;;;;; 0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;; 0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;; 0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;; @@ -2787,10 +3046,10 @@ 0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;nge zung gor ta;;; 0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;che go;;; 0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;tsa tru;;; -0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;N;;gug ta yun;;; -0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;N;;gug ta ye;;; -0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;N;TIBETAN LEFT BRACE;ang kang yun;;; -0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;N;TIBETAN RIGHT BRACE;ang kang ye;;; +0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;Y;;gug ta yun;;; +0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;Y;;gug ta ye;;; +0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;Y;TIBETAN LEFT BRACE;ang kang yun;;; +0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;Y;TIBETAN RIGHT BRACE;ang kang ye;;; 0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;yar tse;;; 0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;mar tse;;; 0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;; @@ -2835,6 +3094,8 @@ 0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;; 0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;; 0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;*;;; +0F6B;TIBETAN LETTER KKA;Lo;0;L;;;;;N;;;;; +0F6C;TIBETAN LETTER RRA;Lo;0;L;;;;;N;;;;; 0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;; 0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;; 0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;; @@ -2921,7 +3182,13 @@ 0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;norbu nyi khyi;;; 0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;norbu sum khyi;;; 0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;norbu shi khyi;;; +0FCE;TIBETAN SIGN RDEL NAG RDEL DKAR;So;0;L;;;;;N;;dena deka;;; 0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;dena sum;;; +0FD0;TIBETAN MARK BSKA- SHOG GI MGO RGYAN;Po;0;L;;;;;N;;ka shog gi go gyen;;; +0FD1;TIBETAN MARK MNYAM YIG GI MGO RGYAN;Po;0;L;;;;;N;;nyam yig gi go gyen;;; +0FD2;TIBETAN MARK NYIS TSHEG;Po;0;L;;;;;N;;nyi tsek;;; +0FD3;TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA;Po;0;L;;;;;N;;da nying yik go dun ma;;; +0FD4;TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA;Po;0;L;;;;;N;;da nying yik go kab ma;;; 1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;; 1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;; 1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;; @@ -2956,13 +3223,16 @@ 101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;; 1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;; 1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;; +1022;MYANMAR LETTER SHAN A;Lo;0;L;;;;;N;;;;; 1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;; 1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;; 1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;; 1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;; 1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;; +1028;MYANMAR LETTER MON E;Lo;0;L;;;;;N;;;;; 1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;; 102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;; +102B;MYANMAR VOWEL SIGN TALL AA;Mc;0;L;;;;;N;;;;; 102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; @@ -2970,10 +3240,19 @@ 1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1033;MYANMAR VOWEL SIGN MON II;Mn;0;NSM;;;;;N;;;;; +1034;MYANMAR VOWEL SIGN MON O;Mn;0;NSM;;;;;N;;;;; +1035;MYANMAR VOWEL SIGN E ABOVE;Mn;0;NSM;;;;;N;;;;; 1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;; 1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;; 1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +103A;MYANMAR SIGN ASAT;Mn;9;NSM;;;;;N;;;;; +103B;MYANMAR CONSONANT SIGN MEDIAL YA;Mc;0;L;;;;;N;;;;; +103C;MYANMAR CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;; +103D;MYANMAR CONSONANT SIGN MEDIAL WA;Mn;0;NSM;;;;;N;;;;; +103E;MYANMAR CONSONANT SIGN MEDIAL HA;Mn;0;NSM;;;;;N;;;;; +103F;MYANMAR LETTER GREAT SA;Lo;0;L;;;;;N;;;;; 1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -3000,44 +3279,110 @@ 1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; 1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; 1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;Khutsuri;;; -10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;Khutsuri;;; -10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;Khutsuri;;; -10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;Khutsuri;;; -10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;Khutsuri;;; -10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;Khutsuri;;; -10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;Khutsuri;;; -10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;Khutsuri;;; -10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;Khutsuri;;; -10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;Khutsuri;;; -10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;Khutsuri;;; -10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;Khutsuri;;; -10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;Khutsuri;;; -10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;Khutsuri;;; -10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;Khutsuri;;; -10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;Khutsuri;;; -10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;Khutsuri;;; -10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;Khutsuri;;; -10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;Khutsuri;;; -10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;Khutsuri;;; -10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;Khutsuri;;; -10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;Khutsuri;;; -10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;Khutsuri;;; -10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;Khutsuri;;; -10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;Khutsuri;;; -10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;Khutsuri;;; -10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;Khutsuri;;; -10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;Khutsuri;;; -10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;Khutsuri;;; -10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;Khutsuri;;; -10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;Khutsuri;;; -10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;Khutsuri;;; -10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;Khutsuri;;; -10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;Khutsuri;;; -10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;Khutsuri;;; -10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;Khutsuri;;; -10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;Khutsuri;;; -10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;Khutsuri;;; +105A;MYANMAR LETTER MON NGA;Lo;0;L;;;;;N;;;;; +105B;MYANMAR LETTER MON JHA;Lo;0;L;;;;;N;;;;; +105C;MYANMAR LETTER MON BBA;Lo;0;L;;;;;N;;;;; +105D;MYANMAR LETTER MON BBE;Lo;0;L;;;;;N;;;;; +105E;MYANMAR CONSONANT SIGN MON MEDIAL NA;Mn;0;NSM;;;;;N;;;;; +105F;MYANMAR CONSONANT SIGN MON MEDIAL MA;Mn;0;NSM;;;;;N;;;;; +1060;MYANMAR CONSONANT SIGN MON MEDIAL LA;Mn;0;NSM;;;;;N;;;;; +1061;MYANMAR LETTER SGAW KAREN SHA;Lo;0;L;;;;;N;;;;; +1062;MYANMAR VOWEL SIGN SGAW KAREN EU;Mc;0;L;;;;;N;;;;; +1063;MYANMAR TONE MARK SGAW KAREN HATHI;Mc;0;L;;;;;N;;;;; +1064;MYANMAR TONE MARK SGAW KAREN KE PHO;Mc;0;L;;;;;N;;;;; +1065;MYANMAR LETTER WESTERN PWO KAREN THA;Lo;0;L;;;;;N;;;;; +1066;MYANMAR LETTER WESTERN PWO KAREN PWA;Lo;0;L;;;;;N;;;;; +1067;MYANMAR VOWEL SIGN WESTERN PWO KAREN EU;Mc;0;L;;;;;N;;;;; +1068;MYANMAR VOWEL SIGN WESTERN PWO KAREN UE;Mc;0;L;;;;;N;;;;; +1069;MYANMAR SIGN WESTERN PWO KAREN TONE-1;Mc;0;L;;;;;N;;;;; +106A;MYANMAR SIGN WESTERN PWO KAREN TONE-2;Mc;0;L;;;;;N;;;;; +106B;MYANMAR SIGN WESTERN PWO KAREN TONE-3;Mc;0;L;;;;;N;;;;; +106C;MYANMAR SIGN WESTERN PWO KAREN TONE-4;Mc;0;L;;;;;N;;;;; +106D;MYANMAR SIGN WESTERN PWO KAREN TONE-5;Mc;0;L;;;;;N;;;;; +106E;MYANMAR LETTER EASTERN PWO KAREN NNA;Lo;0;L;;;;;N;;;;; +106F;MYANMAR LETTER EASTERN PWO KAREN YWA;Lo;0;L;;;;;N;;;;; +1070;MYANMAR LETTER EASTERN PWO KAREN GHWA;Lo;0;L;;;;;N;;;;; +1071;MYANMAR VOWEL SIGN GEBA KAREN I;Mn;0;NSM;;;;;N;;;;; +1072;MYANMAR VOWEL SIGN KAYAH OE;Mn;0;NSM;;;;;N;;;;; +1073;MYANMAR VOWEL SIGN KAYAH U;Mn;0;NSM;;;;;N;;;;; +1074;MYANMAR VOWEL SIGN KAYAH EE;Mn;0;NSM;;;;;N;;;;; +1075;MYANMAR LETTER SHAN KA;Lo;0;L;;;;;N;;;;; +1076;MYANMAR LETTER SHAN KHA;Lo;0;L;;;;;N;;;;; +1077;MYANMAR LETTER SHAN GA;Lo;0;L;;;;;N;;;;; +1078;MYANMAR LETTER SHAN CA;Lo;0;L;;;;;N;;;;; +1079;MYANMAR LETTER SHAN ZA;Lo;0;L;;;;;N;;;;; +107A;MYANMAR LETTER SHAN NYA;Lo;0;L;;;;;N;;;;; +107B;MYANMAR LETTER SHAN DA;Lo;0;L;;;;;N;;;;; +107C;MYANMAR LETTER SHAN NA;Lo;0;L;;;;;N;;;;; +107D;MYANMAR LETTER SHAN PHA;Lo;0;L;;;;;N;;;;; +107E;MYANMAR LETTER SHAN FA;Lo;0;L;;;;;N;;;;; +107F;MYANMAR LETTER SHAN BA;Lo;0;L;;;;;N;;;;; +1080;MYANMAR LETTER SHAN THA;Lo;0;L;;;;;N;;;;; +1081;MYANMAR LETTER SHAN HA;Lo;0;L;;;;;N;;;;; +1082;MYANMAR CONSONANT SIGN SHAN MEDIAL WA;Mn;0;NSM;;;;;N;;;;; +1083;MYANMAR VOWEL SIGN SHAN AA;Mc;0;L;;;;;N;;;;; +1084;MYANMAR VOWEL SIGN SHAN E;Mc;0;L;;;;;N;;;;; +1085;MYANMAR VOWEL SIGN SHAN E ABOVE;Mn;0;NSM;;;;;N;;;;; +1086;MYANMAR VOWEL SIGN SHAN FINAL Y;Mn;0;NSM;;;;;N;;;;; +1087;MYANMAR SIGN SHAN TONE-2;Mc;0;L;;;;;N;;;;; +1088;MYANMAR SIGN SHAN TONE-3;Mc;0;L;;;;;N;;;;; +1089;MYANMAR SIGN SHAN TONE-5;Mc;0;L;;;;;N;;;;; +108A;MYANMAR SIGN SHAN TONE-6;Mc;0;L;;;;;N;;;;; +108B;MYANMAR SIGN SHAN COUNCIL TONE-2;Mc;0;L;;;;;N;;;;; +108C;MYANMAR SIGN SHAN COUNCIL TONE-3;Mc;0;L;;;;;N;;;;; +108D;MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE;Mn;220;NSM;;;;;N;;;;; +108E;MYANMAR LETTER RUMAI PALAUNG FA;Lo;0;L;;;;;N;;;;; +108F;MYANMAR SIGN RUMAI PALAUNG TONE-5;Mc;0;L;;;;;N;;;;; +1090;MYANMAR SHAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1091;MYANMAR SHAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1092;MYANMAR SHAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1093;MYANMAR SHAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1094;MYANMAR SHAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1095;MYANMAR SHAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1096;MYANMAR SHAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1097;MYANMAR SHAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1098;MYANMAR SHAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1099;MYANMAR SHAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +109E;MYANMAR SYMBOL SHAN ONE;So;0;L;;;;;N;;;;; +109F;MYANMAR SYMBOL SHAN EXCLAMATION;So;0;L;;;;;N;;;;; +10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;Khutsuri;;2D00; +10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;Khutsuri;;2D01; +10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;Khutsuri;;2D02; +10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;Khutsuri;;2D03; +10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;Khutsuri;;2D04; +10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;Khutsuri;;2D05; +10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;Khutsuri;;2D06; +10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;Khutsuri;;2D07; +10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;Khutsuri;;2D08; +10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;Khutsuri;;2D09; +10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;Khutsuri;;2D0A; +10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;Khutsuri;;2D0B; +10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;Khutsuri;;2D0C; +10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;Khutsuri;;2D0D; +10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;Khutsuri;;2D0E; +10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;Khutsuri;;2D0F; +10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;Khutsuri;;2D10; +10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;Khutsuri;;2D11; +10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;Khutsuri;;2D12; +10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;Khutsuri;;2D13; +10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;Khutsuri;;2D14; +10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;Khutsuri;;2D15; +10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;Khutsuri;;2D16; +10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;Khutsuri;;2D17; +10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;Khutsuri;;2D18; +10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;Khutsuri;;2D19; +10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;Khutsuri;;2D1A; +10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;Khutsuri;;2D1B; +10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;Khutsuri;;2D1C; +10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;Khutsuri;;2D1D; +10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;Khutsuri;;2D1E; +10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;Khutsuri;;2D1F; +10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;Khutsuri;;2D20; +10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;Khutsuri;;2D21; +10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;Khutsuri;;2D22; +10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;Khutsuri;;2D23; +10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;Khutsuri;;2D24; +10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;Khutsuri;;2D25; 10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;; 10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;; 10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;; @@ -3079,7 +3424,10 @@ 10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;; 10F7;GEORGIAN LETTER YN;Lo;0;L;;;;;N;;;;; 10F8;GEORGIAN LETTER ELIFI;Lo;0;L;;;;;N;;;;; +10F9;GEORGIAN LETTER TURNED GAN;Lo;0;L;;;;;N;;;;; +10FA;GEORGIAN LETTER AIN;Lo;0;L;;;;;N;;;;; 10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; +10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L;<super> 10DC;;;;N;;;;; 1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;; 1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;; 1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;n *;;; @@ -3327,6 +3675,7 @@ 1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;; 1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;; 1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;; +1207;ETHIOPIC SYLLABLE HOA;Lo;0;L;;;;;N;;;;; 1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;; 1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;; 120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;; @@ -3390,6 +3739,7 @@ 1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;; 1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;; 1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;; +1247;ETHIOPIC SYLLABLE QOA;Lo;0;L;;;;;N;;;;; 1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;; 124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;; 124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;; @@ -3446,6 +3796,7 @@ 1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;; 1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;; 1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;; +1287;ETHIOPIC SYLLABLE XOA;Lo;0;L;;;;;N;;;;; 1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;; 128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;; 128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;; @@ -3482,6 +3833,7 @@ 12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;; 12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;; 12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;; +12AF;ETHIOPIC SYLLABLE KOA;Lo;0;L;;;;;N;;;;; 12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;; 12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;; 12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;; @@ -3506,6 +3858,7 @@ 12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;; 12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;; 12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;; +12CF;ETHIOPIC SYLLABLE WOA;Lo;0;L;;;;;N;;;;; 12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;; 12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;; 12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;; @@ -3536,6 +3889,7 @@ 12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;; 12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;; 12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;; +12EF;ETHIOPIC SYLLABLE YOA;Lo;0;L;;;;;N;;;;; 12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;; 12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;; 12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;; @@ -3567,6 +3921,7 @@ 130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;; 130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;; 130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;; +130F;ETHIOPIC SYLLABLE GOA;Lo;0;L;;;;;N;;;;; 1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;; 1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;; 1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;; @@ -3579,6 +3934,7 @@ 131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;; 131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;; 131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;; +131F;ETHIOPIC SYLLABLE GGWAA;Lo;0;L;;;;;N;;;;; 1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;; 1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;; 1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;; @@ -3618,6 +3974,7 @@ 1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;; 1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;; 1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;; +1347;ETHIOPIC SYLLABLE TZOA;Lo;0;L;;;;;N;;;;; 1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;; 1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;; 134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;; @@ -3637,6 +3994,8 @@ 1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;; 1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;; 135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;; +135F;ETHIOPIC COMBINING GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; +1360;ETHIOPIC SECTION MARK;So;0;L;;;;;N;;;;; 1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;; 1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;; 1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;; @@ -3645,15 +4004,15 @@ 1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;; 1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;; 1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; -1369;ETHIOPIC DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -136A;ETHIOPIC DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -136B;ETHIOPIC DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -136C;ETHIOPIC DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -136D;ETHIOPIC DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -136E;ETHIOPIC DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -136F;ETHIOPIC DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1370;ETHIOPIC DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1371;ETHIOPIC DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1369;ETHIOPIC DIGIT ONE;No;0;L;;;1;1;N;;;;; +136A;ETHIOPIC DIGIT TWO;No;0;L;;;2;2;N;;;;; +136B;ETHIOPIC DIGIT THREE;No;0;L;;;3;3;N;;;;; +136C;ETHIOPIC DIGIT FOUR;No;0;L;;;4;4;N;;;;; +136D;ETHIOPIC DIGIT FIVE;No;0;L;;;5;5;N;;;;; +136E;ETHIOPIC DIGIT SIX;No;0;L;;;6;6;N;;;;; +136F;ETHIOPIC DIGIT SEVEN;No;0;L;;;7;7;N;;;;; +1370;ETHIOPIC DIGIT EIGHT;No;0;L;;;8;8;N;;;;; +1371;ETHIOPIC DIGIT NINE;No;0;L;;;9;9;N;;;;; 1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;; 1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;; 1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;; @@ -3665,6 +4024,32 @@ 137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;; 137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;; 137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;; +1380;ETHIOPIC SYLLABLE SEBATBEIT MWA;Lo;0;L;;;;;N;;;;; +1381;ETHIOPIC SYLLABLE MWI;Lo;0;L;;;;;N;;;;; +1382;ETHIOPIC SYLLABLE MWEE;Lo;0;L;;;;;N;;;;; +1383;ETHIOPIC SYLLABLE MWE;Lo;0;L;;;;;N;;;;; +1384;ETHIOPIC SYLLABLE SEBATBEIT BWA;Lo;0;L;;;;;N;;;;; +1385;ETHIOPIC SYLLABLE BWI;Lo;0;L;;;;;N;;;;; +1386;ETHIOPIC SYLLABLE BWEE;Lo;0;L;;;;;N;;;;; +1387;ETHIOPIC SYLLABLE BWE;Lo;0;L;;;;;N;;;;; +1388;ETHIOPIC SYLLABLE SEBATBEIT FWA;Lo;0;L;;;;;N;;;;; +1389;ETHIOPIC SYLLABLE FWI;Lo;0;L;;;;;N;;;;; +138A;ETHIOPIC SYLLABLE FWEE;Lo;0;L;;;;;N;;;;; +138B;ETHIOPIC SYLLABLE FWE;Lo;0;L;;;;;N;;;;; +138C;ETHIOPIC SYLLABLE SEBATBEIT PWA;Lo;0;L;;;;;N;;;;; +138D;ETHIOPIC SYLLABLE PWI;Lo;0;L;;;;;N;;;;; +138E;ETHIOPIC SYLLABLE PWEE;Lo;0;L;;;;;N;;;;; +138F;ETHIOPIC SYLLABLE PWE;Lo;0;L;;;;;N;;;;; +1390;ETHIOPIC TONAL MARK YIZET;So;0;ON;;;;;N;;;;; +1391;ETHIOPIC TONAL MARK DERET;So;0;ON;;;;;N;;;;; +1392;ETHIOPIC TONAL MARK RIKRIK;So;0;ON;;;;;N;;;;; +1393;ETHIOPIC TONAL MARK SHORT RIKRIK;So;0;ON;;;;;N;;;;; +1394;ETHIOPIC TONAL MARK DIFAT;So;0;ON;;;;;N;;;;; +1395;ETHIOPIC TONAL MARK KENAT;So;0;ON;;;;;N;;;;; +1396;ETHIOPIC TONAL MARK CHIRET;So;0;ON;;;;;N;;;;; +1397;ETHIOPIC TONAL MARK HIDET;So;0;ON;;;;;N;;;;; +1398;ETHIOPIC TONAL MARK DERET-HIDET;So;0;ON;;;;;N;;;;; +1399;ETHIOPIC TONAL MARK KURT;So;0;ON;;;;;N;;;;; 13A0;CHEROKEE LETTER A;Lo;0;L;;;;;N;;;;; 13A1;CHEROKEE LETTER E;Lo;0;L;;;;;N;;;;; 13A2;CHEROKEE LETTER I;Lo;0;L;;;;;N;;;;; @@ -4407,8 +4792,8 @@ 1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;; 1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;; 169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;; -169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;N;;;;; -169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;N;;;;; +169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;Y;;;;; +169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;Y;;;;; 16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;; 16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;; 16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;; @@ -4840,6 +5225,7 @@ 18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;; 18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;; 18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;; +18AA;MONGOLIAN LETTER MANCHU ALI GALI LHA;Lo;0;L;;;;;N;;;;; 1900;LIMBU VOWEL-CARRIER LETTER;Lo;0;L;;;;;N;;;;; 1901;LIMBU LETTER KA;Lo;0;L;;;;;N;;;;; 1902;LIMBU LETTER KHA;Lo;0;L;;;;;N;;;;; @@ -4878,9 +5264,9 @@ 1926;LIMBU VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; 1927;LIMBU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; 1928;LIMBU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -1929;LIMBU SUBJOINED LETTER YA;Mc;0;NSM;;;;;N;;;;; -192A;LIMBU SUBJOINED LETTER RA;Mc;0;NSM;;;;;N;;;;; -192B;LIMBU SUBJOINED LETTER WA;Mc;0;NSM;;;;;N;;;;; +1929;LIMBU SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; +192A;LIMBU SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;; +192B;LIMBU SUBJOINED LETTER WA;Mc;0;L;;;;;N;;;;; 1930;LIMBU SMALL LETTER KA;Mc;0;L;;;;;N;;;;; 1931;LIMBU SMALL LETTER NGA;Mc;0;L;;;;;N;;;;; 1932;LIMBU SMALL LETTER ANUSVARA;Mn;0;NSM;;;;;N;;;;; @@ -4941,6 +5327,86 @@ 1972;TAI LE LETTER TONE-4;Lo;0;L;;;;;N;;;;; 1973;TAI LE LETTER TONE-5;Lo;0;L;;;;;N;;;;; 1974;TAI LE LETTER TONE-6;Lo;0;L;;;;;N;;;;; +1980;NEW TAI LUE LETTER HIGH QA;Lo;0;L;;;;;N;;;;; +1981;NEW TAI LUE LETTER LOW QA;Lo;0;L;;;;;N;;;;; +1982;NEW TAI LUE LETTER HIGH KA;Lo;0;L;;;;;N;;;;; +1983;NEW TAI LUE LETTER HIGH XA;Lo;0;L;;;;;N;;;;; +1984;NEW TAI LUE LETTER HIGH NGA;Lo;0;L;;;;;N;;;;; +1985;NEW TAI LUE LETTER LOW KA;Lo;0;L;;;;;N;;;;; +1986;NEW TAI LUE LETTER LOW XA;Lo;0;L;;;;;N;;;;; +1987;NEW TAI LUE LETTER LOW NGA;Lo;0;L;;;;;N;;;;; +1988;NEW TAI LUE LETTER HIGH TSA;Lo;0;L;;;;;N;;;;; +1989;NEW TAI LUE LETTER HIGH SA;Lo;0;L;;;;;N;;;;; +198A;NEW TAI LUE LETTER HIGH YA;Lo;0;L;;;;;N;;;;; +198B;NEW TAI LUE LETTER LOW TSA;Lo;0;L;;;;;N;;;;; +198C;NEW TAI LUE LETTER LOW SA;Lo;0;L;;;;;N;;;;; +198D;NEW TAI LUE LETTER LOW YA;Lo;0;L;;;;;N;;;;; +198E;NEW TAI LUE LETTER HIGH TA;Lo;0;L;;;;;N;;;;; +198F;NEW TAI LUE LETTER HIGH THA;Lo;0;L;;;;;N;;;;; +1990;NEW TAI LUE LETTER HIGH NA;Lo;0;L;;;;;N;;;;; +1991;NEW TAI LUE LETTER LOW TA;Lo;0;L;;;;;N;;;;; +1992;NEW TAI LUE LETTER LOW THA;Lo;0;L;;;;;N;;;;; +1993;NEW TAI LUE LETTER LOW NA;Lo;0;L;;;;;N;;;;; +1994;NEW TAI LUE LETTER HIGH PA;Lo;0;L;;;;;N;;;;; +1995;NEW TAI LUE LETTER HIGH PHA;Lo;0;L;;;;;N;;;;; +1996;NEW TAI LUE LETTER HIGH MA;Lo;0;L;;;;;N;;;;; +1997;NEW TAI LUE LETTER LOW PA;Lo;0;L;;;;;N;;;;; +1998;NEW TAI LUE LETTER LOW PHA;Lo;0;L;;;;;N;;;;; +1999;NEW TAI LUE LETTER LOW MA;Lo;0;L;;;;;N;;;;; +199A;NEW TAI LUE LETTER HIGH FA;Lo;0;L;;;;;N;;;;; +199B;NEW TAI LUE LETTER HIGH VA;Lo;0;L;;;;;N;;;;; +199C;NEW TAI LUE LETTER HIGH LA;Lo;0;L;;;;;N;;;;; +199D;NEW TAI LUE LETTER LOW FA;Lo;0;L;;;;;N;;;;; +199E;NEW TAI LUE LETTER LOW VA;Lo;0;L;;;;;N;;;;; +199F;NEW TAI LUE LETTER LOW LA;Lo;0;L;;;;;N;;;;; +19A0;NEW TAI LUE LETTER HIGH HA;Lo;0;L;;;;;N;;;;; +19A1;NEW TAI LUE LETTER HIGH DA;Lo;0;L;;;;;N;;;;; +19A2;NEW TAI LUE LETTER HIGH BA;Lo;0;L;;;;;N;;;;; +19A3;NEW TAI LUE LETTER LOW HA;Lo;0;L;;;;;N;;;;; +19A4;NEW TAI LUE LETTER LOW DA;Lo;0;L;;;;;N;;;;; +19A5;NEW TAI LUE LETTER LOW BA;Lo;0;L;;;;;N;;;;; +19A6;NEW TAI LUE LETTER HIGH KVA;Lo;0;L;;;;;N;;;;; +19A7;NEW TAI LUE LETTER HIGH XVA;Lo;0;L;;;;;N;;;;; +19A8;NEW TAI LUE LETTER LOW KVA;Lo;0;L;;;;;N;;;;; +19A9;NEW TAI LUE LETTER LOW XVA;Lo;0;L;;;;;N;;;;; +19B0;NEW TAI LUE VOWEL SIGN VOWEL SHORTENER;Mc;0;L;;;;;N;;;;; +19B1;NEW TAI LUE VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +19B2;NEW TAI LUE VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +19B3;NEW TAI LUE VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +19B4;NEW TAI LUE VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +19B5;NEW TAI LUE VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +19B6;NEW TAI LUE VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; +19B7;NEW TAI LUE VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +19B8;NEW TAI LUE VOWEL SIGN OA;Mc;0;L;;;;;N;;;;; +19B9;NEW TAI LUE VOWEL SIGN UE;Mc;0;L;;;;;N;;;;; +19BA;NEW TAI LUE VOWEL SIGN AY;Mc;0;L;;;;;N;;;;; +19BB;NEW TAI LUE VOWEL SIGN AAY;Mc;0;L;;;;;N;;;;; +19BC;NEW TAI LUE VOWEL SIGN UY;Mc;0;L;;;;;N;;;;; +19BD;NEW TAI LUE VOWEL SIGN OY;Mc;0;L;;;;;N;;;;; +19BE;NEW TAI LUE VOWEL SIGN OAY;Mc;0;L;;;;;N;;;;; +19BF;NEW TAI LUE VOWEL SIGN UEY;Mc;0;L;;;;;N;;;;; +19C0;NEW TAI LUE VOWEL SIGN IY;Mc;0;L;;;;;N;;;;; +19C1;NEW TAI LUE LETTER FINAL V;Lo;0;L;;;;;N;;;;; +19C2;NEW TAI LUE LETTER FINAL NG;Lo;0;L;;;;;N;;;;; +19C3;NEW TAI LUE LETTER FINAL N;Lo;0;L;;;;;N;;;;; +19C4;NEW TAI LUE LETTER FINAL M;Lo;0;L;;;;;N;;;;; +19C5;NEW TAI LUE LETTER FINAL K;Lo;0;L;;;;;N;;;;; +19C6;NEW TAI LUE LETTER FINAL D;Lo;0;L;;;;;N;;;;; +19C7;NEW TAI LUE LETTER FINAL B;Lo;0;L;;;;;N;;;;; +19C8;NEW TAI LUE TONE MARK-1;Mc;0;L;;;;;N;;;;; +19C9;NEW TAI LUE TONE MARK-2;Mc;0;L;;;;;N;;;;; +19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +19D3;NEW TAI LUE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +19D4;NEW TAI LUE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +19D5;NEW TAI LUE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +19D6;NEW TAI LUE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +19DE;NEW TAI LUE SIGN LAE;Po;0;ON;;;;;N;;;;; +19DF;NEW TAI LUE SIGN LAEV;Po;0;ON;;;;;N;;;;; 19E0;KHMER SYMBOL PATHAMASAT;So;0;ON;;;;;N;;;;; 19E1;KHMER SYMBOL MUOY KOET;So;0;ON;;;;;N;;;;; 19E2;KHMER SYMBOL PII KOET;So;0;ON;;;;;N;;;;; @@ -4973,6 +5439,334 @@ 19FD;KHMER SYMBOL DAP-BEI ROC;So;0;ON;;;;;N;;;;; 19FE;KHMER SYMBOL DAP-BUON ROC;So;0;ON;;;;;N;;;;; 19FF;KHMER SYMBOL DAP-PRAM ROC;So;0;ON;;;;;N;;;;; +1A00;BUGINESE LETTER KA;Lo;0;L;;;;;N;;;;; +1A01;BUGINESE LETTER GA;Lo;0;L;;;;;N;;;;; +1A02;BUGINESE LETTER NGA;Lo;0;L;;;;;N;;;;; +1A03;BUGINESE LETTER NGKA;Lo;0;L;;;;;N;;;;; +1A04;BUGINESE LETTER PA;Lo;0;L;;;;;N;;;;; +1A05;BUGINESE LETTER BA;Lo;0;L;;;;;N;;;;; +1A06;BUGINESE LETTER MA;Lo;0;L;;;;;N;;;;; +1A07;BUGINESE LETTER MPA;Lo;0;L;;;;;N;;;;; +1A08;BUGINESE LETTER TA;Lo;0;L;;;;;N;;;;; +1A09;BUGINESE LETTER DA;Lo;0;L;;;;;N;;;;; +1A0A;BUGINESE LETTER NA;Lo;0;L;;;;;N;;;;; +1A0B;BUGINESE LETTER NRA;Lo;0;L;;;;;N;;;;; +1A0C;BUGINESE LETTER CA;Lo;0;L;;;;;N;;;;; +1A0D;BUGINESE LETTER JA;Lo;0;L;;;;;N;;;;; +1A0E;BUGINESE LETTER NYA;Lo;0;L;;;;;N;;;;; +1A0F;BUGINESE LETTER NYCA;Lo;0;L;;;;;N;;;;; +1A10;BUGINESE LETTER YA;Lo;0;L;;;;;N;;;;; +1A11;BUGINESE LETTER RA;Lo;0;L;;;;;N;;;;; +1A12;BUGINESE LETTER LA;Lo;0;L;;;;;N;;;;; +1A13;BUGINESE LETTER VA;Lo;0;L;;;;;N;;;;; +1A14;BUGINESE LETTER SA;Lo;0;L;;;;;N;;;;; +1A15;BUGINESE LETTER A;Lo;0;L;;;;;N;;;;; +1A16;BUGINESE LETTER HA;Lo;0;L;;;;;N;;;;; +1A17;BUGINESE VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;; +1A18;BUGINESE VOWEL SIGN U;Mn;220;NSM;;;;;N;;;;; +1A19;BUGINESE VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1A1A;BUGINESE VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +1A1B;BUGINESE VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; +1A1E;BUGINESE PALLAWA;Po;0;L;;;;;N;;;;; +1A1F;BUGINESE END OF SECTION;Po;0;L;;;;;N;;;;; +1B00;BALINESE SIGN ULU RICEM;Mn;0;NSM;;;;;N;;ardhacandra;;; +1B01;BALINESE SIGN ULU CANDRA;Mn;0;NSM;;;;;N;;candrabindu;;; +1B02;BALINESE SIGN CECEK;Mn;0;NSM;;;;;N;;anusvara;;; +1B03;BALINESE SIGN SURANG;Mn;0;NSM;;;;;N;;repha;;; +1B04;BALINESE SIGN BISAH;Mc;0;L;;;;;N;;visarga;;; +1B05;BALINESE LETTER AKARA;Lo;0;L;;;;;N;;a;;; +1B06;BALINESE LETTER AKARA TEDUNG;Lo;0;L;1B05 1B35;;;;N;;aa;;; +1B07;BALINESE LETTER IKARA;Lo;0;L;;;;;N;;i;;; +1B08;BALINESE LETTER IKARA TEDUNG;Lo;0;L;1B07 1B35;;;;N;;ii;;; +1B09;BALINESE LETTER UKARA;Lo;0;L;;;;;N;;u;;; +1B0A;BALINESE LETTER UKARA TEDUNG;Lo;0;L;1B09 1B35;;;;N;;uu;;; +1B0B;BALINESE LETTER RA REPA;Lo;0;L;;;;;N;;vocalic r;;; +1B0C;BALINESE LETTER RA REPA TEDUNG;Lo;0;L;1B0B 1B35;;;;N;;vocalic rr;;; +1B0D;BALINESE LETTER LA LENGA;Lo;0;L;;;;;N;;vocalic l;;; +1B0E;BALINESE LETTER LA LENGA TEDUNG;Lo;0;L;1B0D 1B35;;;;N;;vocalic ll;;; +1B0F;BALINESE LETTER EKARA;Lo;0;L;;;;;N;;e;;; +1B10;BALINESE LETTER AIKARA;Lo;0;L;;;;;N;;ai;;; +1B11;BALINESE LETTER OKARA;Lo;0;L;;;;;N;;o;;; +1B12;BALINESE LETTER OKARA TEDUNG;Lo;0;L;1B11 1B35;;;;N;;au;;; +1B13;BALINESE LETTER KA;Lo;0;L;;;;;N;;;;; +1B14;BALINESE LETTER KA MAHAPRANA;Lo;0;L;;;;;N;;kha;;; +1B15;BALINESE LETTER GA;Lo;0;L;;;;;N;;;;; +1B16;BALINESE LETTER GA GORA;Lo;0;L;;;;;N;;gha;;; +1B17;BALINESE LETTER NGA;Lo;0;L;;;;;N;;;;; +1B18;BALINESE LETTER CA;Lo;0;L;;;;;N;;;;; +1B19;BALINESE LETTER CA LACA;Lo;0;L;;;;;N;;cha;;; +1B1A;BALINESE LETTER JA;Lo;0;L;;;;;N;;;;; +1B1B;BALINESE LETTER JA JERA;Lo;0;L;;;;;N;;jha;;; +1B1C;BALINESE LETTER NYA;Lo;0;L;;;;;N;;;;; +1B1D;BALINESE LETTER TA LATIK;Lo;0;L;;;;;N;;tta;;; +1B1E;BALINESE LETTER TA MURDA MAHAPRANA;Lo;0;L;;;;;N;;ttha;;; +1B1F;BALINESE LETTER DA MURDA ALPAPRANA;Lo;0;L;;;;;N;;dda;;; +1B20;BALINESE LETTER DA MURDA MAHAPRANA;Lo;0;L;;;;;N;;ddha;;; +1B21;BALINESE LETTER NA RAMBAT;Lo;0;L;;;;;N;;nna;;; +1B22;BALINESE LETTER TA;Lo;0;L;;;;;N;;;;; +1B23;BALINESE LETTER TA TAWA;Lo;0;L;;;;;N;;tha;;; +1B24;BALINESE LETTER DA;Lo;0;L;;;;;N;;;;; +1B25;BALINESE LETTER DA MADU;Lo;0;L;;;;;N;;dha;;; +1B26;BALINESE LETTER NA;Lo;0;L;;;;;N;;;;; +1B27;BALINESE LETTER PA;Lo;0;L;;;;;N;;;;; +1B28;BALINESE LETTER PA KAPAL;Lo;0;L;;;;;N;;pha;;; +1B29;BALINESE LETTER BA;Lo;0;L;;;;;N;;;;; +1B2A;BALINESE LETTER BA KEMBANG;Lo;0;L;;;;;N;;bha;;; +1B2B;BALINESE LETTER MA;Lo;0;L;;;;;N;;;;; +1B2C;BALINESE LETTER YA;Lo;0;L;;;;;N;;;;; +1B2D;BALINESE LETTER RA;Lo;0;L;;;;;N;;;;; +1B2E;BALINESE LETTER LA;Lo;0;L;;;;;N;;;;; +1B2F;BALINESE LETTER WA;Lo;0;L;;;;;N;;;;; +1B30;BALINESE LETTER SA SAGA;Lo;0;L;;;;;N;;sha;;; +1B31;BALINESE LETTER SA SAPA;Lo;0;L;;;;;N;;ssa;;; +1B32;BALINESE LETTER SA;Lo;0;L;;;;;N;;;;; +1B33;BALINESE LETTER HA;Lo;0;L;;;;;N;;;;; +1B34;BALINESE SIGN REREKAN;Mn;7;NSM;;;;;N;;nukta;;; +1B35;BALINESE VOWEL SIGN TEDUNG;Mc;0;L;;;;;N;;aa;;; +1B36;BALINESE VOWEL SIGN ULU;Mn;0;NSM;;;;;N;;i;;; +1B37;BALINESE VOWEL SIGN ULU SARI;Mn;0;NSM;;;;;N;;ii;;; +1B38;BALINESE VOWEL SIGN SUKU;Mn;0;NSM;;;;;N;;u;;; +1B39;BALINESE VOWEL SIGN SUKU ILUT;Mn;0;NSM;;;;;N;;uu;;; +1B3A;BALINESE VOWEL SIGN RA REPA;Mn;0;NSM;;;;;N;;vocalic r;;; +1B3B;BALINESE VOWEL SIGN RA REPA TEDUNG;Mc;0;L;1B3A 1B35;;;;N;;vocalic rr;;; +1B3C;BALINESE VOWEL SIGN LA LENGA;Mn;0;NSM;;;;;N;;vocalic l;;; +1B3D;BALINESE VOWEL SIGN LA LENGA TEDUNG;Mc;0;L;1B3C 1B35;;;;N;;vocalic ll;;; +1B3E;BALINESE VOWEL SIGN TALING;Mc;0;L;;;;;N;;e;;; +1B3F;BALINESE VOWEL SIGN TALING REPA;Mc;0;L;;;;;N;;ai;;; +1B40;BALINESE VOWEL SIGN TALING TEDUNG;Mc;0;L;1B3E 1B35;;;;N;;o;;; +1B41;BALINESE VOWEL SIGN TALING REPA TEDUNG;Mc;0;L;1B3F 1B35;;;;N;;au;;; +1B42;BALINESE VOWEL SIGN PEPET;Mn;0;NSM;;;;;N;;ae;;; +1B43;BALINESE VOWEL SIGN PEPET TEDUNG;Mc;0;L;1B42 1B35;;;;N;;oe;;; +1B44;BALINESE ADEG ADEG;Mc;9;L;;;;;N;;virama;;; +1B45;BALINESE LETTER KAF SASAK;Lo;0;L;;;;;N;;;;; +1B46;BALINESE LETTER KHOT SASAK;Lo;0;L;;;;;N;;;;; +1B47;BALINESE LETTER TZIR SASAK;Lo;0;L;;;;;N;;;;; +1B48;BALINESE LETTER EF SASAK;Lo;0;L;;;;;N;;;;; +1B49;BALINESE LETTER VE SASAK;Lo;0;L;;;;;N;;;;; +1B4A;BALINESE LETTER ZAL SASAK;Lo;0;L;;;;;N;;;;; +1B4B;BALINESE LETTER ASYURA SASAK;Lo;0;L;;;;;N;;;;; +1B50;BALINESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1B51;BALINESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1B52;BALINESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1B53;BALINESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1B54;BALINESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1B55;BALINESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1B56;BALINESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1B57;BALINESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1B58;BALINESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1B59;BALINESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1B5A;BALINESE PANTI;Po;0;L;;;;;N;;section;;; +1B5B;BALINESE PAMADA;Po;0;L;;;;;N;;honorific section;;; +1B5C;BALINESE WINDU;Po;0;L;;;;;N;;punctuation ring;;; +1B5D;BALINESE CARIK PAMUNGKAH;Po;0;L;;;;;N;;colon;;; +1B5E;BALINESE CARIK SIKI;Po;0;L;;;;;N;;danda;;; +1B5F;BALINESE CARIK PAREREN;Po;0;L;;;;;N;;double danda;;; +1B60;BALINESE PAMENENG;Po;0;L;;;;;N;;line-breaking hyphen;;; +1B61;BALINESE MUSICAL SYMBOL DONG;So;0;L;;;;;N;;;;; +1B62;BALINESE MUSICAL SYMBOL DENG;So;0;L;;;;;N;;;;; +1B63;BALINESE MUSICAL SYMBOL DUNG;So;0;L;;;;;N;;;;; +1B64;BALINESE MUSICAL SYMBOL DANG;So;0;L;;;;;N;;;;; +1B65;BALINESE MUSICAL SYMBOL DANG SURANG;So;0;L;;;;;N;;;;; +1B66;BALINESE MUSICAL SYMBOL DING;So;0;L;;;;;N;;;;; +1B67;BALINESE MUSICAL SYMBOL DAENG;So;0;L;;;;;N;;;;; +1B68;BALINESE MUSICAL SYMBOL DEUNG;So;0;L;;;;;N;;;;; +1B69;BALINESE MUSICAL SYMBOL DAING;So;0;L;;;;;N;;;;; +1B6A;BALINESE MUSICAL SYMBOL DANG GEDE;So;0;L;;;;;N;;;;; +1B6B;BALINESE MUSICAL SYMBOL COMBINING TEGEH;Mn;230;NSM;;;;;N;;;;; +1B6C;BALINESE MUSICAL SYMBOL COMBINING ENDEP;Mn;220;NSM;;;;;N;;;;; +1B6D;BALINESE MUSICAL SYMBOL COMBINING KEMPUL;Mn;230;NSM;;;;;N;;;;; +1B6E;BALINESE MUSICAL SYMBOL COMBINING KEMPLI;Mn;230;NSM;;;;;N;;;;; +1B6F;BALINESE MUSICAL SYMBOL COMBINING JEGOGAN;Mn;230;NSM;;;;;N;;;;; +1B70;BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;; +1B71;BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;; +1B72;BALINESE MUSICAL SYMBOL COMBINING BENDE;Mn;230;NSM;;;;;N;;;;; +1B73;BALINESE MUSICAL SYMBOL COMBINING GONG;Mn;230;NSM;;;;;N;;;;; +1B74;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG;So;0;L;;;;;N;;;;; +1B75;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DAG;So;0;L;;;;;N;;;;; +1B76;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TUK;So;0;L;;;;;N;;;;; +1B77;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TAK;So;0;L;;;;;N;;;;; +1B78;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PANG;So;0;L;;;;;N;;;;; +1B79;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PUNG;So;0;L;;;;;N;;;;; +1B7A;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLAK;So;0;L;;;;;N;;;;; +1B7B;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUK;So;0;L;;;;;N;;;;; +1B7C;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING;So;0;L;;;;;N;;;;; +1B80;SUNDANESE SIGN PANYECEK;Mn;0;NSM;;;;;N;;;;; +1B81;SUNDANESE SIGN PANGLAYAR;Mn;0;NSM;;;;;N;;;;; +1B82;SUNDANESE SIGN PANGWISAD;Mc;0;L;;;;;N;;;;; +1B83;SUNDANESE LETTER A;Lo;0;L;;;;;N;;;;; +1B84;SUNDANESE LETTER I;Lo;0;L;;;;;N;;;;; +1B85;SUNDANESE LETTER U;Lo;0;L;;;;;N;;;;; +1B86;SUNDANESE LETTER AE;Lo;0;L;;;;;N;;;;; +1B87;SUNDANESE LETTER O;Lo;0;L;;;;;N;;;;; +1B88;SUNDANESE LETTER E;Lo;0;L;;;;;N;;;;; +1B89;SUNDANESE LETTER EU;Lo;0;L;;;;;N;;;;; +1B8A;SUNDANESE LETTER KA;Lo;0;L;;;;;N;;;;; +1B8B;SUNDANESE LETTER QA;Lo;0;L;;;;;N;;;;; +1B8C;SUNDANESE LETTER GA;Lo;0;L;;;;;N;;;;; +1B8D;SUNDANESE LETTER NGA;Lo;0;L;;;;;N;;;;; +1B8E;SUNDANESE LETTER CA;Lo;0;L;;;;;N;;;;; +1B8F;SUNDANESE LETTER JA;Lo;0;L;;;;;N;;;;; +1B90;SUNDANESE LETTER ZA;Lo;0;L;;;;;N;;;;; +1B91;SUNDANESE LETTER NYA;Lo;0;L;;;;;N;;;;; +1B92;SUNDANESE LETTER TA;Lo;0;L;;;;;N;;;;; +1B93;SUNDANESE LETTER DA;Lo;0;L;;;;;N;;;;; +1B94;SUNDANESE LETTER NA;Lo;0;L;;;;;N;;;;; +1B95;SUNDANESE LETTER PA;Lo;0;L;;;;;N;;;;; +1B96;SUNDANESE LETTER FA;Lo;0;L;;;;;N;;;;; +1B97;SUNDANESE LETTER VA;Lo;0;L;;;;;N;;;;; +1B98;SUNDANESE LETTER BA;Lo;0;L;;;;;N;;;;; +1B99;SUNDANESE LETTER MA;Lo;0;L;;;;;N;;;;; +1B9A;SUNDANESE LETTER YA;Lo;0;L;;;;;N;;;;; +1B9B;SUNDANESE LETTER RA;Lo;0;L;;;;;N;;;;; +1B9C;SUNDANESE LETTER LA;Lo;0;L;;;;;N;;;;; +1B9D;SUNDANESE LETTER WA;Lo;0;L;;;;;N;;;;; +1B9E;SUNDANESE LETTER SA;Lo;0;L;;;;;N;;;;; +1B9F;SUNDANESE LETTER XA;Lo;0;L;;;;;N;;;;; +1BA0;SUNDANESE LETTER HA;Lo;0;L;;;;;N;;;;; +1BA1;SUNDANESE CONSONANT SIGN PAMINGKAL;Mc;0;L;;;;;N;;;;; +1BA2;SUNDANESE CONSONANT SIGN PANYAKRA;Mn;0;NSM;;;;;N;;;;; +1BA3;SUNDANESE CONSONANT SIGN PANYIKU;Mn;0;NSM;;;;;N;;;;; +1BA4;SUNDANESE VOWEL SIGN PANGHULU;Mn;0;NSM;;;;;N;;;;; +1BA5;SUNDANESE VOWEL SIGN PANYUKU;Mn;0;NSM;;;;;N;;;;; +1BA6;SUNDANESE VOWEL SIGN PANAELAENG;Mc;0;L;;;;;N;;;;; +1BA7;SUNDANESE VOWEL SIGN PANOLONG;Mc;0;L;;;;;N;;;;; +1BA8;SUNDANESE VOWEL SIGN PAMEPET;Mn;0;NSM;;;;;N;;;;; +1BA9;SUNDANESE VOWEL SIGN PANEULEUNG;Mn;0;NSM;;;;;N;;;;; +1BAA;SUNDANESE SIGN PAMAAEH;Mc;9;L;;;;;N;;;;; +1BAE;SUNDANESE LETTER KHA;Lo;0;L;;;;;N;;;;; +1BAF;SUNDANESE LETTER SYA;Lo;0;L;;;;;N;;;;; +1BB0;SUNDANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1BB1;SUNDANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1BB2;SUNDANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1BB3;SUNDANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1BB4;SUNDANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1BB5;SUNDANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1BB6;SUNDANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1BB7;SUNDANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1BB8;SUNDANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1BB9;SUNDANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1C00;LEPCHA LETTER KA;Lo;0;L;;;;;N;;;;; +1C01;LEPCHA LETTER KLA;Lo;0;L;;;;;N;;;;; +1C02;LEPCHA LETTER KHA;Lo;0;L;;;;;N;;;;; +1C03;LEPCHA LETTER GA;Lo;0;L;;;;;N;;;;; +1C04;LEPCHA LETTER GLA;Lo;0;L;;;;;N;;;;; +1C05;LEPCHA LETTER NGA;Lo;0;L;;;;;N;;;;; +1C06;LEPCHA LETTER CA;Lo;0;L;;;;;N;;;;; +1C07;LEPCHA LETTER CHA;Lo;0;L;;;;;N;;;;; +1C08;LEPCHA LETTER JA;Lo;0;L;;;;;N;;;;; +1C09;LEPCHA LETTER NYA;Lo;0;L;;;;;N;;;;; +1C0A;LEPCHA LETTER TA;Lo;0;L;;;;;N;;;;; +1C0B;LEPCHA LETTER THA;Lo;0;L;;;;;N;;;;; +1C0C;LEPCHA LETTER DA;Lo;0;L;;;;;N;;;;; +1C0D;LEPCHA LETTER NA;Lo;0;L;;;;;N;;;;; +1C0E;LEPCHA LETTER PA;Lo;0;L;;;;;N;;;;; +1C0F;LEPCHA LETTER PLA;Lo;0;L;;;;;N;;;;; +1C10;LEPCHA LETTER PHA;Lo;0;L;;;;;N;;;;; +1C11;LEPCHA LETTER FA;Lo;0;L;;;;;N;;;;; +1C12;LEPCHA LETTER FLA;Lo;0;L;;;;;N;;;;; +1C13;LEPCHA LETTER BA;Lo;0;L;;;;;N;;;;; +1C14;LEPCHA LETTER BLA;Lo;0;L;;;;;N;;;;; +1C15;LEPCHA LETTER MA;Lo;0;L;;;;;N;;;;; +1C16;LEPCHA LETTER MLA;Lo;0;L;;;;;N;;;;; +1C17;LEPCHA LETTER TSA;Lo;0;L;;;;;N;;;;; +1C18;LEPCHA LETTER TSHA;Lo;0;L;;;;;N;;;;; +1C19;LEPCHA LETTER DZA;Lo;0;L;;;;;N;;;;; +1C1A;LEPCHA LETTER YA;Lo;0;L;;;;;N;;;;; +1C1B;LEPCHA LETTER RA;Lo;0;L;;;;;N;;;;; +1C1C;LEPCHA LETTER LA;Lo;0;L;;;;;N;;;;; +1C1D;LEPCHA LETTER HA;Lo;0;L;;;;;N;;;;; +1C1E;LEPCHA LETTER HLA;Lo;0;L;;;;;N;;;;; +1C1F;LEPCHA LETTER VA;Lo;0;L;;;;;N;;;;; +1C20;LEPCHA LETTER SA;Lo;0;L;;;;;N;;;;; +1C21;LEPCHA LETTER SHA;Lo;0;L;;;;;N;;;;; +1C22;LEPCHA LETTER WA;Lo;0;L;;;;;N;;;;; +1C23;LEPCHA LETTER A;Lo;0;L;;;;;N;;;;; +1C24;LEPCHA SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; +1C25;LEPCHA SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;; +1C26;LEPCHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +1C27;LEPCHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +1C28;LEPCHA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +1C29;LEPCHA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +1C2A;LEPCHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +1C2B;LEPCHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +1C2C;LEPCHA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +1C2D;LEPCHA CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;; +1C2E;LEPCHA CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;; +1C2F;LEPCHA CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;; +1C30;LEPCHA CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;; +1C31;LEPCHA CONSONANT SIGN P;Mn;0;NSM;;;;;N;;;;; +1C32;LEPCHA CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;; +1C33;LEPCHA CONSONANT SIGN T;Mn;0;NSM;;;;;N;;;;; +1C34;LEPCHA CONSONANT SIGN NYIN-DO;Mc;0;L;;;;;N;;;;; +1C35;LEPCHA CONSONANT SIGN KANG;Mc;0;L;;;;;N;;;;; +1C36;LEPCHA SIGN RAN;Mn;0;NSM;;;;;N;;;;; +1C37;LEPCHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +1C3B;LEPCHA PUNCTUATION TA-ROL;Po;0;L;;;;;N;;;;; +1C3C;LEPCHA PUNCTUATION NYET THYOOM TA-ROL;Po;0;L;;;;;N;;;;; +1C3D;LEPCHA PUNCTUATION CER-WA;Po;0;L;;;;;N;;;;; +1C3E;LEPCHA PUNCTUATION TSHOOK CER-WA;Po;0;L;;;;;N;;;;; +1C3F;LEPCHA PUNCTUATION TSHOOK;Po;0;L;;;;;N;;;;; +1C40;LEPCHA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1C41;LEPCHA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1C42;LEPCHA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1C43;LEPCHA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1C44;LEPCHA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1C45;LEPCHA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1C46;LEPCHA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1C47;LEPCHA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1C48;LEPCHA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1C49;LEPCHA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1C4D;LEPCHA LETTER TTA;Lo;0;L;;;;;N;;;;; +1C4E;LEPCHA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1C4F;LEPCHA LETTER DDA;Lo;0;L;;;;;N;;;;; +1C50;OL CHIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1C51;OL CHIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1C52;OL CHIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1C53;OL CHIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1C54;OL CHIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1C55;OL CHIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1C56;OL CHIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1C57;OL CHIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1C58;OL CHIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1C59;OL CHIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1C5A;OL CHIKI LETTER LA;Lo;0;L;;;;;N;;;;; +1C5B;OL CHIKI LETTER AT;Lo;0;L;;;;;N;;;;; +1C5C;OL CHIKI LETTER AG;Lo;0;L;;;;;N;;;;; +1C5D;OL CHIKI LETTER ANG;Lo;0;L;;;;;N;;;;; +1C5E;OL CHIKI LETTER AL;Lo;0;L;;;;;N;;;;; +1C5F;OL CHIKI LETTER LAA;Lo;0;L;;;;;N;;;;; +1C60;OL CHIKI LETTER AAK;Lo;0;L;;;;;N;;;;; +1C61;OL CHIKI LETTER AAJ;Lo;0;L;;;;;N;;;;; +1C62;OL CHIKI LETTER AAM;Lo;0;L;;;;;N;;;;; +1C63;OL CHIKI LETTER AAW;Lo;0;L;;;;;N;;;;; +1C64;OL CHIKI LETTER LI;Lo;0;L;;;;;N;;;;; +1C65;OL CHIKI LETTER IS;Lo;0;L;;;;;N;;;;; +1C66;OL CHIKI LETTER IH;Lo;0;L;;;;;N;;;;; +1C67;OL CHIKI LETTER INY;Lo;0;L;;;;;N;;;;; +1C68;OL CHIKI LETTER IR;Lo;0;L;;;;;N;;;;; +1C69;OL CHIKI LETTER LU;Lo;0;L;;;;;N;;;;; +1C6A;OL CHIKI LETTER UC;Lo;0;L;;;;;N;;;;; +1C6B;OL CHIKI LETTER UD;Lo;0;L;;;;;N;;;;; +1C6C;OL CHIKI LETTER UNN;Lo;0;L;;;;;N;;;;; +1C6D;OL CHIKI LETTER UY;Lo;0;L;;;;;N;;;;; +1C6E;OL CHIKI LETTER LE;Lo;0;L;;;;;N;;;;; +1C6F;OL CHIKI LETTER EP;Lo;0;L;;;;;N;;;;; +1C70;OL CHIKI LETTER EDD;Lo;0;L;;;;;N;;;;; +1C71;OL CHIKI LETTER EN;Lo;0;L;;;;;N;;;;; +1C72;OL CHIKI LETTER ERR;Lo;0;L;;;;;N;;;;; +1C73;OL CHIKI LETTER LO;Lo;0;L;;;;;N;;;;; +1C74;OL CHIKI LETTER OTT;Lo;0;L;;;;;N;;;;; +1C75;OL CHIKI LETTER OB;Lo;0;L;;;;;N;;;;; +1C76;OL CHIKI LETTER OV;Lo;0;L;;;;;N;;;;; +1C77;OL CHIKI LETTER OH;Lo;0;L;;;;;N;;;;; +1C78;OL CHIKI MU TTUDDAG;Lm;0;L;;;;;N;;;;; +1C79;OL CHIKI GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;; +1C7A;OL CHIKI MU-GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;; +1C7B;OL CHIKI RELAA;Lm;0;L;;;;;N;;;;; +1C7C;OL CHIKI PHAARKAA;Lm;0;L;;;;;N;;;;; +1C7D;OL CHIKI AHAD;Lm;0;L;;;;;N;;;;; +1C7E;OL CHIKI PUNCTUATION MUCAAD;Po;0;L;;;;;N;;;;; +1C7F;OL CHIKI PUNCTUATION DOUBLE MUCAAD;Po;0;L;;;;;N;;;;; 1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;; 1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;; 1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;; @@ -5081,6 +5875,131 @@ 1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Ll;0;L;<sub> 03C6;;;;N;;;;; 1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Ll;0;L;<sub> 03C7;;;;N;;;;; 1D6B;LATIN SMALL LETTER UE;Ll;0;L;;;;;N;;;;; +1D6C;LATIN SMALL LETTER B WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D6D;LATIN SMALL LETTER D WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D6E;LATIN SMALL LETTER F WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D6F;LATIN SMALL LETTER M WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D70;LATIN SMALL LETTER N WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D71;LATIN SMALL LETTER P WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D72;LATIN SMALL LETTER R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D73;LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D74;LATIN SMALL LETTER S WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D75;LATIN SMALL LETTER T WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D76;LATIN SMALL LETTER Z WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D77;LATIN SMALL LETTER TURNED G;Ll;0;L;;;;;N;;;;; +1D78;MODIFIER LETTER CYRILLIC EN;Lm;0;L;<super> 043D;;;;N;;;;; +1D79;LATIN SMALL LETTER INSULAR G;Ll;0;L;;;;;N;;;A77D;;A77D +1D7A;LATIN SMALL LETTER TH WITH STRIKETHROUGH;Ll;0;L;;;;;N;;;;; +1D7B;LATIN SMALL CAPITAL LETTER I WITH STROKE;Ll;0;L;;;;;N;;;;; +1D7C;LATIN SMALL LETTER IOTA WITH STROKE;Ll;0;L;;;;;N;;;;; +1D7D;LATIN SMALL LETTER P WITH STROKE;Ll;0;L;;;;;N;;;2C63;;2C63 +1D7E;LATIN SMALL CAPITAL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;;; +1D7F;LATIN SMALL LETTER UPSILON WITH STROKE;Ll;0;L;;;;;N;;;;; +1D80;LATIN SMALL LETTER B WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D81;LATIN SMALL LETTER D WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D82;LATIN SMALL LETTER F WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D83;LATIN SMALL LETTER G WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D84;LATIN SMALL LETTER K WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D85;LATIN SMALL LETTER L WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D86;LATIN SMALL LETTER M WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D87;LATIN SMALL LETTER N WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D88;LATIN SMALL LETTER P WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D89;LATIN SMALL LETTER R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8A;LATIN SMALL LETTER S WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8B;LATIN SMALL LETTER ESH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8C;LATIN SMALL LETTER V WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8D;LATIN SMALL LETTER X WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8E;LATIN SMALL LETTER Z WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8F;LATIN SMALL LETTER A WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D90;LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D91;LATIN SMALL LETTER D WITH HOOK AND TAIL;Ll;0;L;;;;;N;;;;; +1D92;LATIN SMALL LETTER E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D93;LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D94;LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D95;LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D96;LATIN SMALL LETTER I WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D97;LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D98;LATIN SMALL LETTER ESH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D99;LATIN SMALL LETTER U WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D9A;LATIN SMALL LETTER EZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D9B;MODIFIER LETTER SMALL TURNED ALPHA;Lm;0;L;<super> 0252;;;;N;;;;; +1D9C;MODIFIER LETTER SMALL C;Lm;0;L;<super> 0063;;;;N;;;;; +1D9D;MODIFIER LETTER SMALL C WITH CURL;Lm;0;L;<super> 0255;;;;N;;;;; +1D9E;MODIFIER LETTER SMALL ETH;Lm;0;L;<super> 00F0;;;;N;;;;; +1D9F;MODIFIER LETTER SMALL REVERSED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;; +1DA0;MODIFIER LETTER SMALL F;Lm;0;L;<super> 0066;;;;N;;;;; +1DA1;MODIFIER LETTER SMALL DOTLESS J WITH STROKE;Lm;0;L;<super> 025F;;;;N;;;;; +1DA2;MODIFIER LETTER SMALL SCRIPT G;Lm;0;L;<super> 0261;;;;N;;;;; +1DA3;MODIFIER LETTER SMALL TURNED H;Lm;0;L;<super> 0265;;;;N;;;;; +1DA4;MODIFIER LETTER SMALL I WITH STROKE;Lm;0;L;<super> 0268;;;;N;;;;; +1DA5;MODIFIER LETTER SMALL IOTA;Lm;0;L;<super> 0269;;;;N;;;;; +1DA6;MODIFIER LETTER SMALL CAPITAL I;Lm;0;L;<super> 026A;;;;N;;;;; +1DA7;MODIFIER LETTER SMALL CAPITAL I WITH STROKE;Lm;0;L;<super> 1D7B;;;;N;;;;; +1DA8;MODIFIER LETTER SMALL J WITH CROSSED-TAIL;Lm;0;L;<super> 029D;;;;N;;;;; +1DA9;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK;Lm;0;L;<super> 026D;;;;N;;;;; +1DAA;MODIFIER LETTER SMALL L WITH PALATAL HOOK;Lm;0;L;<super> 1D85;;;;N;;;;; +1DAB;MODIFIER LETTER SMALL CAPITAL L;Lm;0;L;<super> 029F;;;;N;;;;; +1DAC;MODIFIER LETTER SMALL M WITH HOOK;Lm;0;L;<super> 0271;;;;N;;;;; +1DAD;MODIFIER LETTER SMALL TURNED M WITH LONG LEG;Lm;0;L;<super> 0270;;;;N;;;;; +1DAE;MODIFIER LETTER SMALL N WITH LEFT HOOK;Lm;0;L;<super> 0272;;;;N;;;;; +1DAF;MODIFIER LETTER SMALL N WITH RETROFLEX HOOK;Lm;0;L;<super> 0273;;;;N;;;;; +1DB0;MODIFIER LETTER SMALL CAPITAL N;Lm;0;L;<super> 0274;;;;N;;;;; +1DB1;MODIFIER LETTER SMALL BARRED O;Lm;0;L;<super> 0275;;;;N;;;;; +1DB2;MODIFIER LETTER SMALL PHI;Lm;0;L;<super> 0278;;;;N;;;;; +1DB3;MODIFIER LETTER SMALL S WITH HOOK;Lm;0;L;<super> 0282;;;;N;;;;; +1DB4;MODIFIER LETTER SMALL ESH;Lm;0;L;<super> 0283;;;;N;;;;; +1DB5;MODIFIER LETTER SMALL T WITH PALATAL HOOK;Lm;0;L;<super> 01AB;;;;N;;;;; +1DB6;MODIFIER LETTER SMALL U BAR;Lm;0;L;<super> 0289;;;;N;;;;; +1DB7;MODIFIER LETTER SMALL UPSILON;Lm;0;L;<super> 028A;;;;N;;;;; +1DB8;MODIFIER LETTER SMALL CAPITAL U;Lm;0;L;<super> 1D1C;;;;N;;;;; +1DB9;MODIFIER LETTER SMALL V WITH HOOK;Lm;0;L;<super> 028B;;;;N;;;;; +1DBA;MODIFIER LETTER SMALL TURNED V;Lm;0;L;<super> 028C;;;;N;;;;; +1DBB;MODIFIER LETTER SMALL Z;Lm;0;L;<super> 007A;;;;N;;;;; +1DBC;MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK;Lm;0;L;<super> 0290;;;;N;;;;; +1DBD;MODIFIER LETTER SMALL Z WITH CURL;Lm;0;L;<super> 0291;;;;N;;;;; +1DBE;MODIFIER LETTER SMALL EZH;Lm;0;L;<super> 0292;;;;N;;;;; +1DBF;MODIFIER LETTER SMALL THETA;Lm;0;L;<super> 03B8;;;;N;;;;; +1DC0;COMBINING DOTTED GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;; +1DC1;COMBINING DOTTED ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; +1DC2;COMBINING SNAKE BELOW;Mn;220;NSM;;;;;N;;;;; +1DC3;COMBINING SUSPENSION MARK;Mn;230;NSM;;;;;N;;;;; +1DC4;COMBINING MACRON-ACUTE;Mn;230;NSM;;;;;N;;;;; +1DC5;COMBINING GRAVE-MACRON;Mn;230;NSM;;;;;N;;;;; +1DC6;COMBINING MACRON-GRAVE;Mn;230;NSM;;;;;N;;;;; +1DC7;COMBINING ACUTE-MACRON;Mn;230;NSM;;;;;N;;;;; +1DC8;COMBINING GRAVE-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;; +1DC9;COMBINING ACUTE-GRAVE-ACUTE;Mn;230;NSM;;;;;N;;;;; +1DCA;COMBINING LATIN SMALL LETTER R BELOW;Mn;220;NSM;;;;;N;;;;; +1DCB;COMBINING BREVE-MACRON;Mn;230;NSM;;;;;N;;;;; +1DCC;COMBINING MACRON-BREVE;Mn;230;NSM;;;;;N;;;;; +1DCD;COMBINING DOUBLE CIRCUMFLEX ABOVE;Mn;234;NSM;;;;;N;;;;; +1DCE;COMBINING OGONEK ABOVE;Mn;214;NSM;;;;;N;;;;; +1DCF;COMBINING ZIGZAG BELOW;Mn;220;NSM;;;;;N;;;;; +1DD0;COMBINING IS BELOW;Mn;202;NSM;;;;;N;;;;; +1DD1;COMBINING UR ABOVE;Mn;230;NSM;;;;;N;;;;; +1DD2;COMBINING US ABOVE;Mn;230;NSM;;;;;N;;;;; +1DD3;COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE;Mn;230;NSM;;;;;N;;;;; +1DD4;COMBINING LATIN SMALL LETTER AE;Mn;230;NSM;;;;;N;;;;; +1DD5;COMBINING LATIN SMALL LETTER AO;Mn;230;NSM;;;;;N;;;;; +1DD6;COMBINING LATIN SMALL LETTER AV;Mn;230;NSM;;;;;N;;;;; +1DD7;COMBINING LATIN SMALL LETTER C CEDILLA;Mn;230;NSM;;;;;N;;;;; +1DD8;COMBINING LATIN SMALL LETTER INSULAR D;Mn;230;NSM;;;;;N;;;;; +1DD9;COMBINING LATIN SMALL LETTER ETH;Mn;230;NSM;;;;;N;;;;; +1DDA;COMBINING LATIN SMALL LETTER G;Mn;230;NSM;;;;;N;;;;; +1DDB;COMBINING LATIN LETTER SMALL CAPITAL G;Mn;230;NSM;;;;;N;;;;; +1DDC;COMBINING LATIN SMALL LETTER K;Mn;230;NSM;;;;;N;;;;; +1DDD;COMBINING LATIN SMALL LETTER L;Mn;230;NSM;;;;;N;;;;; +1DDE;COMBINING LATIN LETTER SMALL CAPITAL L;Mn;230;NSM;;;;;N;;;;; +1DDF;COMBINING LATIN LETTER SMALL CAPITAL M;Mn;230;NSM;;;;;N;;;;; +1DE0;COMBINING LATIN SMALL LETTER N;Mn;230;NSM;;;;;N;;;;; +1DE1;COMBINING LATIN LETTER SMALL CAPITAL N;Mn;230;NSM;;;;;N;;;;; +1DE2;COMBINING LATIN LETTER SMALL CAPITAL R;Mn;230;NSM;;;;;N;;;;; +1DE3;COMBINING LATIN SMALL LETTER R ROTUNDA;Mn;230;NSM;;;;;N;;;;; +1DE4;COMBINING LATIN SMALL LETTER S;Mn;230;NSM;;;;;N;;;;; +1DE5;COMBINING LATIN SMALL LETTER LONG S;Mn;230;NSM;;;;;N;;;;; +1DE6;COMBINING LATIN SMALL LETTER Z;Mn;230;NSM;;;;;N;;;;; +1DFE;COMBINING LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +1DFF;COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; 1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01; 1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00 1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03; @@ -5237,6 +6156,10 @@ 1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;; 1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L;<compat> 0061 02BE;;;;N;;;;; 1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60 +1E9C;LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;;; +1E9D;LATIN SMALL LETTER LONG S WITH HIGH STROKE;Ll;0;L;;;;;N;;;;; +1E9E;LATIN CAPITAL LETTER SHARP S;Lu;0;L;;;;;N;;;;00DF; +1E9F;LATIN SMALL LETTER DELTA;Ll;0;L;;;;;N;;;;; 1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1; 1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0 1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3; @@ -5327,6 +6250,12 @@ 1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6 1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9; 1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8 +1EFA;LATIN CAPITAL LETTER MIDDLE-WELSH LL;Lu;0;L;;;;;N;;;;1EFB; +1EFB;LATIN SMALL LETTER MIDDLE-WELSH LL;Ll;0;L;;;;;N;;;1EFA;;1EFA +1EFC;LATIN CAPITAL LETTER MIDDLE-WELSH V;Lu;0;L;;;;;N;;;;1EFD; +1EFD;LATIN SMALL LETTER MIDDLE-WELSH V;Ll;0;L;;;;;N;;;1EFC;;1EFC +1EFE;LATIN CAPITAL LETTER Y WITH LOOP;Lu;0;L;;;;;N;;;;1EFF; +1EFF;LATIN SMALL LETTER Y WITH LOOP;Ll;0;L;;;;;N;;;1EFE;;1EFE 1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08 1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09 1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A @@ -5571,7 +6500,7 @@ 2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; 2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; 200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -200B;ZERO WIDTH SPACE;Zs;0;BN;;;;;N;;;;; +200B;ZERO WIDTH SPACE;Cf;0;BN;;;;;N;;;;; 200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;; 200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;; 200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;; @@ -5607,7 +6536,7 @@ 202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;; 202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;; 202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;; -202F;NARROW NO-BREAK SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;; +202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;; 2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;; 2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;; 2032;PRIME;Po;0;ET;;;;;N;;;;; @@ -5628,7 +6557,7 @@ 2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;; 2042;ASTERISM;Po;0;ON;;;;;N;;;;; 2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;; -2044;FRACTION SLASH;Sm;0;ON;;;;;N;;;;; +2044;FRACTION SLASH;Sm;0;CS;;;;;N;;;;; 2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;; 2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;; 2047;DOUBLE QUESTION MARK;Po;0;ON;<compat> 003F 003F;;;;N;;;;; @@ -5645,12 +6574,22 @@ 2052;COMMERCIAL MINUS SIGN;Sm;0;ON;;;;;N;;;;; 2053;SWUNG DASH;Po;0;ON;;;;;N;;;;; 2054;INVERTED UNDERTIE;Pc;0;ON;;;;;N;;;;; +2055;FLOWER PUNCTUATION MARK;Po;0;ON;;;;;N;;;;; +2056;THREE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; 2057;QUADRUPLE PRIME;Po;0;ON;<compat> 2032 2032 2032 2032;;;;N;;;;; +2058;FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +2059;FIVE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +205A;TWO DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +205B;FOUR DOT MARK;Po;0;ON;;;;;N;;;;; +205C;DOTTED CROSS;Po;0;ON;;;;;N;;;;; +205D;TRICOLON;Po;0;ON;;;;;N;;;;; +205E;VERTICAL FOUR DOTS;Po;0;ON;;;;;N;;;;; 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; 2060;WORD JOINER;Cf;0;BN;;;;;N;;;;; 2061;FUNCTION APPLICATION;Cf;0;BN;;;;;N;;;;; 2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;; 2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;; +2064;INVISIBLE PLUS;Cf;0;BN;;;;;N;;;;; 206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; 206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; 206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; @@ -5665,8 +6604,8 @@ 2077;SUPERSCRIPT SEVEN;No;0;EN;<super> 0037;;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;; 2078;SUPERSCRIPT EIGHT;No;0;EN;<super> 0038;;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;; 2079;SUPERSCRIPT NINE;No;0;EN;<super> 0039;;9;9;N;SUPERSCRIPT DIGIT NINE;;;; -207A;SUPERSCRIPT PLUS SIGN;Sm;0;ET;<super> 002B;;;;N;;;;; -207B;SUPERSCRIPT MINUS;Sm;0;ET;<super> 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;; +207A;SUPERSCRIPT PLUS SIGN;Sm;0;ES;<super> 002B;;;;N;;;;; +207B;SUPERSCRIPT MINUS;Sm;0;ES;<super> 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;; 207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON;<super> 003D;;;;N;;;;; 207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON;<super> 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;; 207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<super> 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;; @@ -5681,11 +6620,16 @@ 2087;SUBSCRIPT SEVEN;No;0;EN;<sub> 0037;;7;7;N;SUBSCRIPT DIGIT SEVEN;;;; 2088;SUBSCRIPT EIGHT;No;0;EN;<sub> 0038;;8;8;N;SUBSCRIPT DIGIT EIGHT;;;; 2089;SUBSCRIPT NINE;No;0;EN;<sub> 0039;;9;9;N;SUBSCRIPT DIGIT NINE;;;; -208A;SUBSCRIPT PLUS SIGN;Sm;0;ET;<sub> 002B;;;;N;;;;; -208B;SUBSCRIPT MINUS;Sm;0;ET;<sub> 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;; +208A;SUBSCRIPT PLUS SIGN;Sm;0;ES;<sub> 002B;;;;N;;;;; +208B;SUBSCRIPT MINUS;Sm;0;ES;<sub> 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;; 208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON;<sub> 003D;;;;N;;;;; 208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON;<sub> 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;; 208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<sub> 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;; +2090;LATIN SUBSCRIPT SMALL LETTER A;Lm;0;L;<sub> 0061;;;;N;;;;; +2091;LATIN SUBSCRIPT SMALL LETTER E;Lm;0;L;<sub> 0065;;;;N;;;;; +2092;LATIN SUBSCRIPT SMALL LETTER O;Lm;0;L;<sub> 006F;;;;N;;;;; +2093;LATIN SUBSCRIPT SMALL LETTER X;Lm;0;L;<sub> 0078;;;;N;;;;; +2094;LATIN SUBSCRIPT SMALL LETTER SCHWA;Lm;0;L;<sub> 0259;;;;N;;;;; 20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; 20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;; 20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;; @@ -5704,6 +6648,10 @@ 20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;; 20B0;GERMAN PENNY SIGN;Sc;0;ET;;;;;N;;;;; 20B1;PESO SIGN;Sc;0;ET;;;;;N;;;;; +20B2;GUARANI SIGN;Sc;0;ET;;;;;N;;;;; +20B3;AUSTRAL SIGN;Sc;0;ET;;;;;N;;;;; +20B4;HRYVNIA SIGN;Sc;0;ET;;;;;N;;;;; +20B5;CEDI SIGN;Sc;0;ET;;;;;N;;;;; 20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; 20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; 20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; @@ -5731,6 +6679,12 @@ 20E8;COMBINING TRIPLE UNDERDOT;Mn;220;NSM;;;;;N;;;;; 20E9;COMBINING WIDE BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; 20EA;COMBINING LEFTWARDS ARROW OVERLAY;Mn;1;NSM;;;;;N;;;;; +20EB;COMBINING LONG DOUBLE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;; +20EC;COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;; +20ED;COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;; +20EE;COMBINING LEFT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +20EF;COMBINING RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +20F0;COMBINING ASTERISK ABOVE;Mn;230;NSM;;;;;N;;;;; 2100;ACCOUNT OF;So;0;ON;<compat> 0061 002F 0063;;;;N;;;;; 2101;ADDRESSED TO THE SUBJECT;So;0;ON;<compat> 0061 002F 0073;;;;N;;;;; 2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L;<font> 0043;;;;N;DOUBLE-STRUCK C;;;; @@ -5781,7 +6735,7 @@ 212F;SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; 2130;SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;SCRIPT E;;;; 2131;SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;SCRIPT F;;;; -2132;TURNED CAPITAL F;So;0;ON;;;;;N;TURNED F;;;; +2132;TURNED CAPITAL F;Lu;0;L;;;;;N;TURNED F;;;214E; 2133;SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;SCRIPT M;;;; 2134;SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; 2135;ALEF SYMBOL;Lo;0;L;<compat> 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;; @@ -5791,6 +6745,7 @@ 2139;INFORMATION SOURCE;Ll;0;L;<font> 0069;;;;N;;;;; 213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;; 213B;FACSIMILE SIGN;So;0;ON;<compat> 0046 0041 0058;;;;N;;;;; +213C;DOUBLE-STRUCK SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; 213D;DOUBLE-STRUCK SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; 213E;DOUBLE-STRUCK CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; 213F;DOUBLE-STRUCK CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; @@ -5806,6 +6761,10 @@ 2149;DOUBLE-STRUCK ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; 214A;PROPERTY LINE;So;0;ON;;;;;N;;;;; 214B;TURNED AMPERSAND;Sm;0;ON;;;;;N;;;;; +214C;PER SIGN;So;0;ON;;;;;N;;;;; +214D;AKTIESELSKAB;So;0;ON;;;;;N;;;;; +214E;TURNED SMALL F;Ll;0;L;;;;;N;;;2132;;2132 +214F;SYMBOL FOR SAMARITAN SOURCE;So;0;L;;;;;N;;;;; 2153;VULGAR FRACTION ONE THIRD;No;0;ON;<fraction> 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;; 2154;VULGAR FRACTION TWO THIRDS;No;0;ON;<fraction> 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;; 2155;VULGAR FRACTION ONE FIFTH;No;0;ON;<fraction> 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;; @@ -5854,7 +6813,12 @@ 2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;; 2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;; 2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;; -2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Nl;0;L;;;;;N;;;;; +2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Lu;0;L;;;;;N;;;;2184; +2184;LATIN SMALL LETTER REVERSED C;Ll;0;L;;;;;N;;;2183;;2183 +2185;ROMAN NUMERAL SIX LATE FORM;Nl;0;L;;;;6;N;;;;; +2186;ROMAN NUMERAL FIFTY EARLY FORM;Nl;0;L;;;;50;N;;;;; +2187;ROMAN NUMERAL FIFTY THOUSAND;Nl;0;L;;;;50000;N;;;;; +2188;ROMAN NUMERAL ONE HUNDRED THOUSAND;Nl;0;L;;;;100000;N;;;;; 2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;; 2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;; 2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;; @@ -5985,7 +6949,7 @@ 220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;; 2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;; 2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;; -2212;MINUS SIGN;Sm;0;ET;;;;;N;;;;; +2212;MINUS SIGN;Sm;0;ES;;;;;N;;;;; 2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;; 2214;DOT PLUS;Sm;0;ON;;;;;N;;;;; 2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; @@ -6403,9 +7367,9 @@ 23B1;UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;; 23B2;SUMMATION TOP;Sm;0;ON;;;;;N;;;;; 23B3;SUMMATION BOTTOM;Sm;0;ON;;;;;N;;;;; -23B4;TOP SQUARE BRACKET;Ps;0;ON;;;;;N;;;;; -23B5;BOTTOM SQUARE BRACKET;Pe;0;ON;;;;;N;;;;; -23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;Po;0;ON;;;;;N;;;;; +23B4;TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;; +23B5;BOTTOM SQUARE BRACKET;So;0;ON;;;;;N;;;;; +23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;; 23B7;RADICAL SYMBOL BOTTOM;So;0;ON;;;;;N;;;;; 23B8;LEFT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; 23B9;RIGHT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; @@ -6432,6 +7396,29 @@ 23CE;RETURN SYMBOL;So;0;ON;;;;;N;;;;; 23CF;EJECT SYMBOL;So;0;ON;;;;;N;;;;; 23D0;VERTICAL LINE EXTENSION;So;0;ON;;;;;N;;;;; +23D1;METRICAL BREVE;So;0;ON;;;;;N;;;;; +23D2;METRICAL LONG OVER SHORT;So;0;ON;;;;;N;;;;; +23D3;METRICAL SHORT OVER LONG;So;0;ON;;;;;N;;;;; +23D4;METRICAL LONG OVER TWO SHORTS;So;0;ON;;;;;N;;;;; +23D5;METRICAL TWO SHORTS OVER LONG;So;0;ON;;;;;N;;;;; +23D6;METRICAL TWO SHORTS JOINED;So;0;ON;;;;;N;;;;; +23D7;METRICAL TRISEME;So;0;ON;;;;;N;;;;; +23D8;METRICAL TETRASEME;So;0;ON;;;;;N;;;;; +23D9;METRICAL PENTASEME;So;0;ON;;;;;N;;;;; +23DA;EARTH GROUND;So;0;ON;;;;;N;;;;; +23DB;FUSE;So;0;ON;;;;;N;;;;; +23DC;TOP PARENTHESIS;Sm;0;ON;;;;;N;;mathematical use;;; +23DD;BOTTOM PARENTHESIS;Sm;0;ON;;;;;N;;mathematical use;;; +23DE;TOP CURLY BRACKET;Sm;0;ON;;;;;N;;mathematical use;;; +23DF;BOTTOM CURLY BRACKET;Sm;0;ON;;;;;N;;mathematical use;;; +23E0;TOP TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;mathematical use;;; +23E1;BOTTOM TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;mathematical use;;; +23E2;WHITE TRAPEZIUM;So;0;ON;;;;;N;;;;; +23E3;BENZENE RING WITH CIRCLE;So;0;ON;;;;;N;;;;; +23E4;STRAIGHTNESS;So;0;ON;;;;;N;;;;; +23E5;FLATNESS;So;0;ON;;;;;N;;;;; +23E6;AC CURRENT;So;0;ON;;;;;N;;;;; +23E7;ELECTRICAL INTERSECTION;So;0;ON;;;;;N;;;;; 2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; 2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; 2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; @@ -6482,46 +7469,46 @@ 2448;OCR DASH;So;0;ON;;;;;N;;;;; 2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;; 244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;; -2460;CIRCLED DIGIT ONE;No;0;EN;<circle> 0031;;1;1;N;;;;; -2461;CIRCLED DIGIT TWO;No;0;EN;<circle> 0032;;2;2;N;;;;; -2462;CIRCLED DIGIT THREE;No;0;EN;<circle> 0033;;3;3;N;;;;; -2463;CIRCLED DIGIT FOUR;No;0;EN;<circle> 0034;;4;4;N;;;;; -2464;CIRCLED DIGIT FIVE;No;0;EN;<circle> 0035;;5;5;N;;;;; -2465;CIRCLED DIGIT SIX;No;0;EN;<circle> 0036;;6;6;N;;;;; -2466;CIRCLED DIGIT SEVEN;No;0;EN;<circle> 0037;;7;7;N;;;;; -2467;CIRCLED DIGIT EIGHT;No;0;EN;<circle> 0038;;8;8;N;;;;; -2468;CIRCLED DIGIT NINE;No;0;EN;<circle> 0039;;9;9;N;;;;; -2469;CIRCLED NUMBER TEN;No;0;EN;<circle> 0031 0030;;;10;N;;;;; -246A;CIRCLED NUMBER ELEVEN;No;0;EN;<circle> 0031 0031;;;11;N;;;;; -246B;CIRCLED NUMBER TWELVE;No;0;EN;<circle> 0031 0032;;;12;N;;;;; -246C;CIRCLED NUMBER THIRTEEN;No;0;EN;<circle> 0031 0033;;;13;N;;;;; -246D;CIRCLED NUMBER FOURTEEN;No;0;EN;<circle> 0031 0034;;;14;N;;;;; -246E;CIRCLED NUMBER FIFTEEN;No;0;EN;<circle> 0031 0035;;;15;N;;;;; -246F;CIRCLED NUMBER SIXTEEN;No;0;EN;<circle> 0031 0036;;;16;N;;;;; -2470;CIRCLED NUMBER SEVENTEEN;No;0;EN;<circle> 0031 0037;;;17;N;;;;; -2471;CIRCLED NUMBER EIGHTEEN;No;0;EN;<circle> 0031 0038;;;18;N;;;;; -2472;CIRCLED NUMBER NINETEEN;No;0;EN;<circle> 0031 0039;;;19;N;;;;; -2473;CIRCLED NUMBER TWENTY;No;0;EN;<circle> 0032 0030;;;20;N;;;;; -2474;PARENTHESIZED DIGIT ONE;No;0;EN;<compat> 0028 0031 0029;;1;1;N;;;;; -2475;PARENTHESIZED DIGIT TWO;No;0;EN;<compat> 0028 0032 0029;;2;2;N;;;;; -2476;PARENTHESIZED DIGIT THREE;No;0;EN;<compat> 0028 0033 0029;;3;3;N;;;;; -2477;PARENTHESIZED DIGIT FOUR;No;0;EN;<compat> 0028 0034 0029;;4;4;N;;;;; -2478;PARENTHESIZED DIGIT FIVE;No;0;EN;<compat> 0028 0035 0029;;5;5;N;;;;; -2479;PARENTHESIZED DIGIT SIX;No;0;EN;<compat> 0028 0036 0029;;6;6;N;;;;; -247A;PARENTHESIZED DIGIT SEVEN;No;0;EN;<compat> 0028 0037 0029;;7;7;N;;;;; -247B;PARENTHESIZED DIGIT EIGHT;No;0;EN;<compat> 0028 0038 0029;;8;8;N;;;;; -247C;PARENTHESIZED DIGIT NINE;No;0;EN;<compat> 0028 0039 0029;;9;9;N;;;;; -247D;PARENTHESIZED NUMBER TEN;No;0;EN;<compat> 0028 0031 0030 0029;;;10;N;;;;; -247E;PARENTHESIZED NUMBER ELEVEN;No;0;EN;<compat> 0028 0031 0031 0029;;;11;N;;;;; -247F;PARENTHESIZED NUMBER TWELVE;No;0;EN;<compat> 0028 0031 0032 0029;;;12;N;;;;; -2480;PARENTHESIZED NUMBER THIRTEEN;No;0;EN;<compat> 0028 0031 0033 0029;;;13;N;;;;; -2481;PARENTHESIZED NUMBER FOURTEEN;No;0;EN;<compat> 0028 0031 0034 0029;;;14;N;;;;; -2482;PARENTHESIZED NUMBER FIFTEEN;No;0;EN;<compat> 0028 0031 0035 0029;;;15;N;;;;; -2483;PARENTHESIZED NUMBER SIXTEEN;No;0;EN;<compat> 0028 0031 0036 0029;;;16;N;;;;; -2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;EN;<compat> 0028 0031 0037 0029;;;17;N;;;;; -2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;EN;<compat> 0028 0031 0038 0029;;;18;N;;;;; -2486;PARENTHESIZED NUMBER NINETEEN;No;0;EN;<compat> 0028 0031 0039 0029;;;19;N;;;;; -2487;PARENTHESIZED NUMBER TWENTY;No;0;EN;<compat> 0028 0032 0030 0029;;;20;N;;;;; +2460;CIRCLED DIGIT ONE;No;0;ON;<circle> 0031;;1;1;N;;;;; +2461;CIRCLED DIGIT TWO;No;0;ON;<circle> 0032;;2;2;N;;;;; +2462;CIRCLED DIGIT THREE;No;0;ON;<circle> 0033;;3;3;N;;;;; +2463;CIRCLED DIGIT FOUR;No;0;ON;<circle> 0034;;4;4;N;;;;; +2464;CIRCLED DIGIT FIVE;No;0;ON;<circle> 0035;;5;5;N;;;;; +2465;CIRCLED DIGIT SIX;No;0;ON;<circle> 0036;;6;6;N;;;;; +2466;CIRCLED DIGIT SEVEN;No;0;ON;<circle> 0037;;7;7;N;;;;; +2467;CIRCLED DIGIT EIGHT;No;0;ON;<circle> 0038;;8;8;N;;;;; +2468;CIRCLED DIGIT NINE;No;0;ON;<circle> 0039;;9;9;N;;;;; +2469;CIRCLED NUMBER TEN;No;0;ON;<circle> 0031 0030;;;10;N;;;;; +246A;CIRCLED NUMBER ELEVEN;No;0;ON;<circle> 0031 0031;;;11;N;;;;; +246B;CIRCLED NUMBER TWELVE;No;0;ON;<circle> 0031 0032;;;12;N;;;;; +246C;CIRCLED NUMBER THIRTEEN;No;0;ON;<circle> 0031 0033;;;13;N;;;;; +246D;CIRCLED NUMBER FOURTEEN;No;0;ON;<circle> 0031 0034;;;14;N;;;;; +246E;CIRCLED NUMBER FIFTEEN;No;0;ON;<circle> 0031 0035;;;15;N;;;;; +246F;CIRCLED NUMBER SIXTEEN;No;0;ON;<circle> 0031 0036;;;16;N;;;;; +2470;CIRCLED NUMBER SEVENTEEN;No;0;ON;<circle> 0031 0037;;;17;N;;;;; +2471;CIRCLED NUMBER EIGHTEEN;No;0;ON;<circle> 0031 0038;;;18;N;;;;; +2472;CIRCLED NUMBER NINETEEN;No;0;ON;<circle> 0031 0039;;;19;N;;;;; +2473;CIRCLED NUMBER TWENTY;No;0;ON;<circle> 0032 0030;;;20;N;;;;; +2474;PARENTHESIZED DIGIT ONE;No;0;ON;<compat> 0028 0031 0029;;1;1;N;;;;; +2475;PARENTHESIZED DIGIT TWO;No;0;ON;<compat> 0028 0032 0029;;2;2;N;;;;; +2476;PARENTHESIZED DIGIT THREE;No;0;ON;<compat> 0028 0033 0029;;3;3;N;;;;; +2477;PARENTHESIZED DIGIT FOUR;No;0;ON;<compat> 0028 0034 0029;;4;4;N;;;;; +2478;PARENTHESIZED DIGIT FIVE;No;0;ON;<compat> 0028 0035 0029;;5;5;N;;;;; +2479;PARENTHESIZED DIGIT SIX;No;0;ON;<compat> 0028 0036 0029;;6;6;N;;;;; +247A;PARENTHESIZED DIGIT SEVEN;No;0;ON;<compat> 0028 0037 0029;;7;7;N;;;;; +247B;PARENTHESIZED DIGIT EIGHT;No;0;ON;<compat> 0028 0038 0029;;8;8;N;;;;; +247C;PARENTHESIZED DIGIT NINE;No;0;ON;<compat> 0028 0039 0029;;9;9;N;;;;; +247D;PARENTHESIZED NUMBER TEN;No;0;ON;<compat> 0028 0031 0030 0029;;;10;N;;;;; +247E;PARENTHESIZED NUMBER ELEVEN;No;0;ON;<compat> 0028 0031 0031 0029;;;11;N;;;;; +247F;PARENTHESIZED NUMBER TWELVE;No;0;ON;<compat> 0028 0031 0032 0029;;;12;N;;;;; +2480;PARENTHESIZED NUMBER THIRTEEN;No;0;ON;<compat> 0028 0031 0033 0029;;;13;N;;;;; +2481;PARENTHESIZED NUMBER FOURTEEN;No;0;ON;<compat> 0028 0031 0034 0029;;;14;N;;;;; +2482;PARENTHESIZED NUMBER FIFTEEN;No;0;ON;<compat> 0028 0031 0035 0029;;;15;N;;;;; +2483;PARENTHESIZED NUMBER SIXTEEN;No;0;ON;<compat> 0028 0031 0036 0029;;;16;N;;;;; +2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;ON;<compat> 0028 0031 0037 0029;;;17;N;;;;; +2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;ON;<compat> 0028 0031 0038 0029;;;18;N;;;;; +2486;PARENTHESIZED NUMBER NINETEEN;No;0;ON;<compat> 0028 0031 0039 0029;;;19;N;;;;; +2487;PARENTHESIZED NUMBER TWENTY;No;0;ON;<compat> 0028 0032 0030 0029;;;20;N;;;;; 2488;DIGIT ONE FULL STOP;No;0;EN;<compat> 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;; 2489;DIGIT TWO FULL STOP;No;0;EN;<compat> 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;; 248A;DIGIT THREE FULL STOP;No;0;EN;<compat> 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;; @@ -6620,7 +7607,7 @@ 24E7;CIRCLED LATIN SMALL LETTER X;So;0;L;<circle> 0078;;;;N;;;24CD;;24CD 24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L;<circle> 0079;;;;N;;;24CE;;24CE 24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L;<circle> 007A;;;;N;;;24CF;;24CF -24EA;CIRCLED DIGIT ZERO;No;0;EN;<circle> 0030;;0;0;N;;;;; +24EA;CIRCLED DIGIT ZERO;No;0;ON;<circle> 0030;;0;0;N;;;;; 24EB;NEGATIVE CIRCLED NUMBER ELEVEN;No;0;ON;;;;11;N;;;;; 24EC;NEGATIVE CIRCLED NUMBER TWELVE;No;0;ON;;;;12;N;;;;; 24ED;NEGATIVE CIRCLED NUMBER THIRTEEN;No;0;ON;;;;13;N;;;;; @@ -6922,6 +7909,7 @@ 2615;HOT BEVERAGE;So;0;ON;;;;;N;;;;; 2616;WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;; 2617;BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;; +2618;SHAMROCK;So;0;ON;;;;;N;;;;; 2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; 261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; 261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; @@ -7023,6 +8011,8 @@ 267B;BLACK UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;; 267C;RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; 267D;PARTIALLY-RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; +267E;PERMANENT PAPER SIGN;So;0;ON;;;;;N;;;;; +267F;WHEELCHAIR SYMBOL;So;0;ON;;;;;N;;;;; 2680;DIE FACE-1;So;0;ON;;;;;N;;;;; 2681;DIE FACE-2;So;0;ON;;;;;N;;;;; 2682;DIE FACE-3;So;0;ON;;;;;N;;;;; @@ -7041,8 +8031,51 @@ 268F;DIGRAM FOR GREATER YIN;So;0;ON;;;;;N;;;;; 2690;WHITE FLAG;So;0;ON;;;;;N;;;;; 2691;BLACK FLAG;So;0;ON;;;;;N;;;;; +2692;HAMMER AND PICK;So;0;ON;;;;;N;;;;; +2693;ANCHOR;So;0;ON;;;;;N;;;;; +2694;CROSSED SWORDS;So;0;ON;;;;;N;;;;; +2695;STAFF OF AESCULAPIUS;So;0;ON;;;;;N;;;;; +2696;SCALES;So;0;ON;;;;;N;;;;; +2697;ALEMBIC;So;0;ON;;;;;N;;;;; +2698;FLOWER;So;0;ON;;;;;N;;;;; +2699;GEAR;So;0;ON;;;;;N;;;;; +269A;STAFF OF HERMES;So;0;ON;;;;;N;;;;; +269B;ATOM SYMBOL;So;0;ON;;;;;N;;;;; +269C;FLEUR-DE-LIS;So;0;ON;;;;;N;;;;; +269D;OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;; 26A0;WARNING SIGN;So;0;ON;;;;;N;;;;; 26A1;HIGH VOLTAGE SIGN;So;0;ON;;;;;N;;;;; +26A2;DOUBLED FEMALE SIGN;So;0;ON;;;;;N;;;;; +26A3;DOUBLED MALE SIGN;So;0;ON;;;;;N;;;;; +26A4;INTERLOCKED FEMALE AND MALE SIGN;So;0;ON;;;;;N;;;;; +26A5;MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;; +26A6;MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;; +26A7;MALE WITH STROKE AND MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;; +26A8;VERTICAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;; +26A9;HORIZONTAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;; +26AA;MEDIUM WHITE CIRCLE;So;0;ON;;;;;N;;;;; +26AB;MEDIUM BLACK CIRCLE;So;0;ON;;;;;N;;;;; +26AC;MEDIUM SMALL WHITE CIRCLE;So;0;L;;;;;N;;;;; +26AD;MARRIAGE SYMBOL;So;0;ON;;;;;N;;;;; +26AE;DIVORCE SYMBOL;So;0;ON;;;;;N;;;;; +26AF;UNMARRIED PARTNERSHIP SYMBOL;So;0;ON;;;;;N;;;;; +26B0;COFFIN;So;0;ON;;;;;N;;;;; +26B1;FUNERAL URN;So;0;ON;;;;;N;;;;; +26B2;NEUTER;So;0;ON;;;;;N;;;;; +26B3;CERES;So;0;ON;;;;;N;;;;; +26B4;PALLAS;So;0;ON;;;;;N;;;;; +26B5;JUNO;So;0;ON;;;;;N;;;;; +26B6;VESTA;So;0;ON;;;;;N;;;;; +26B7;CHIRON;So;0;ON;;;;;N;;;;; +26B8;BLACK MOON LILITH;So;0;ON;;;;;N;;;;; +26B9;SEXTILE;So;0;ON;;;;;N;;;;; +26BA;SEMISEXTILE;So;0;ON;;;;;N;;;;; +26BB;QUINCUNX;So;0;ON;;;;;N;;;;; +26BC;SESQUIQUADRATE;So;0;ON;;;;;N;;;;; +26C0;WHITE DRAUGHTS MAN;So;0;ON;;;;;N;;;;; +26C1;WHITE DRAUGHTS KING;So;0;ON;;;;;N;;;;; +26C2;BLACK DRAUGHTS MAN;So;0;ON;;;;;N;;;;; +26C3;BLACK DRAUGHTS KING;So;0;ON;;;;;N;;;;; 2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;; 2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;; 2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;; @@ -7217,6 +8250,18 @@ 27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;; 27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;; 27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;; +27C0;THREE DIMENSIONAL ANGLE;Sm;0;ON;;;;;Y;;;;; +27C1;WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE;Sm;0;ON;;;;;N;;;;; +27C2;PERPENDICULAR;Sm;0;ON;;;;;N;;;;; +27C3;OPEN SUBSET;Sm;0;ON;;;;;Y;;;;; +27C4;OPEN SUPERSET;Sm;0;ON;;;;;Y;;;;; +27C5;LEFT S-SHAPED BAG DELIMITER;Ps;0;ON;;;;;Y;;;;; +27C6;RIGHT S-SHAPED BAG DELIMITER;Pe;0;ON;;;;;Y;;;;; +27C7;OR WITH DOT INSIDE;Sm;0;ON;;;;;N;;;;; +27C8;REVERSE SOLIDUS PRECEDING SUBSET;Sm;0;ON;;;;;Y;;;;; +27C9;SUPERSET PRECEDING SOLIDUS;Sm;0;ON;;;;;Y;;;;; +27CA;VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +27CC;LONG DIVISION;Sm;0;ON;;;;;Y;;;;; 27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;; 27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;; 27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;; @@ -7245,6 +8290,10 @@ 27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; 27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; 27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; +27EC;MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;; +27ED;MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;; +27EE;MATHEMATICAL LEFT FLATTENED PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +27EF;MATHEMATICAL RIGHT FLATTENED PARENTHESIS;Pe;0;ON;;;;;Y;;;;; 27F0;UPWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; 27F1;DOWNWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; 27F2;ANTICLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; @@ -7261,262 +8310,262 @@ 27FD;LONG LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; 27FE;LONG RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; 27FF;LONG RIGHTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;; -2800;BRAILLE PATTERN BLANK;So;0;ON;;;;;N;;;;; -2801;BRAILLE PATTERN DOTS-1;So;0;ON;;;;;N;;;;; -2802;BRAILLE PATTERN DOTS-2;So;0;ON;;;;;N;;;;; -2803;BRAILLE PATTERN DOTS-12;So;0;ON;;;;;N;;;;; -2804;BRAILLE PATTERN DOTS-3;So;0;ON;;;;;N;;;;; -2805;BRAILLE PATTERN DOTS-13;So;0;ON;;;;;N;;;;; -2806;BRAILLE PATTERN DOTS-23;So;0;ON;;;;;N;;;;; -2807;BRAILLE PATTERN DOTS-123;So;0;ON;;;;;N;;;;; -2808;BRAILLE PATTERN DOTS-4;So;0;ON;;;;;N;;;;; -2809;BRAILLE PATTERN DOTS-14;So;0;ON;;;;;N;;;;; -280A;BRAILLE PATTERN DOTS-24;So;0;ON;;;;;N;;;;; -280B;BRAILLE PATTERN DOTS-124;So;0;ON;;;;;N;;;;; -280C;BRAILLE PATTERN DOTS-34;So;0;ON;;;;;N;;;;; -280D;BRAILLE PATTERN DOTS-134;So;0;ON;;;;;N;;;;; -280E;BRAILLE PATTERN DOTS-234;So;0;ON;;;;;N;;;;; -280F;BRAILLE PATTERN DOTS-1234;So;0;ON;;;;;N;;;;; -2810;BRAILLE PATTERN DOTS-5;So;0;ON;;;;;N;;;;; -2811;BRAILLE PATTERN DOTS-15;So;0;ON;;;;;N;;;;; -2812;BRAILLE PATTERN DOTS-25;So;0;ON;;;;;N;;;;; -2813;BRAILLE PATTERN DOTS-125;So;0;ON;;;;;N;;;;; -2814;BRAILLE PATTERN DOTS-35;So;0;ON;;;;;N;;;;; -2815;BRAILLE PATTERN DOTS-135;So;0;ON;;;;;N;;;;; -2816;BRAILLE PATTERN DOTS-235;So;0;ON;;;;;N;;;;; -2817;BRAILLE PATTERN DOTS-1235;So;0;ON;;;;;N;;;;; -2818;BRAILLE PATTERN DOTS-45;So;0;ON;;;;;N;;;;; -2819;BRAILLE PATTERN DOTS-145;So;0;ON;;;;;N;;;;; -281A;BRAILLE PATTERN DOTS-245;So;0;ON;;;;;N;;;;; -281B;BRAILLE PATTERN DOTS-1245;So;0;ON;;;;;N;;;;; -281C;BRAILLE PATTERN DOTS-345;So;0;ON;;;;;N;;;;; -281D;BRAILLE PATTERN DOTS-1345;So;0;ON;;;;;N;;;;; -281E;BRAILLE PATTERN DOTS-2345;So;0;ON;;;;;N;;;;; -281F;BRAILLE PATTERN DOTS-12345;So;0;ON;;;;;N;;;;; -2820;BRAILLE PATTERN DOTS-6;So;0;ON;;;;;N;;;;; -2821;BRAILLE PATTERN DOTS-16;So;0;ON;;;;;N;;;;; -2822;BRAILLE PATTERN DOTS-26;So;0;ON;;;;;N;;;;; -2823;BRAILLE PATTERN DOTS-126;So;0;ON;;;;;N;;;;; -2824;BRAILLE PATTERN DOTS-36;So;0;ON;;;;;N;;;;; -2825;BRAILLE PATTERN DOTS-136;So;0;ON;;;;;N;;;;; -2826;BRAILLE PATTERN DOTS-236;So;0;ON;;;;;N;;;;; -2827;BRAILLE PATTERN DOTS-1236;So;0;ON;;;;;N;;;;; -2828;BRAILLE PATTERN DOTS-46;So;0;ON;;;;;N;;;;; -2829;BRAILLE PATTERN DOTS-146;So;0;ON;;;;;N;;;;; -282A;BRAILLE PATTERN DOTS-246;So;0;ON;;;;;N;;;;; -282B;BRAILLE PATTERN DOTS-1246;So;0;ON;;;;;N;;;;; -282C;BRAILLE PATTERN DOTS-346;So;0;ON;;;;;N;;;;; -282D;BRAILLE PATTERN DOTS-1346;So;0;ON;;;;;N;;;;; -282E;BRAILLE PATTERN DOTS-2346;So;0;ON;;;;;N;;;;; -282F;BRAILLE PATTERN DOTS-12346;So;0;ON;;;;;N;;;;; -2830;BRAILLE PATTERN DOTS-56;So;0;ON;;;;;N;;;;; -2831;BRAILLE PATTERN DOTS-156;So;0;ON;;;;;N;;;;; -2832;BRAILLE PATTERN DOTS-256;So;0;ON;;;;;N;;;;; -2833;BRAILLE PATTERN DOTS-1256;So;0;ON;;;;;N;;;;; -2834;BRAILLE PATTERN DOTS-356;So;0;ON;;;;;N;;;;; -2835;BRAILLE PATTERN DOTS-1356;So;0;ON;;;;;N;;;;; -2836;BRAILLE PATTERN DOTS-2356;So;0;ON;;;;;N;;;;; -2837;BRAILLE PATTERN DOTS-12356;So;0;ON;;;;;N;;;;; -2838;BRAILLE PATTERN DOTS-456;So;0;ON;;;;;N;;;;; -2839;BRAILLE PATTERN DOTS-1456;So;0;ON;;;;;N;;;;; -283A;BRAILLE PATTERN DOTS-2456;So;0;ON;;;;;N;;;;; -283B;BRAILLE PATTERN DOTS-12456;So;0;ON;;;;;N;;;;; -283C;BRAILLE PATTERN DOTS-3456;So;0;ON;;;;;N;;;;; -283D;BRAILLE PATTERN DOTS-13456;So;0;ON;;;;;N;;;;; -283E;BRAILLE PATTERN DOTS-23456;So;0;ON;;;;;N;;;;; -283F;BRAILLE PATTERN DOTS-123456;So;0;ON;;;;;N;;;;; -2840;BRAILLE PATTERN DOTS-7;So;0;ON;;;;;N;;;;; -2841;BRAILLE PATTERN DOTS-17;So;0;ON;;;;;N;;;;; -2842;BRAILLE PATTERN DOTS-27;So;0;ON;;;;;N;;;;; -2843;BRAILLE PATTERN DOTS-127;So;0;ON;;;;;N;;;;; -2844;BRAILLE PATTERN DOTS-37;So;0;ON;;;;;N;;;;; -2845;BRAILLE PATTERN DOTS-137;So;0;ON;;;;;N;;;;; -2846;BRAILLE PATTERN DOTS-237;So;0;ON;;;;;N;;;;; -2847;BRAILLE PATTERN DOTS-1237;So;0;ON;;;;;N;;;;; -2848;BRAILLE PATTERN DOTS-47;So;0;ON;;;;;N;;;;; -2849;BRAILLE PATTERN DOTS-147;So;0;ON;;;;;N;;;;; -284A;BRAILLE PATTERN DOTS-247;So;0;ON;;;;;N;;;;; -284B;BRAILLE PATTERN DOTS-1247;So;0;ON;;;;;N;;;;; -284C;BRAILLE PATTERN DOTS-347;So;0;ON;;;;;N;;;;; -284D;BRAILLE PATTERN DOTS-1347;So;0;ON;;;;;N;;;;; -284E;BRAILLE PATTERN DOTS-2347;So;0;ON;;;;;N;;;;; -284F;BRAILLE PATTERN DOTS-12347;So;0;ON;;;;;N;;;;; -2850;BRAILLE PATTERN DOTS-57;So;0;ON;;;;;N;;;;; -2851;BRAILLE PATTERN DOTS-157;So;0;ON;;;;;N;;;;; -2852;BRAILLE PATTERN DOTS-257;So;0;ON;;;;;N;;;;; -2853;BRAILLE PATTERN DOTS-1257;So;0;ON;;;;;N;;;;; -2854;BRAILLE PATTERN DOTS-357;So;0;ON;;;;;N;;;;; -2855;BRAILLE PATTERN DOTS-1357;So;0;ON;;;;;N;;;;; -2856;BRAILLE PATTERN DOTS-2357;So;0;ON;;;;;N;;;;; -2857;BRAILLE PATTERN DOTS-12357;So;0;ON;;;;;N;;;;; -2858;BRAILLE PATTERN DOTS-457;So;0;ON;;;;;N;;;;; -2859;BRAILLE PATTERN DOTS-1457;So;0;ON;;;;;N;;;;; -285A;BRAILLE PATTERN DOTS-2457;So;0;ON;;;;;N;;;;; -285B;BRAILLE PATTERN DOTS-12457;So;0;ON;;;;;N;;;;; -285C;BRAILLE PATTERN DOTS-3457;So;0;ON;;;;;N;;;;; -285D;BRAILLE PATTERN DOTS-13457;So;0;ON;;;;;N;;;;; -285E;BRAILLE PATTERN DOTS-23457;So;0;ON;;;;;N;;;;; -285F;BRAILLE PATTERN DOTS-123457;So;0;ON;;;;;N;;;;; -2860;BRAILLE PATTERN DOTS-67;So;0;ON;;;;;N;;;;; -2861;BRAILLE PATTERN DOTS-167;So;0;ON;;;;;N;;;;; -2862;BRAILLE PATTERN DOTS-267;So;0;ON;;;;;N;;;;; -2863;BRAILLE PATTERN DOTS-1267;So;0;ON;;;;;N;;;;; -2864;BRAILLE PATTERN DOTS-367;So;0;ON;;;;;N;;;;; -2865;BRAILLE PATTERN DOTS-1367;So;0;ON;;;;;N;;;;; -2866;BRAILLE PATTERN DOTS-2367;So;0;ON;;;;;N;;;;; -2867;BRAILLE PATTERN DOTS-12367;So;0;ON;;;;;N;;;;; -2868;BRAILLE PATTERN DOTS-467;So;0;ON;;;;;N;;;;; -2869;BRAILLE PATTERN DOTS-1467;So;0;ON;;;;;N;;;;; -286A;BRAILLE PATTERN DOTS-2467;So;0;ON;;;;;N;;;;; -286B;BRAILLE PATTERN DOTS-12467;So;0;ON;;;;;N;;;;; -286C;BRAILLE PATTERN DOTS-3467;So;0;ON;;;;;N;;;;; -286D;BRAILLE PATTERN DOTS-13467;So;0;ON;;;;;N;;;;; -286E;BRAILLE PATTERN DOTS-23467;So;0;ON;;;;;N;;;;; -286F;BRAILLE PATTERN DOTS-123467;So;0;ON;;;;;N;;;;; -2870;BRAILLE PATTERN DOTS-567;So;0;ON;;;;;N;;;;; -2871;BRAILLE PATTERN DOTS-1567;So;0;ON;;;;;N;;;;; -2872;BRAILLE PATTERN DOTS-2567;So;0;ON;;;;;N;;;;; -2873;BRAILLE PATTERN DOTS-12567;So;0;ON;;;;;N;;;;; -2874;BRAILLE PATTERN DOTS-3567;So;0;ON;;;;;N;;;;; -2875;BRAILLE PATTERN DOTS-13567;So;0;ON;;;;;N;;;;; -2876;BRAILLE PATTERN DOTS-23567;So;0;ON;;;;;N;;;;; -2877;BRAILLE PATTERN DOTS-123567;So;0;ON;;;;;N;;;;; -2878;BRAILLE PATTERN DOTS-4567;So;0;ON;;;;;N;;;;; -2879;BRAILLE PATTERN DOTS-14567;So;0;ON;;;;;N;;;;; -287A;BRAILLE PATTERN DOTS-24567;So;0;ON;;;;;N;;;;; -287B;BRAILLE PATTERN DOTS-124567;So;0;ON;;;;;N;;;;; -287C;BRAILLE PATTERN DOTS-34567;So;0;ON;;;;;N;;;;; -287D;BRAILLE PATTERN DOTS-134567;So;0;ON;;;;;N;;;;; -287E;BRAILLE PATTERN DOTS-234567;So;0;ON;;;;;N;;;;; -287F;BRAILLE PATTERN DOTS-1234567;So;0;ON;;;;;N;;;;; -2880;BRAILLE PATTERN DOTS-8;So;0;ON;;;;;N;;;;; -2881;BRAILLE PATTERN DOTS-18;So;0;ON;;;;;N;;;;; -2882;BRAILLE PATTERN DOTS-28;So;0;ON;;;;;N;;;;; -2883;BRAILLE PATTERN DOTS-128;So;0;ON;;;;;N;;;;; -2884;BRAILLE PATTERN DOTS-38;So;0;ON;;;;;N;;;;; -2885;BRAILLE PATTERN DOTS-138;So;0;ON;;;;;N;;;;; -2886;BRAILLE PATTERN DOTS-238;So;0;ON;;;;;N;;;;; -2887;BRAILLE PATTERN DOTS-1238;So;0;ON;;;;;N;;;;; -2888;BRAILLE PATTERN DOTS-48;So;0;ON;;;;;N;;;;; -2889;BRAILLE PATTERN DOTS-148;So;0;ON;;;;;N;;;;; -288A;BRAILLE PATTERN DOTS-248;So;0;ON;;;;;N;;;;; -288B;BRAILLE PATTERN DOTS-1248;So;0;ON;;;;;N;;;;; -288C;BRAILLE PATTERN DOTS-348;So;0;ON;;;;;N;;;;; -288D;BRAILLE PATTERN DOTS-1348;So;0;ON;;;;;N;;;;; -288E;BRAILLE PATTERN DOTS-2348;So;0;ON;;;;;N;;;;; -288F;BRAILLE PATTERN DOTS-12348;So;0;ON;;;;;N;;;;; -2890;BRAILLE PATTERN DOTS-58;So;0;ON;;;;;N;;;;; -2891;BRAILLE PATTERN DOTS-158;So;0;ON;;;;;N;;;;; -2892;BRAILLE PATTERN DOTS-258;So;0;ON;;;;;N;;;;; -2893;BRAILLE PATTERN DOTS-1258;So;0;ON;;;;;N;;;;; -2894;BRAILLE PATTERN DOTS-358;So;0;ON;;;;;N;;;;; -2895;BRAILLE PATTERN DOTS-1358;So;0;ON;;;;;N;;;;; -2896;BRAILLE PATTERN DOTS-2358;So;0;ON;;;;;N;;;;; -2897;BRAILLE PATTERN DOTS-12358;So;0;ON;;;;;N;;;;; -2898;BRAILLE PATTERN DOTS-458;So;0;ON;;;;;N;;;;; -2899;BRAILLE PATTERN DOTS-1458;So;0;ON;;;;;N;;;;; -289A;BRAILLE PATTERN DOTS-2458;So;0;ON;;;;;N;;;;; -289B;BRAILLE PATTERN DOTS-12458;So;0;ON;;;;;N;;;;; -289C;BRAILLE PATTERN DOTS-3458;So;0;ON;;;;;N;;;;; -289D;BRAILLE PATTERN DOTS-13458;So;0;ON;;;;;N;;;;; -289E;BRAILLE PATTERN DOTS-23458;So;0;ON;;;;;N;;;;; -289F;BRAILLE PATTERN DOTS-123458;So;0;ON;;;;;N;;;;; -28A0;BRAILLE PATTERN DOTS-68;So;0;ON;;;;;N;;;;; -28A1;BRAILLE PATTERN DOTS-168;So;0;ON;;;;;N;;;;; -28A2;BRAILLE PATTERN DOTS-268;So;0;ON;;;;;N;;;;; -28A3;BRAILLE PATTERN DOTS-1268;So;0;ON;;;;;N;;;;; -28A4;BRAILLE PATTERN DOTS-368;So;0;ON;;;;;N;;;;; -28A5;BRAILLE PATTERN DOTS-1368;So;0;ON;;;;;N;;;;; -28A6;BRAILLE PATTERN DOTS-2368;So;0;ON;;;;;N;;;;; -28A7;BRAILLE PATTERN DOTS-12368;So;0;ON;;;;;N;;;;; -28A8;BRAILLE PATTERN DOTS-468;So;0;ON;;;;;N;;;;; -28A9;BRAILLE PATTERN DOTS-1468;So;0;ON;;;;;N;;;;; -28AA;BRAILLE PATTERN DOTS-2468;So;0;ON;;;;;N;;;;; -28AB;BRAILLE PATTERN DOTS-12468;So;0;ON;;;;;N;;;;; -28AC;BRAILLE PATTERN DOTS-3468;So;0;ON;;;;;N;;;;; -28AD;BRAILLE PATTERN DOTS-13468;So;0;ON;;;;;N;;;;; -28AE;BRAILLE PATTERN DOTS-23468;So;0;ON;;;;;N;;;;; -28AF;BRAILLE PATTERN DOTS-123468;So;0;ON;;;;;N;;;;; -28B0;BRAILLE PATTERN DOTS-568;So;0;ON;;;;;N;;;;; -28B1;BRAILLE PATTERN DOTS-1568;So;0;ON;;;;;N;;;;; -28B2;BRAILLE PATTERN DOTS-2568;So;0;ON;;;;;N;;;;; -28B3;BRAILLE PATTERN DOTS-12568;So;0;ON;;;;;N;;;;; -28B4;BRAILLE PATTERN DOTS-3568;So;0;ON;;;;;N;;;;; -28B5;BRAILLE PATTERN DOTS-13568;So;0;ON;;;;;N;;;;; -28B6;BRAILLE PATTERN DOTS-23568;So;0;ON;;;;;N;;;;; -28B7;BRAILLE PATTERN DOTS-123568;So;0;ON;;;;;N;;;;; -28B8;BRAILLE PATTERN DOTS-4568;So;0;ON;;;;;N;;;;; -28B9;BRAILLE PATTERN DOTS-14568;So;0;ON;;;;;N;;;;; -28BA;BRAILLE PATTERN DOTS-24568;So;0;ON;;;;;N;;;;; -28BB;BRAILLE PATTERN DOTS-124568;So;0;ON;;;;;N;;;;; -28BC;BRAILLE PATTERN DOTS-34568;So;0;ON;;;;;N;;;;; -28BD;BRAILLE PATTERN DOTS-134568;So;0;ON;;;;;N;;;;; -28BE;BRAILLE PATTERN DOTS-234568;So;0;ON;;;;;N;;;;; -28BF;BRAILLE PATTERN DOTS-1234568;So;0;ON;;;;;N;;;;; -28C0;BRAILLE PATTERN DOTS-78;So;0;ON;;;;;N;;;;; -28C1;BRAILLE PATTERN DOTS-178;So;0;ON;;;;;N;;;;; -28C2;BRAILLE PATTERN DOTS-278;So;0;ON;;;;;N;;;;; -28C3;BRAILLE PATTERN DOTS-1278;So;0;ON;;;;;N;;;;; -28C4;BRAILLE PATTERN DOTS-378;So;0;ON;;;;;N;;;;; -28C5;BRAILLE PATTERN DOTS-1378;So;0;ON;;;;;N;;;;; -28C6;BRAILLE PATTERN DOTS-2378;So;0;ON;;;;;N;;;;; -28C7;BRAILLE PATTERN DOTS-12378;So;0;ON;;;;;N;;;;; -28C8;BRAILLE PATTERN DOTS-478;So;0;ON;;;;;N;;;;; -28C9;BRAILLE PATTERN DOTS-1478;So;0;ON;;;;;N;;;;; -28CA;BRAILLE PATTERN DOTS-2478;So;0;ON;;;;;N;;;;; -28CB;BRAILLE PATTERN DOTS-12478;So;0;ON;;;;;N;;;;; -28CC;BRAILLE PATTERN DOTS-3478;So;0;ON;;;;;N;;;;; -28CD;BRAILLE PATTERN DOTS-13478;So;0;ON;;;;;N;;;;; -28CE;BRAILLE PATTERN DOTS-23478;So;0;ON;;;;;N;;;;; -28CF;BRAILLE PATTERN DOTS-123478;So;0;ON;;;;;N;;;;; -28D0;BRAILLE PATTERN DOTS-578;So;0;ON;;;;;N;;;;; -28D1;BRAILLE PATTERN DOTS-1578;So;0;ON;;;;;N;;;;; -28D2;BRAILLE PATTERN DOTS-2578;So;0;ON;;;;;N;;;;; -28D3;BRAILLE PATTERN DOTS-12578;So;0;ON;;;;;N;;;;; -28D4;BRAILLE PATTERN DOTS-3578;So;0;ON;;;;;N;;;;; -28D5;BRAILLE PATTERN DOTS-13578;So;0;ON;;;;;N;;;;; -28D6;BRAILLE PATTERN DOTS-23578;So;0;ON;;;;;N;;;;; -28D7;BRAILLE PATTERN DOTS-123578;So;0;ON;;;;;N;;;;; -28D8;BRAILLE PATTERN DOTS-4578;So;0;ON;;;;;N;;;;; -28D9;BRAILLE PATTERN DOTS-14578;So;0;ON;;;;;N;;;;; -28DA;BRAILLE PATTERN DOTS-24578;So;0;ON;;;;;N;;;;; -28DB;BRAILLE PATTERN DOTS-124578;So;0;ON;;;;;N;;;;; -28DC;BRAILLE PATTERN DOTS-34578;So;0;ON;;;;;N;;;;; -28DD;BRAILLE PATTERN DOTS-134578;So;0;ON;;;;;N;;;;; -28DE;BRAILLE PATTERN DOTS-234578;So;0;ON;;;;;N;;;;; -28DF;BRAILLE PATTERN DOTS-1234578;So;0;ON;;;;;N;;;;; -28E0;BRAILLE PATTERN DOTS-678;So;0;ON;;;;;N;;;;; -28E1;BRAILLE PATTERN DOTS-1678;So;0;ON;;;;;N;;;;; -28E2;BRAILLE PATTERN DOTS-2678;So;0;ON;;;;;N;;;;; -28E3;BRAILLE PATTERN DOTS-12678;So;0;ON;;;;;N;;;;; -28E4;BRAILLE PATTERN DOTS-3678;So;0;ON;;;;;N;;;;; -28E5;BRAILLE PATTERN DOTS-13678;So;0;ON;;;;;N;;;;; -28E6;BRAILLE PATTERN DOTS-23678;So;0;ON;;;;;N;;;;; -28E7;BRAILLE PATTERN DOTS-123678;So;0;ON;;;;;N;;;;; -28E8;BRAILLE PATTERN DOTS-4678;So;0;ON;;;;;N;;;;; -28E9;BRAILLE PATTERN DOTS-14678;So;0;ON;;;;;N;;;;; -28EA;BRAILLE PATTERN DOTS-24678;So;0;ON;;;;;N;;;;; -28EB;BRAILLE PATTERN DOTS-124678;So;0;ON;;;;;N;;;;; -28EC;BRAILLE PATTERN DOTS-34678;So;0;ON;;;;;N;;;;; -28ED;BRAILLE PATTERN DOTS-134678;So;0;ON;;;;;N;;;;; -28EE;BRAILLE PATTERN DOTS-234678;So;0;ON;;;;;N;;;;; -28EF;BRAILLE PATTERN DOTS-1234678;So;0;ON;;;;;N;;;;; -28F0;BRAILLE PATTERN DOTS-5678;So;0;ON;;;;;N;;;;; -28F1;BRAILLE PATTERN DOTS-15678;So;0;ON;;;;;N;;;;; -28F2;BRAILLE PATTERN DOTS-25678;So;0;ON;;;;;N;;;;; -28F3;BRAILLE PATTERN DOTS-125678;So;0;ON;;;;;N;;;;; -28F4;BRAILLE PATTERN DOTS-35678;So;0;ON;;;;;N;;;;; -28F5;BRAILLE PATTERN DOTS-135678;So;0;ON;;;;;N;;;;; -28F6;BRAILLE PATTERN DOTS-235678;So;0;ON;;;;;N;;;;; -28F7;BRAILLE PATTERN DOTS-1235678;So;0;ON;;;;;N;;;;; -28F8;BRAILLE PATTERN DOTS-45678;So;0;ON;;;;;N;;;;; -28F9;BRAILLE PATTERN DOTS-145678;So;0;ON;;;;;N;;;;; -28FA;BRAILLE PATTERN DOTS-245678;So;0;ON;;;;;N;;;;; -28FB;BRAILLE PATTERN DOTS-1245678;So;0;ON;;;;;N;;;;; -28FC;BRAILLE PATTERN DOTS-345678;So;0;ON;;;;;N;;;;; -28FD;BRAILLE PATTERN DOTS-1345678;So;0;ON;;;;;N;;;;; -28FE;BRAILLE PATTERN DOTS-2345678;So;0;ON;;;;;N;;;;; -28FF;BRAILLE PATTERN DOTS-12345678;So;0;ON;;;;;N;;;;; +2800;BRAILLE PATTERN BLANK;So;0;L;;;;;N;;;;; +2801;BRAILLE PATTERN DOTS-1;So;0;L;;;;;N;;;;; +2802;BRAILLE PATTERN DOTS-2;So;0;L;;;;;N;;;;; +2803;BRAILLE PATTERN DOTS-12;So;0;L;;;;;N;;;;; +2804;BRAILLE PATTERN DOTS-3;So;0;L;;;;;N;;;;; +2805;BRAILLE PATTERN DOTS-13;So;0;L;;;;;N;;;;; +2806;BRAILLE PATTERN DOTS-23;So;0;L;;;;;N;;;;; +2807;BRAILLE PATTERN DOTS-123;So;0;L;;;;;N;;;;; +2808;BRAILLE PATTERN DOTS-4;So;0;L;;;;;N;;;;; +2809;BRAILLE PATTERN DOTS-14;So;0;L;;;;;N;;;;; +280A;BRAILLE PATTERN DOTS-24;So;0;L;;;;;N;;;;; +280B;BRAILLE PATTERN DOTS-124;So;0;L;;;;;N;;;;; +280C;BRAILLE PATTERN DOTS-34;So;0;L;;;;;N;;;;; +280D;BRAILLE PATTERN DOTS-134;So;0;L;;;;;N;;;;; +280E;BRAILLE PATTERN DOTS-234;So;0;L;;;;;N;;;;; +280F;BRAILLE PATTERN DOTS-1234;So;0;L;;;;;N;;;;; +2810;BRAILLE PATTERN DOTS-5;So;0;L;;;;;N;;;;; +2811;BRAILLE PATTERN DOTS-15;So;0;L;;;;;N;;;;; +2812;BRAILLE PATTERN DOTS-25;So;0;L;;;;;N;;;;; +2813;BRAILLE PATTERN DOTS-125;So;0;L;;;;;N;;;;; +2814;BRAILLE PATTERN DOTS-35;So;0;L;;;;;N;;;;; +2815;BRAILLE PATTERN DOTS-135;So;0;L;;;;;N;;;;; +2816;BRAILLE PATTERN DOTS-235;So;0;L;;;;;N;;;;; +2817;BRAILLE PATTERN DOTS-1235;So;0;L;;;;;N;;;;; +2818;BRAILLE PATTERN DOTS-45;So;0;L;;;;;N;;;;; +2819;BRAILLE PATTERN DOTS-145;So;0;L;;;;;N;;;;; +281A;BRAILLE PATTERN DOTS-245;So;0;L;;;;;N;;;;; +281B;BRAILLE PATTERN DOTS-1245;So;0;L;;;;;N;;;;; +281C;BRAILLE PATTERN DOTS-345;So;0;L;;;;;N;;;;; +281D;BRAILLE PATTERN DOTS-1345;So;0;L;;;;;N;;;;; +281E;BRAILLE PATTERN DOTS-2345;So;0;L;;;;;N;;;;; +281F;BRAILLE PATTERN DOTS-12345;So;0;L;;;;;N;;;;; +2820;BRAILLE PATTERN DOTS-6;So;0;L;;;;;N;;;;; +2821;BRAILLE PATTERN DOTS-16;So;0;L;;;;;N;;;;; +2822;BRAILLE PATTERN DOTS-26;So;0;L;;;;;N;;;;; +2823;BRAILLE PATTERN DOTS-126;So;0;L;;;;;N;;;;; +2824;BRAILLE PATTERN DOTS-36;So;0;L;;;;;N;;;;; +2825;BRAILLE PATTERN DOTS-136;So;0;L;;;;;N;;;;; +2826;BRAILLE PATTERN DOTS-236;So;0;L;;;;;N;;;;; +2827;BRAILLE PATTERN DOTS-1236;So;0;L;;;;;N;;;;; +2828;BRAILLE PATTERN DOTS-46;So;0;L;;;;;N;;;;; +2829;BRAILLE PATTERN DOTS-146;So;0;L;;;;;N;;;;; +282A;BRAILLE PATTERN DOTS-246;So;0;L;;;;;N;;;;; +282B;BRAILLE PATTERN DOTS-1246;So;0;L;;;;;N;;;;; +282C;BRAILLE PATTERN DOTS-346;So;0;L;;;;;N;;;;; +282D;BRAILLE PATTERN DOTS-1346;So;0;L;;;;;N;;;;; +282E;BRAILLE PATTERN DOTS-2346;So;0;L;;;;;N;;;;; +282F;BRAILLE PATTERN DOTS-12346;So;0;L;;;;;N;;;;; +2830;BRAILLE PATTERN DOTS-56;So;0;L;;;;;N;;;;; +2831;BRAILLE PATTERN DOTS-156;So;0;L;;;;;N;;;;; +2832;BRAILLE PATTERN DOTS-256;So;0;L;;;;;N;;;;; +2833;BRAILLE PATTERN DOTS-1256;So;0;L;;;;;N;;;;; +2834;BRAILLE PATTERN DOTS-356;So;0;L;;;;;N;;;;; +2835;BRAILLE PATTERN DOTS-1356;So;0;L;;;;;N;;;;; +2836;BRAILLE PATTERN DOTS-2356;So;0;L;;;;;N;;;;; +2837;BRAILLE PATTERN DOTS-12356;So;0;L;;;;;N;;;;; +2838;BRAILLE PATTERN DOTS-456;So;0;L;;;;;N;;;;; +2839;BRAILLE PATTERN DOTS-1456;So;0;L;;;;;N;;;;; +283A;BRAILLE PATTERN DOTS-2456;So;0;L;;;;;N;;;;; +283B;BRAILLE PATTERN DOTS-12456;So;0;L;;;;;N;;;;; +283C;BRAILLE PATTERN DOTS-3456;So;0;L;;;;;N;;;;; +283D;BRAILLE PATTERN DOTS-13456;So;0;L;;;;;N;;;;; +283E;BRAILLE PATTERN DOTS-23456;So;0;L;;;;;N;;;;; +283F;BRAILLE PATTERN DOTS-123456;So;0;L;;;;;N;;;;; +2840;BRAILLE PATTERN DOTS-7;So;0;L;;;;;N;;;;; +2841;BRAILLE PATTERN DOTS-17;So;0;L;;;;;N;;;;; +2842;BRAILLE PATTERN DOTS-27;So;0;L;;;;;N;;;;; +2843;BRAILLE PATTERN DOTS-127;So;0;L;;;;;N;;;;; +2844;BRAILLE PATTERN DOTS-37;So;0;L;;;;;N;;;;; +2845;BRAILLE PATTERN DOTS-137;So;0;L;;;;;N;;;;; +2846;BRAILLE PATTERN DOTS-237;So;0;L;;;;;N;;;;; +2847;BRAILLE PATTERN DOTS-1237;So;0;L;;;;;N;;;;; +2848;BRAILLE PATTERN DOTS-47;So;0;L;;;;;N;;;;; +2849;BRAILLE PATTERN DOTS-147;So;0;L;;;;;N;;;;; +284A;BRAILLE PATTERN DOTS-247;So;0;L;;;;;N;;;;; +284B;BRAILLE PATTERN DOTS-1247;So;0;L;;;;;N;;;;; +284C;BRAILLE PATTERN DOTS-347;So;0;L;;;;;N;;;;; +284D;BRAILLE PATTERN DOTS-1347;So;0;L;;;;;N;;;;; +284E;BRAILLE PATTERN DOTS-2347;So;0;L;;;;;N;;;;; +284F;BRAILLE PATTERN DOTS-12347;So;0;L;;;;;N;;;;; +2850;BRAILLE PATTERN DOTS-57;So;0;L;;;;;N;;;;; +2851;BRAILLE PATTERN DOTS-157;So;0;L;;;;;N;;;;; +2852;BRAILLE PATTERN DOTS-257;So;0;L;;;;;N;;;;; +2853;BRAILLE PATTERN DOTS-1257;So;0;L;;;;;N;;;;; +2854;BRAILLE PATTERN DOTS-357;So;0;L;;;;;N;;;;; +2855;BRAILLE PATTERN DOTS-1357;So;0;L;;;;;N;;;;; +2856;BRAILLE PATTERN DOTS-2357;So;0;L;;;;;N;;;;; +2857;BRAILLE PATTERN DOTS-12357;So;0;L;;;;;N;;;;; +2858;BRAILLE PATTERN DOTS-457;So;0;L;;;;;N;;;;; +2859;BRAILLE PATTERN DOTS-1457;So;0;L;;;;;N;;;;; +285A;BRAILLE PATTERN DOTS-2457;So;0;L;;;;;N;;;;; +285B;BRAILLE PATTERN DOTS-12457;So;0;L;;;;;N;;;;; +285C;BRAILLE PATTERN DOTS-3457;So;0;L;;;;;N;;;;; +285D;BRAILLE PATTERN DOTS-13457;So;0;L;;;;;N;;;;; +285E;BRAILLE PATTERN DOTS-23457;So;0;L;;;;;N;;;;; +285F;BRAILLE PATTERN DOTS-123457;So;0;L;;;;;N;;;;; +2860;BRAILLE PATTERN DOTS-67;So;0;L;;;;;N;;;;; +2861;BRAILLE PATTERN DOTS-167;So;0;L;;;;;N;;;;; +2862;BRAILLE PATTERN DOTS-267;So;0;L;;;;;N;;;;; +2863;BRAILLE PATTERN DOTS-1267;So;0;L;;;;;N;;;;; +2864;BRAILLE PATTERN DOTS-367;So;0;L;;;;;N;;;;; +2865;BRAILLE PATTERN DOTS-1367;So;0;L;;;;;N;;;;; +2866;BRAILLE PATTERN DOTS-2367;So;0;L;;;;;N;;;;; +2867;BRAILLE PATTERN DOTS-12367;So;0;L;;;;;N;;;;; +2868;BRAILLE PATTERN DOTS-467;So;0;L;;;;;N;;;;; +2869;BRAILLE PATTERN DOTS-1467;So;0;L;;;;;N;;;;; +286A;BRAILLE PATTERN DOTS-2467;So;0;L;;;;;N;;;;; +286B;BRAILLE PATTERN DOTS-12467;So;0;L;;;;;N;;;;; +286C;BRAILLE PATTERN DOTS-3467;So;0;L;;;;;N;;;;; +286D;BRAILLE PATTERN DOTS-13467;So;0;L;;;;;N;;;;; +286E;BRAILLE PATTERN DOTS-23467;So;0;L;;;;;N;;;;; +286F;BRAILLE PATTERN DOTS-123467;So;0;L;;;;;N;;;;; +2870;BRAILLE PATTERN DOTS-567;So;0;L;;;;;N;;;;; +2871;BRAILLE PATTERN DOTS-1567;So;0;L;;;;;N;;;;; +2872;BRAILLE PATTERN DOTS-2567;So;0;L;;;;;N;;;;; +2873;BRAILLE PATTERN DOTS-12567;So;0;L;;;;;N;;;;; +2874;BRAILLE PATTERN DOTS-3567;So;0;L;;;;;N;;;;; +2875;BRAILLE PATTERN DOTS-13567;So;0;L;;;;;N;;;;; +2876;BRAILLE PATTERN DOTS-23567;So;0;L;;;;;N;;;;; +2877;BRAILLE PATTERN DOTS-123567;So;0;L;;;;;N;;;;; +2878;BRAILLE PATTERN DOTS-4567;So;0;L;;;;;N;;;;; +2879;BRAILLE PATTERN DOTS-14567;So;0;L;;;;;N;;;;; +287A;BRAILLE PATTERN DOTS-24567;So;0;L;;;;;N;;;;; +287B;BRAILLE PATTERN DOTS-124567;So;0;L;;;;;N;;;;; +287C;BRAILLE PATTERN DOTS-34567;So;0;L;;;;;N;;;;; +287D;BRAILLE PATTERN DOTS-134567;So;0;L;;;;;N;;;;; +287E;BRAILLE PATTERN DOTS-234567;So;0;L;;;;;N;;;;; +287F;BRAILLE PATTERN DOTS-1234567;So;0;L;;;;;N;;;;; +2880;BRAILLE PATTERN DOTS-8;So;0;L;;;;;N;;;;; +2881;BRAILLE PATTERN DOTS-18;So;0;L;;;;;N;;;;; +2882;BRAILLE PATTERN DOTS-28;So;0;L;;;;;N;;;;; +2883;BRAILLE PATTERN DOTS-128;So;0;L;;;;;N;;;;; +2884;BRAILLE PATTERN DOTS-38;So;0;L;;;;;N;;;;; +2885;BRAILLE PATTERN DOTS-138;So;0;L;;;;;N;;;;; +2886;BRAILLE PATTERN DOTS-238;So;0;L;;;;;N;;;;; +2887;BRAILLE PATTERN DOTS-1238;So;0;L;;;;;N;;;;; +2888;BRAILLE PATTERN DOTS-48;So;0;L;;;;;N;;;;; +2889;BRAILLE PATTERN DOTS-148;So;0;L;;;;;N;;;;; +288A;BRAILLE PATTERN DOTS-248;So;0;L;;;;;N;;;;; +288B;BRAILLE PATTERN DOTS-1248;So;0;L;;;;;N;;;;; +288C;BRAILLE PATTERN DOTS-348;So;0;L;;;;;N;;;;; +288D;BRAILLE PATTERN DOTS-1348;So;0;L;;;;;N;;;;; +288E;BRAILLE PATTERN DOTS-2348;So;0;L;;;;;N;;;;; +288F;BRAILLE PATTERN DOTS-12348;So;0;L;;;;;N;;;;; +2890;BRAILLE PATTERN DOTS-58;So;0;L;;;;;N;;;;; +2891;BRAILLE PATTERN DOTS-158;So;0;L;;;;;N;;;;; +2892;BRAILLE PATTERN DOTS-258;So;0;L;;;;;N;;;;; +2893;BRAILLE PATTERN DOTS-1258;So;0;L;;;;;N;;;;; +2894;BRAILLE PATTERN DOTS-358;So;0;L;;;;;N;;;;; +2895;BRAILLE PATTERN DOTS-1358;So;0;L;;;;;N;;;;; +2896;BRAILLE PATTERN DOTS-2358;So;0;L;;;;;N;;;;; +2897;BRAILLE PATTERN DOTS-12358;So;0;L;;;;;N;;;;; +2898;BRAILLE PATTERN DOTS-458;So;0;L;;;;;N;;;;; +2899;BRAILLE PATTERN DOTS-1458;So;0;L;;;;;N;;;;; +289A;BRAILLE PATTERN DOTS-2458;So;0;L;;;;;N;;;;; +289B;BRAILLE PATTERN DOTS-12458;So;0;L;;;;;N;;;;; +289C;BRAILLE PATTERN DOTS-3458;So;0;L;;;;;N;;;;; +289D;BRAILLE PATTERN DOTS-13458;So;0;L;;;;;N;;;;; +289E;BRAILLE PATTERN DOTS-23458;So;0;L;;;;;N;;;;; +289F;BRAILLE PATTERN DOTS-123458;So;0;L;;;;;N;;;;; +28A0;BRAILLE PATTERN DOTS-68;So;0;L;;;;;N;;;;; +28A1;BRAILLE PATTERN DOTS-168;So;0;L;;;;;N;;;;; +28A2;BRAILLE PATTERN DOTS-268;So;0;L;;;;;N;;;;; +28A3;BRAILLE PATTERN DOTS-1268;So;0;L;;;;;N;;;;; +28A4;BRAILLE PATTERN DOTS-368;So;0;L;;;;;N;;;;; +28A5;BRAILLE PATTERN DOTS-1368;So;0;L;;;;;N;;;;; +28A6;BRAILLE PATTERN DOTS-2368;So;0;L;;;;;N;;;;; +28A7;BRAILLE PATTERN DOTS-12368;So;0;L;;;;;N;;;;; +28A8;BRAILLE PATTERN DOTS-468;So;0;L;;;;;N;;;;; +28A9;BRAILLE PATTERN DOTS-1468;So;0;L;;;;;N;;;;; +28AA;BRAILLE PATTERN DOTS-2468;So;0;L;;;;;N;;;;; +28AB;BRAILLE PATTERN DOTS-12468;So;0;L;;;;;N;;;;; +28AC;BRAILLE PATTERN DOTS-3468;So;0;L;;;;;N;;;;; +28AD;BRAILLE PATTERN DOTS-13468;So;0;L;;;;;N;;;;; +28AE;BRAILLE PATTERN DOTS-23468;So;0;L;;;;;N;;;;; +28AF;BRAILLE PATTERN DOTS-123468;So;0;L;;;;;N;;;;; +28B0;BRAILLE PATTERN DOTS-568;So;0;L;;;;;N;;;;; +28B1;BRAILLE PATTERN DOTS-1568;So;0;L;;;;;N;;;;; +28B2;BRAILLE PATTERN DOTS-2568;So;0;L;;;;;N;;;;; +28B3;BRAILLE PATTERN DOTS-12568;So;0;L;;;;;N;;;;; +28B4;BRAILLE PATTERN DOTS-3568;So;0;L;;;;;N;;;;; +28B5;BRAILLE PATTERN DOTS-13568;So;0;L;;;;;N;;;;; +28B6;BRAILLE PATTERN DOTS-23568;So;0;L;;;;;N;;;;; +28B7;BRAILLE PATTERN DOTS-123568;So;0;L;;;;;N;;;;; +28B8;BRAILLE PATTERN DOTS-4568;So;0;L;;;;;N;;;;; +28B9;BRAILLE PATTERN DOTS-14568;So;0;L;;;;;N;;;;; +28BA;BRAILLE PATTERN DOTS-24568;So;0;L;;;;;N;;;;; +28BB;BRAILLE PATTERN DOTS-124568;So;0;L;;;;;N;;;;; +28BC;BRAILLE PATTERN DOTS-34568;So;0;L;;;;;N;;;;; +28BD;BRAILLE PATTERN DOTS-134568;So;0;L;;;;;N;;;;; +28BE;BRAILLE PATTERN DOTS-234568;So;0;L;;;;;N;;;;; +28BF;BRAILLE PATTERN DOTS-1234568;So;0;L;;;;;N;;;;; +28C0;BRAILLE PATTERN DOTS-78;So;0;L;;;;;N;;;;; +28C1;BRAILLE PATTERN DOTS-178;So;0;L;;;;;N;;;;; +28C2;BRAILLE PATTERN DOTS-278;So;0;L;;;;;N;;;;; +28C3;BRAILLE PATTERN DOTS-1278;So;0;L;;;;;N;;;;; +28C4;BRAILLE PATTERN DOTS-378;So;0;L;;;;;N;;;;; +28C5;BRAILLE PATTERN DOTS-1378;So;0;L;;;;;N;;;;; +28C6;BRAILLE PATTERN DOTS-2378;So;0;L;;;;;N;;;;; +28C7;BRAILLE PATTERN DOTS-12378;So;0;L;;;;;N;;;;; +28C8;BRAILLE PATTERN DOTS-478;So;0;L;;;;;N;;;;; +28C9;BRAILLE PATTERN DOTS-1478;So;0;L;;;;;N;;;;; +28CA;BRAILLE PATTERN DOTS-2478;So;0;L;;;;;N;;;;; +28CB;BRAILLE PATTERN DOTS-12478;So;0;L;;;;;N;;;;; +28CC;BRAILLE PATTERN DOTS-3478;So;0;L;;;;;N;;;;; +28CD;BRAILLE PATTERN DOTS-13478;So;0;L;;;;;N;;;;; +28CE;BRAILLE PATTERN DOTS-23478;So;0;L;;;;;N;;;;; +28CF;BRAILLE PATTERN DOTS-123478;So;0;L;;;;;N;;;;; +28D0;BRAILLE PATTERN DOTS-578;So;0;L;;;;;N;;;;; +28D1;BRAILLE PATTERN DOTS-1578;So;0;L;;;;;N;;;;; +28D2;BRAILLE PATTERN DOTS-2578;So;0;L;;;;;N;;;;; +28D3;BRAILLE PATTERN DOTS-12578;So;0;L;;;;;N;;;;; +28D4;BRAILLE PATTERN DOTS-3578;So;0;L;;;;;N;;;;; +28D5;BRAILLE PATTERN DOTS-13578;So;0;L;;;;;N;;;;; +28D6;BRAILLE PATTERN DOTS-23578;So;0;L;;;;;N;;;;; +28D7;BRAILLE PATTERN DOTS-123578;So;0;L;;;;;N;;;;; +28D8;BRAILLE PATTERN DOTS-4578;So;0;L;;;;;N;;;;; +28D9;BRAILLE PATTERN DOTS-14578;So;0;L;;;;;N;;;;; +28DA;BRAILLE PATTERN DOTS-24578;So;0;L;;;;;N;;;;; +28DB;BRAILLE PATTERN DOTS-124578;So;0;L;;;;;N;;;;; +28DC;BRAILLE PATTERN DOTS-34578;So;0;L;;;;;N;;;;; +28DD;BRAILLE PATTERN DOTS-134578;So;0;L;;;;;N;;;;; +28DE;BRAILLE PATTERN DOTS-234578;So;0;L;;;;;N;;;;; +28DF;BRAILLE PATTERN DOTS-1234578;So;0;L;;;;;N;;;;; +28E0;BRAILLE PATTERN DOTS-678;So;0;L;;;;;N;;;;; +28E1;BRAILLE PATTERN DOTS-1678;So;0;L;;;;;N;;;;; +28E2;BRAILLE PATTERN DOTS-2678;So;0;L;;;;;N;;;;; +28E3;BRAILLE PATTERN DOTS-12678;So;0;L;;;;;N;;;;; +28E4;BRAILLE PATTERN DOTS-3678;So;0;L;;;;;N;;;;; +28E5;BRAILLE PATTERN DOTS-13678;So;0;L;;;;;N;;;;; +28E6;BRAILLE PATTERN DOTS-23678;So;0;L;;;;;N;;;;; +28E7;BRAILLE PATTERN DOTS-123678;So;0;L;;;;;N;;;;; +28E8;BRAILLE PATTERN DOTS-4678;So;0;L;;;;;N;;;;; +28E9;BRAILLE PATTERN DOTS-14678;So;0;L;;;;;N;;;;; +28EA;BRAILLE PATTERN DOTS-24678;So;0;L;;;;;N;;;;; +28EB;BRAILLE PATTERN DOTS-124678;So;0;L;;;;;N;;;;; +28EC;BRAILLE PATTERN DOTS-34678;So;0;L;;;;;N;;;;; +28ED;BRAILLE PATTERN DOTS-134678;So;0;L;;;;;N;;;;; +28EE;BRAILLE PATTERN DOTS-234678;So;0;L;;;;;N;;;;; +28EF;BRAILLE PATTERN DOTS-1234678;So;0;L;;;;;N;;;;; +28F0;BRAILLE PATTERN DOTS-5678;So;0;L;;;;;N;;;;; +28F1;BRAILLE PATTERN DOTS-15678;So;0;L;;;;;N;;;;; +28F2;BRAILLE PATTERN DOTS-25678;So;0;L;;;;;N;;;;; +28F3;BRAILLE PATTERN DOTS-125678;So;0;L;;;;;N;;;;; +28F4;BRAILLE PATTERN DOTS-35678;So;0;L;;;;;N;;;;; +28F5;BRAILLE PATTERN DOTS-135678;So;0;L;;;;;N;;;;; +28F6;BRAILLE PATTERN DOTS-235678;So;0;L;;;;;N;;;;; +28F7;BRAILLE PATTERN DOTS-1235678;So;0;L;;;;;N;;;;; +28F8;BRAILLE PATTERN DOTS-45678;So;0;L;;;;;N;;;;; +28F9;BRAILLE PATTERN DOTS-145678;So;0;L;;;;;N;;;;; +28FA;BRAILLE PATTERN DOTS-245678;So;0;L;;;;;N;;;;; +28FB;BRAILLE PATTERN DOTS-1245678;So;0;L;;;;;N;;;;; +28FC;BRAILLE PATTERN DOTS-345678;So;0;L;;;;;N;;;;; +28FD;BRAILLE PATTERN DOTS-1345678;So;0;L;;;;;N;;;;; +28FE;BRAILLE PATTERN DOTS-2345678;So;0;L;;;;;N;;;;; +28FF;BRAILLE PATTERN DOTS-12345678;So;0;L;;;;;N;;;;; 2900;RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2901;RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2902;LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; @@ -8043,6 +9092,564 @@ 2B0B;SOUTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;; 2B0C;LEFT RIGHT BLACK ARROW;So;0;ON;;;;;N;;;;; 2B0D;UP DOWN BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0E;RIGHTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;; +2B0F;RIGHTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;; +2B10;LEFTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;; +2B11;LEFTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;; +2B12;SQUARE WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;; +2B13;SQUARE WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;; +2B14;SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +2B15;SQUARE WITH LOWER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +2B16;DIAMOND WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +2B17;DIAMOND WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; +2B18;DIAMOND WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;; +2B19;DIAMOND WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;; +2B1A;DOTTED SQUARE;So;0;ON;;;;;N;;;;; +2B1B;BLACK LARGE SQUARE;So;0;ON;;;;;N;;;;; +2B1C;WHITE LARGE SQUARE;So;0;ON;;;;;N;;;;; +2B1D;BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; +2B1E;WHITE VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; +2B1F;BLACK PENTAGON;So;0;ON;;;;;N;;;;; +2B20;WHITE PENTAGON;So;0;ON;;;;;N;;;;; +2B21;WHITE HEXAGON;So;0;ON;;;;;N;;;;; +2B22;BLACK HEXAGON;So;0;ON;;;;;N;;;;; +2B23;HORIZONTAL BLACK HEXAGON;So;0;ON;;;;;N;;;;; +2B24;BLACK LARGE CIRCLE;So;0;ON;;;;;N;;;;; +2B25;BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;; +2B26;WHITE MEDIUM DIAMOND;So;0;ON;;;;;N;;;;; +2B27;BLACK MEDIUM LOZENGE;So;0;ON;;;;;N;;;;; +2B28;WHITE MEDIUM LOZENGE;So;0;ON;;;;;N;;;;; +2B29;BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;; +2B2A;BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;; +2B2B;WHITE SMALL LOZENGE;So;0;ON;;;;;N;;;;; +2B2C;BLACK HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;; +2B2D;WHITE HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;; +2B2E;BLACK VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;; +2B2F;WHITE VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;; +2B30;LEFT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +2B31;THREE LEFTWARDS ARROWS;Sm;0;ON;;;;;N;;;;; +2B32;LEFT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; +2B33;LONG LEFTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;; +2B34;LEFTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B35;LEFTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B36;LEFTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +2B37;LEFTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +2B38;LEFTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;; +2B39;LEFTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B3A;LEFTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B3B;LEFTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;; +2B3C;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B3D;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B3E;LEFTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;; +2B3F;WAVE ARROW POINTING DIRECTLY LEFT;Sm;0;ON;;;;;N;;;;; +2B40;EQUALS SIGN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2B41;REVERSE TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2B42;LEFTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; +2B43;RIGHTWARDS ARROW THROUGH GREATER-THAN;Sm;0;ON;;;;;N;;;;; +2B44;RIGHTWARDS ARROW THROUGH SUPERSET;Sm;0;ON;;;;;N;;;;; +2B45;LEFTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;; +2B46;RIGHTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;; +2B47;REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2B48;RIGHTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; +2B49;TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2B4A;LEFTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; +2B4B;LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; +2B4C;RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; +2B50;WHITE MEDIUM STAR;So;0;ON;;;;;N;;;;; +2B51;BLACK SMALL STAR;So;0;ON;;;;;N;;;;; +2B52;WHITE SMALL STAR;So;0;ON;;;;;N;;;;; +2B53;BLACK RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;; +2B54;WHITE RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;; +2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30; +2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31; +2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32; +2C03;GLAGOLITIC CAPITAL LETTER GLAGOLI;Lu;0;L;;;;;N;;;;2C33; +2C04;GLAGOLITIC CAPITAL LETTER DOBRO;Lu;0;L;;;;;N;;;;2C34; +2C05;GLAGOLITIC CAPITAL LETTER YESTU;Lu;0;L;;;;;N;;;;2C35; +2C06;GLAGOLITIC CAPITAL LETTER ZHIVETE;Lu;0;L;;;;;N;;;;2C36; +2C07;GLAGOLITIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;2C37; +2C08;GLAGOLITIC CAPITAL LETTER ZEMLJA;Lu;0;L;;;;;N;;;;2C38; +2C09;GLAGOLITIC CAPITAL LETTER IZHE;Lu;0;L;;;;;N;;;;2C39; +2C0A;GLAGOLITIC CAPITAL LETTER INITIAL IZHE;Lu;0;L;;;;;N;;;;2C3A; +2C0B;GLAGOLITIC CAPITAL LETTER I;Lu;0;L;;;;;N;;;;2C3B; +2C0C;GLAGOLITIC CAPITAL LETTER DJERVI;Lu;0;L;;;;;N;;;;2C3C; +2C0D;GLAGOLITIC CAPITAL LETTER KAKO;Lu;0;L;;;;;N;;;;2C3D; +2C0E;GLAGOLITIC CAPITAL LETTER LJUDIJE;Lu;0;L;;;;;N;;;;2C3E; +2C0F;GLAGOLITIC CAPITAL LETTER MYSLITE;Lu;0;L;;;;;N;;;;2C3F; +2C10;GLAGOLITIC CAPITAL LETTER NASHI;Lu;0;L;;;;;N;;;;2C40; +2C11;GLAGOLITIC CAPITAL LETTER ONU;Lu;0;L;;;;;N;;;;2C41; +2C12;GLAGOLITIC CAPITAL LETTER POKOJI;Lu;0;L;;;;;N;;;;2C42; +2C13;GLAGOLITIC CAPITAL LETTER RITSI;Lu;0;L;;;;;N;;;;2C43; +2C14;GLAGOLITIC CAPITAL LETTER SLOVO;Lu;0;L;;;;;N;;;;2C44; +2C15;GLAGOLITIC CAPITAL LETTER TVRIDO;Lu;0;L;;;;;N;;;;2C45; +2C16;GLAGOLITIC CAPITAL LETTER UKU;Lu;0;L;;;;;N;;;;2C46; +2C17;GLAGOLITIC CAPITAL LETTER FRITU;Lu;0;L;;;;;N;;;;2C47; +2C18;GLAGOLITIC CAPITAL LETTER HERU;Lu;0;L;;;;;N;;;;2C48; +2C19;GLAGOLITIC CAPITAL LETTER OTU;Lu;0;L;;;;;N;;;;2C49; +2C1A;GLAGOLITIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;2C4A; +2C1B;GLAGOLITIC CAPITAL LETTER SHTA;Lu;0;L;;;;;N;;;;2C4B; +2C1C;GLAGOLITIC CAPITAL LETTER TSI;Lu;0;L;;;;;N;;;;2C4C; +2C1D;GLAGOLITIC CAPITAL LETTER CHRIVI;Lu;0;L;;;;;N;;;;2C4D; +2C1E;GLAGOLITIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;2C4E; +2C1F;GLAGOLITIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;;;;2C4F; +2C20;GLAGOLITIC CAPITAL LETTER YERI;Lu;0;L;;;;;N;;;;2C50; +2C21;GLAGOLITIC CAPITAL LETTER YATI;Lu;0;L;;;;;N;;;;2C51; +2C22;GLAGOLITIC CAPITAL LETTER SPIDERY HA;Lu;0;L;;;;;N;;;;2C52; +2C23;GLAGOLITIC CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;2C53; +2C24;GLAGOLITIC CAPITAL LETTER SMALL YUS;Lu;0;L;;;;;N;;;;2C54; +2C25;GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL;Lu;0;L;;;;;N;;;;2C55; +2C26;GLAGOLITIC CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;2C56; +2C27;GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS;Lu;0;L;;;;;N;;;;2C57; +2C28;GLAGOLITIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;2C58; +2C29;GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS;Lu;0;L;;;;;N;;;;2C59; +2C2A;GLAGOLITIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;2C5A; +2C2B;GLAGOLITIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;2C5B; +2C2C;GLAGOLITIC CAPITAL LETTER SHTAPIC;Lu;0;L;;;;;N;;;;2C5C; +2C2D;GLAGOLITIC CAPITAL LETTER TROKUTASTI A;Lu;0;L;;;;;N;;;;2C5D; +2C2E;GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE;Lu;0;L;;;;;N;;;;2C5E; +2C30;GLAGOLITIC SMALL LETTER AZU;Ll;0;L;;;;;N;;;2C00;;2C00 +2C31;GLAGOLITIC SMALL LETTER BUKY;Ll;0;L;;;;;N;;;2C01;;2C01 +2C32;GLAGOLITIC SMALL LETTER VEDE;Ll;0;L;;;;;N;;;2C02;;2C02 +2C33;GLAGOLITIC SMALL LETTER GLAGOLI;Ll;0;L;;;;;N;;;2C03;;2C03 +2C34;GLAGOLITIC SMALL LETTER DOBRO;Ll;0;L;;;;;N;;;2C04;;2C04 +2C35;GLAGOLITIC SMALL LETTER YESTU;Ll;0;L;;;;;N;;;2C05;;2C05 +2C36;GLAGOLITIC SMALL LETTER ZHIVETE;Ll;0;L;;;;;N;;;2C06;;2C06 +2C37;GLAGOLITIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;2C07;;2C07 +2C38;GLAGOLITIC SMALL LETTER ZEMLJA;Ll;0;L;;;;;N;;;2C08;;2C08 +2C39;GLAGOLITIC SMALL LETTER IZHE;Ll;0;L;;;;;N;;;2C09;;2C09 +2C3A;GLAGOLITIC SMALL LETTER INITIAL IZHE;Ll;0;L;;;;;N;;;2C0A;;2C0A +2C3B;GLAGOLITIC SMALL LETTER I;Ll;0;L;;;;;N;;;2C0B;;2C0B +2C3C;GLAGOLITIC SMALL LETTER DJERVI;Ll;0;L;;;;;N;;;2C0C;;2C0C +2C3D;GLAGOLITIC SMALL LETTER KAKO;Ll;0;L;;;;;N;;;2C0D;;2C0D +2C3E;GLAGOLITIC SMALL LETTER LJUDIJE;Ll;0;L;;;;;N;;;2C0E;;2C0E +2C3F;GLAGOLITIC SMALL LETTER MYSLITE;Ll;0;L;;;;;N;;;2C0F;;2C0F +2C40;GLAGOLITIC SMALL LETTER NASHI;Ll;0;L;;;;;N;;;2C10;;2C10 +2C41;GLAGOLITIC SMALL LETTER ONU;Ll;0;L;;;;;N;;;2C11;;2C11 +2C42;GLAGOLITIC SMALL LETTER POKOJI;Ll;0;L;;;;;N;;;2C12;;2C12 +2C43;GLAGOLITIC SMALL LETTER RITSI;Ll;0;L;;;;;N;;;2C13;;2C13 +2C44;GLAGOLITIC SMALL LETTER SLOVO;Ll;0;L;;;;;N;;;2C14;;2C14 +2C45;GLAGOLITIC SMALL LETTER TVRIDO;Ll;0;L;;;;;N;;;2C15;;2C15 +2C46;GLAGOLITIC SMALL LETTER UKU;Ll;0;L;;;;;N;;;2C16;;2C16 +2C47;GLAGOLITIC SMALL LETTER FRITU;Ll;0;L;;;;;N;;;2C17;;2C17 +2C48;GLAGOLITIC SMALL LETTER HERU;Ll;0;L;;;;;N;;;2C18;;2C18 +2C49;GLAGOLITIC SMALL LETTER OTU;Ll;0;L;;;;;N;;;2C19;;2C19 +2C4A;GLAGOLITIC SMALL LETTER PE;Ll;0;L;;;;;N;;;2C1A;;2C1A +2C4B;GLAGOLITIC SMALL LETTER SHTA;Ll;0;L;;;;;N;;;2C1B;;2C1B +2C4C;GLAGOLITIC SMALL LETTER TSI;Ll;0;L;;;;;N;;;2C1C;;2C1C +2C4D;GLAGOLITIC SMALL LETTER CHRIVI;Ll;0;L;;;;;N;;;2C1D;;2C1D +2C4E;GLAGOLITIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;2C1E;;2C1E +2C4F;GLAGOLITIC SMALL LETTER YERU;Ll;0;L;;;;;N;;;2C1F;;2C1F +2C50;GLAGOLITIC SMALL LETTER YERI;Ll;0;L;;;;;N;;;2C20;;2C20 +2C51;GLAGOLITIC SMALL LETTER YATI;Ll;0;L;;;;;N;;;2C21;;2C21 +2C52;GLAGOLITIC SMALL LETTER SPIDERY HA;Ll;0;L;;;;;N;;;2C22;;2C22 +2C53;GLAGOLITIC SMALL LETTER YU;Ll;0;L;;;;;N;;;2C23;;2C23 +2C54;GLAGOLITIC SMALL LETTER SMALL YUS;Ll;0;L;;;;;N;;;2C24;;2C24 +2C55;GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL;Ll;0;L;;;;;N;;;2C25;;2C25 +2C56;GLAGOLITIC SMALL LETTER YO;Ll;0;L;;;;;N;;;2C26;;2C26 +2C57;GLAGOLITIC SMALL LETTER IOTATED SMALL YUS;Ll;0;L;;;;;N;;;2C27;;2C27 +2C58;GLAGOLITIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;2C28;;2C28 +2C59;GLAGOLITIC SMALL LETTER IOTATED BIG YUS;Ll;0;L;;;;;N;;;2C29;;2C29 +2C5A;GLAGOLITIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;2C2A;;2C2A +2C5B;GLAGOLITIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;2C2B;;2C2B +2C5C;GLAGOLITIC SMALL LETTER SHTAPIC;Ll;0;L;;;;;N;;;2C2C;;2C2C +2C5D;GLAGOLITIC SMALL LETTER TROKUTASTI A;Ll;0;L;;;;;N;;;2C2D;;2C2D +2C5E;GLAGOLITIC SMALL LETTER LATINATE MYSLITE;Ll;0;L;;;;;N;;;2C2E;;2C2E +2C60;LATIN CAPITAL LETTER L WITH DOUBLE BAR;Lu;0;L;;;;;N;;;;2C61; +2C61;LATIN SMALL LETTER L WITH DOUBLE BAR;Ll;0;L;;;;;N;;;2C60;;2C60 +2C62;LATIN CAPITAL LETTER L WITH MIDDLE TILDE;Lu;0;L;;;;;N;;;;026B; +2C63;LATIN CAPITAL LETTER P WITH STROKE;Lu;0;L;;;;;N;;;;1D7D; +2C64;LATIN CAPITAL LETTER R WITH TAIL;Lu;0;L;;;;;N;;;;027D; +2C65;LATIN SMALL LETTER A WITH STROKE;Ll;0;L;;;;;N;;;023A;;023A +2C66;LATIN SMALL LETTER T WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;023E;;023E +2C67;LATIN CAPITAL LETTER H WITH DESCENDER;Lu;0;L;;;;;N;;;;2C68; +2C68;LATIN SMALL LETTER H WITH DESCENDER;Ll;0;L;;;;;N;;;2C67;;2C67 +2C69;LATIN CAPITAL LETTER K WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6A; +2C6A;LATIN SMALL LETTER K WITH DESCENDER;Ll;0;L;;;;;N;;;2C69;;2C69 +2C6B;LATIN CAPITAL LETTER Z WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6C; +2C6C;LATIN SMALL LETTER Z WITH DESCENDER;Ll;0;L;;;;;N;;;2C6B;;2C6B +2C6D;LATIN CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;0251; +2C6E;LATIN CAPITAL LETTER M WITH HOOK;Lu;0;L;;;;;N;;;;0271; +2C6F;LATIN CAPITAL LETTER TURNED A;Lu;0;L;;;;;N;;;;0250; +2C71;LATIN SMALL LETTER V WITH RIGHT HOOK;Ll;0;L;;;;;N;;;;; +2C72;LATIN CAPITAL LETTER W WITH HOOK;Lu;0;L;;;;;N;;;;2C73; +2C73;LATIN SMALL LETTER W WITH HOOK;Ll;0;L;;;;;N;;;2C72;;2C72 +2C74;LATIN SMALL LETTER V WITH CURL;Ll;0;L;;;;;N;;;;; +2C75;LATIN CAPITAL LETTER HALF H;Lu;0;L;;;;;N;;;;2C76; +2C76;LATIN SMALL LETTER HALF H;Ll;0;L;;;;;N;;;2C75;;2C75 +2C77;LATIN SMALL LETTER TAILLESS PHI;Ll;0;L;;;;;N;;;;; +2C78;LATIN SMALL LETTER E WITH NOTCH;Ll;0;L;;;;;N;;;;; +2C79;LATIN SMALL LETTER TURNED R WITH TAIL;Ll;0;L;;;;;N;;;;; +2C7A;LATIN SMALL LETTER O WITH LOW RING INSIDE;Ll;0;L;;;;;N;;;;; +2C7B;LATIN LETTER SMALL CAPITAL TURNED E;Ll;0;L;;;;;N;;;;; +2C7C;LATIN SUBSCRIPT SMALL LETTER J;Ll;0;L;<sub> 006A;;;;N;;;;; +2C7D;MODIFIER LETTER CAPITAL V;Lm;0;L;<super> 0056;;;;N;;;;; +2C80;COPTIC CAPITAL LETTER ALFA;Lu;0;L;;;;;N;;;;2C81; +2C81;COPTIC SMALL LETTER ALFA;Ll;0;L;;;;;N;;;2C80;;2C80 +2C82;COPTIC CAPITAL LETTER VIDA;Lu;0;L;;;;;N;;;;2C83; +2C83;COPTIC SMALL LETTER VIDA;Ll;0;L;;;;;N;;;2C82;;2C82 +2C84;COPTIC CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;2C85; +2C85;COPTIC SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;2C84;;2C84 +2C86;COPTIC CAPITAL LETTER DALDA;Lu;0;L;;;;;N;;;;2C87; +2C87;COPTIC SMALL LETTER DALDA;Ll;0;L;;;;;N;;;2C86;;2C86 +2C88;COPTIC CAPITAL LETTER EIE;Lu;0;L;;;;;N;;;;2C89; +2C89;COPTIC SMALL LETTER EIE;Ll;0;L;;;;;N;;;2C88;;2C88 +2C8A;COPTIC CAPITAL LETTER SOU;Lu;0;L;;;;;N;;;;2C8B; +2C8B;COPTIC SMALL LETTER SOU;Ll;0;L;;;;;N;;;2C8A;;2C8A +2C8C;COPTIC CAPITAL LETTER ZATA;Lu;0;L;;;;;N;;;;2C8D; +2C8D;COPTIC SMALL LETTER ZATA;Ll;0;L;;;;;N;;;2C8C;;2C8C +2C8E;COPTIC CAPITAL LETTER HATE;Lu;0;L;;;;;N;;;;2C8F; +2C8F;COPTIC SMALL LETTER HATE;Ll;0;L;;;;;N;;;2C8E;;2C8E +2C90;COPTIC CAPITAL LETTER THETHE;Lu;0;L;;;;;N;;;;2C91; +2C91;COPTIC SMALL LETTER THETHE;Ll;0;L;;;;;N;;;2C90;;2C90 +2C92;COPTIC CAPITAL LETTER IAUDA;Lu;0;L;;;;;N;;;;2C93; +2C93;COPTIC SMALL LETTER IAUDA;Ll;0;L;;;;;N;;;2C92;;2C92 +2C94;COPTIC CAPITAL LETTER KAPA;Lu;0;L;;;;;N;;;;2C95; +2C95;COPTIC SMALL LETTER KAPA;Ll;0;L;;;;;N;;;2C94;;2C94 +2C96;COPTIC CAPITAL LETTER LAULA;Lu;0;L;;;;;N;;;;2C97; +2C97;COPTIC SMALL LETTER LAULA;Ll;0;L;;;;;N;;;2C96;;2C96 +2C98;COPTIC CAPITAL LETTER MI;Lu;0;L;;;;;N;;;;2C99; +2C99;COPTIC SMALL LETTER MI;Ll;0;L;;;;;N;;;2C98;;2C98 +2C9A;COPTIC CAPITAL LETTER NI;Lu;0;L;;;;;N;;;;2C9B; +2C9B;COPTIC SMALL LETTER NI;Ll;0;L;;;;;N;;;2C9A;;2C9A +2C9C;COPTIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;2C9D; +2C9D;COPTIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;2C9C;;2C9C +2C9E;COPTIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;2C9F; +2C9F;COPTIC SMALL LETTER O;Ll;0;L;;;;;N;;;2C9E;;2C9E +2CA0;COPTIC CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;2CA1; +2CA1;COPTIC SMALL LETTER PI;Ll;0;L;;;;;N;;;2CA0;;2CA0 +2CA2;COPTIC CAPITAL LETTER RO;Lu;0;L;;;;;N;;;;2CA3; +2CA3;COPTIC SMALL LETTER RO;Ll;0;L;;;;;N;;;2CA2;;2CA2 +2CA4;COPTIC CAPITAL LETTER SIMA;Lu;0;L;;;;;N;;;;2CA5; +2CA5;COPTIC SMALL LETTER SIMA;Ll;0;L;;;;;N;;;2CA4;;2CA4 +2CA6;COPTIC CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;2CA7; +2CA7;COPTIC SMALL LETTER TAU;Ll;0;L;;;;;N;;;2CA6;;2CA6 +2CA8;COPTIC CAPITAL LETTER UA;Lu;0;L;;;;;N;;;;2CA9; +2CA9;COPTIC SMALL LETTER UA;Ll;0;L;;;;;N;;;2CA8;;2CA8 +2CAA;COPTIC CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;2CAB; +2CAB;COPTIC SMALL LETTER FI;Ll;0;L;;;;;N;;;2CAA;;2CAA +2CAC;COPTIC CAPITAL LETTER KHI;Lu;0;L;;;;;N;;;;2CAD; +2CAD;COPTIC SMALL LETTER KHI;Ll;0;L;;;;;N;;;2CAC;;2CAC +2CAE;COPTIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;2CAF; +2CAF;COPTIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;2CAE;;2CAE +2CB0;COPTIC CAPITAL LETTER OOU;Lu;0;L;;;;;N;;;;2CB1; +2CB1;COPTIC SMALL LETTER OOU;Ll;0;L;;;;;N;;;2CB0;;2CB0 +2CB2;COPTIC CAPITAL LETTER DIALECT-P ALEF;Lu;0;L;;;;;N;;;;2CB3; +2CB3;COPTIC SMALL LETTER DIALECT-P ALEF;Ll;0;L;;;;;N;;;2CB2;;2CB2 +2CB4;COPTIC CAPITAL LETTER OLD COPTIC AIN;Lu;0;L;;;;;N;;;;2CB5; +2CB5;COPTIC SMALL LETTER OLD COPTIC AIN;Ll;0;L;;;;;N;;;2CB4;;2CB4 +2CB6;COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE;Lu;0;L;;;;;N;;;;2CB7; +2CB7;COPTIC SMALL LETTER CRYPTOGRAMMIC EIE;Ll;0;L;;;;;N;;;2CB6;;2CB6 +2CB8;COPTIC CAPITAL LETTER DIALECT-P KAPA;Lu;0;L;;;;;N;;;;2CB9; +2CB9;COPTIC SMALL LETTER DIALECT-P KAPA;Ll;0;L;;;;;N;;;2CB8;;2CB8 +2CBA;COPTIC CAPITAL LETTER DIALECT-P NI;Lu;0;L;;;;;N;;;;2CBB; +2CBB;COPTIC SMALL LETTER DIALECT-P NI;Ll;0;L;;;;;N;;;2CBA;;2CBA +2CBC;COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI;Lu;0;L;;;;;N;;;;2CBD; +2CBD;COPTIC SMALL LETTER CRYPTOGRAMMIC NI;Ll;0;L;;;;;N;;;2CBC;;2CBC +2CBE;COPTIC CAPITAL LETTER OLD COPTIC OOU;Lu;0;L;;;;;N;;;;2CBF; +2CBF;COPTIC SMALL LETTER OLD COPTIC OOU;Ll;0;L;;;;;N;;;2CBE;;2CBE +2CC0;COPTIC CAPITAL LETTER SAMPI;Lu;0;L;;;;;N;;;;2CC1; +2CC1;COPTIC SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;2CC0;;2CC0 +2CC2;COPTIC CAPITAL LETTER CROSSED SHEI;Lu;0;L;;;;;N;;;;2CC3; +2CC3;COPTIC SMALL LETTER CROSSED SHEI;Ll;0;L;;;;;N;;;2CC2;;2CC2 +2CC4;COPTIC CAPITAL LETTER OLD COPTIC SHEI;Lu;0;L;;;;;N;;;;2CC5; +2CC5;COPTIC SMALL LETTER OLD COPTIC SHEI;Ll;0;L;;;;;N;;;2CC4;;2CC4 +2CC6;COPTIC CAPITAL LETTER OLD COPTIC ESH;Lu;0;L;;;;;N;;;;2CC7; +2CC7;COPTIC SMALL LETTER OLD COPTIC ESH;Ll;0;L;;;;;N;;;2CC6;;2CC6 +2CC8;COPTIC CAPITAL LETTER AKHMIMIC KHEI;Lu;0;L;;;;;N;;;;2CC9; +2CC9;COPTIC SMALL LETTER AKHMIMIC KHEI;Ll;0;L;;;;;N;;;2CC8;;2CC8 +2CCA;COPTIC CAPITAL LETTER DIALECT-P HORI;Lu;0;L;;;;;N;;;;2CCB; +2CCB;COPTIC SMALL LETTER DIALECT-P HORI;Ll;0;L;;;;;N;;;2CCA;;2CCA +2CCC;COPTIC CAPITAL LETTER OLD COPTIC HORI;Lu;0;L;;;;;N;;;;2CCD; +2CCD;COPTIC SMALL LETTER OLD COPTIC HORI;Ll;0;L;;;;;N;;;2CCC;;2CCC +2CCE;COPTIC CAPITAL LETTER OLD COPTIC HA;Lu;0;L;;;;;N;;;;2CCF; +2CCF;COPTIC SMALL LETTER OLD COPTIC HA;Ll;0;L;;;;;N;;;2CCE;;2CCE +2CD0;COPTIC CAPITAL LETTER L-SHAPED HA;Lu;0;L;;;;;N;;;;2CD1; +2CD1;COPTIC SMALL LETTER L-SHAPED HA;Ll;0;L;;;;;N;;;2CD0;;2CD0 +2CD2;COPTIC CAPITAL LETTER OLD COPTIC HEI;Lu;0;L;;;;;N;;;;2CD3; +2CD3;COPTIC SMALL LETTER OLD COPTIC HEI;Ll;0;L;;;;;N;;;2CD2;;2CD2 +2CD4;COPTIC CAPITAL LETTER OLD COPTIC HAT;Lu;0;L;;;;;N;;;;2CD5; +2CD5;COPTIC SMALL LETTER OLD COPTIC HAT;Ll;0;L;;;;;N;;;2CD4;;2CD4 +2CD6;COPTIC CAPITAL LETTER OLD COPTIC GANGIA;Lu;0;L;;;;;N;;;;2CD7; +2CD7;COPTIC SMALL LETTER OLD COPTIC GANGIA;Ll;0;L;;;;;N;;;2CD6;;2CD6 +2CD8;COPTIC CAPITAL LETTER OLD COPTIC DJA;Lu;0;L;;;;;N;;;;2CD9; +2CD9;COPTIC SMALL LETTER OLD COPTIC DJA;Ll;0;L;;;;;N;;;2CD8;;2CD8 +2CDA;COPTIC CAPITAL LETTER OLD COPTIC SHIMA;Lu;0;L;;;;;N;;;;2CDB; +2CDB;COPTIC SMALL LETTER OLD COPTIC SHIMA;Ll;0;L;;;;;N;;;2CDA;;2CDA +2CDC;COPTIC CAPITAL LETTER OLD NUBIAN SHIMA;Lu;0;L;;;;;N;;;;2CDD; +2CDD;COPTIC SMALL LETTER OLD NUBIAN SHIMA;Ll;0;L;;;;;N;;;2CDC;;2CDC +2CDE;COPTIC CAPITAL LETTER OLD NUBIAN NGI;Lu;0;L;;;;;N;;;;2CDF; +2CDF;COPTIC SMALL LETTER OLD NUBIAN NGI;Ll;0;L;;;;;N;;;2CDE;;2CDE +2CE0;COPTIC CAPITAL LETTER OLD NUBIAN NYI;Lu;0;L;;;;;N;;;;2CE1; +2CE1;COPTIC SMALL LETTER OLD NUBIAN NYI;Ll;0;L;;;;;N;;;2CE0;;2CE0 +2CE2;COPTIC CAPITAL LETTER OLD NUBIAN WAU;Lu;0;L;;;;;N;;;;2CE3; +2CE3;COPTIC SMALL LETTER OLD NUBIAN WAU;Ll;0;L;;;;;N;;;2CE2;;2CE2 +2CE4;COPTIC SYMBOL KAI;Ll;0;L;;;;;N;;;;; +2CE5;COPTIC SYMBOL MI RO;So;0;ON;;;;;N;;;;; +2CE6;COPTIC SYMBOL PI RO;So;0;ON;;;;;N;;;;; +2CE7;COPTIC SYMBOL STAUROS;So;0;ON;;;;;N;;;;; +2CE8;COPTIC SYMBOL TAU RO;So;0;ON;;;;;N;;;;; +2CE9;COPTIC SYMBOL KHI RO;So;0;ON;;;;;N;;;;; +2CEA;COPTIC SYMBOL SHIMA SIMA;So;0;ON;;;;;N;;;;; +2CF9;COPTIC OLD NUBIAN FULL STOP;Po;0;ON;;;;;N;;;;; +2CFA;COPTIC OLD NUBIAN DIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;; +2CFB;COPTIC OLD NUBIAN INDIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;; +2CFC;COPTIC OLD NUBIAN VERSE DIVIDER;Po;0;ON;;;;;N;;;;; +2CFD;COPTIC FRACTION ONE HALF;No;0;ON;;;;1/2;N;;;;; +2CFE;COPTIC FULL STOP;Po;0;ON;;;;;N;;;;; +2CFF;COPTIC MORPHOLOGICAL DIVIDER;Po;0;ON;;;;;N;;;;; +2D00;GEORGIAN SMALL LETTER AN;Ll;0;L;;;;;N;;Khutsuri;10A0;;10A0 +2D01;GEORGIAN SMALL LETTER BAN;Ll;0;L;;;;;N;;Khutsuri;10A1;;10A1 +2D02;GEORGIAN SMALL LETTER GAN;Ll;0;L;;;;;N;;Khutsuri;10A2;;10A2 +2D03;GEORGIAN SMALL LETTER DON;Ll;0;L;;;;;N;;Khutsuri;10A3;;10A3 +2D04;GEORGIAN SMALL LETTER EN;Ll;0;L;;;;;N;;Khutsuri;10A4;;10A4 +2D05;GEORGIAN SMALL LETTER VIN;Ll;0;L;;;;;N;;Khutsuri;10A5;;10A5 +2D06;GEORGIAN SMALL LETTER ZEN;Ll;0;L;;;;;N;;Khutsuri;10A6;;10A6 +2D07;GEORGIAN SMALL LETTER TAN;Ll;0;L;;;;;N;;Khutsuri;10A7;;10A7 +2D08;GEORGIAN SMALL LETTER IN;Ll;0;L;;;;;N;;Khutsuri;10A8;;10A8 +2D09;GEORGIAN SMALL LETTER KAN;Ll;0;L;;;;;N;;Khutsuri;10A9;;10A9 +2D0A;GEORGIAN SMALL LETTER LAS;Ll;0;L;;;;;N;;Khutsuri;10AA;;10AA +2D0B;GEORGIAN SMALL LETTER MAN;Ll;0;L;;;;;N;;Khutsuri;10AB;;10AB +2D0C;GEORGIAN SMALL LETTER NAR;Ll;0;L;;;;;N;;Khutsuri;10AC;;10AC +2D0D;GEORGIAN SMALL LETTER ON;Ll;0;L;;;;;N;;Khutsuri;10AD;;10AD +2D0E;GEORGIAN SMALL LETTER PAR;Ll;0;L;;;;;N;;Khutsuri;10AE;;10AE +2D0F;GEORGIAN SMALL LETTER ZHAR;Ll;0;L;;;;;N;;Khutsuri;10AF;;10AF +2D10;GEORGIAN SMALL LETTER RAE;Ll;0;L;;;;;N;;Khutsuri;10B0;;10B0 +2D11;GEORGIAN SMALL LETTER SAN;Ll;0;L;;;;;N;;Khutsuri;10B1;;10B1 +2D12;GEORGIAN SMALL LETTER TAR;Ll;0;L;;;;;N;;Khutsuri;10B2;;10B2 +2D13;GEORGIAN SMALL LETTER UN;Ll;0;L;;;;;N;;Khutsuri;10B3;;10B3 +2D14;GEORGIAN SMALL LETTER PHAR;Ll;0;L;;;;;N;;Khutsuri;10B4;;10B4 +2D15;GEORGIAN SMALL LETTER KHAR;Ll;0;L;;;;;N;;Khutsuri;10B5;;10B5 +2D16;GEORGIAN SMALL LETTER GHAN;Ll;0;L;;;;;N;;Khutsuri;10B6;;10B6 +2D17;GEORGIAN SMALL LETTER QAR;Ll;0;L;;;;;N;;Khutsuri;10B7;;10B7 +2D18;GEORGIAN SMALL LETTER SHIN;Ll;0;L;;;;;N;;Khutsuri;10B8;;10B8 +2D19;GEORGIAN SMALL LETTER CHIN;Ll;0;L;;;;;N;;Khutsuri;10B9;;10B9 +2D1A;GEORGIAN SMALL LETTER CAN;Ll;0;L;;;;;N;;Khutsuri;10BA;;10BA +2D1B;GEORGIAN SMALL LETTER JIL;Ll;0;L;;;;;N;;Khutsuri;10BB;;10BB +2D1C;GEORGIAN SMALL LETTER CIL;Ll;0;L;;;;;N;;Khutsuri;10BC;;10BC +2D1D;GEORGIAN SMALL LETTER CHAR;Ll;0;L;;;;;N;;Khutsuri;10BD;;10BD +2D1E;GEORGIAN SMALL LETTER XAN;Ll;0;L;;;;;N;;Khutsuri;10BE;;10BE +2D1F;GEORGIAN SMALL LETTER JHAN;Ll;0;L;;;;;N;;Khutsuri;10BF;;10BF +2D20;GEORGIAN SMALL LETTER HAE;Ll;0;L;;;;;N;;Khutsuri;10C0;;10C0 +2D21;GEORGIAN SMALL LETTER HE;Ll;0;L;;;;;N;;Khutsuri;10C1;;10C1 +2D22;GEORGIAN SMALL LETTER HIE;Ll;0;L;;;;;N;;Khutsuri;10C2;;10C2 +2D23;GEORGIAN SMALL LETTER WE;Ll;0;L;;;;;N;;Khutsuri;10C3;;10C3 +2D24;GEORGIAN SMALL LETTER HAR;Ll;0;L;;;;;N;;Khutsuri;10C4;;10C4 +2D25;GEORGIAN SMALL LETTER HOE;Ll;0;L;;;;;N;;Khutsuri;10C5;;10C5 +2D30;TIFINAGH LETTER YA;Lo;0;L;;;;;N;;;;; +2D31;TIFINAGH LETTER YAB;Lo;0;L;;;;;N;;;;; +2D32;TIFINAGH LETTER YABH;Lo;0;L;;;;;N;;;;; +2D33;TIFINAGH LETTER YAG;Lo;0;L;;;;;N;;;;; +2D34;TIFINAGH LETTER YAGHH;Lo;0;L;;;;;N;;;;; +2D35;TIFINAGH LETTER BERBER ACADEMY YAJ;Lo;0;L;;;;;N;;;;; +2D36;TIFINAGH LETTER YAJ;Lo;0;L;;;;;N;;;;; +2D37;TIFINAGH LETTER YAD;Lo;0;L;;;;;N;;;;; +2D38;TIFINAGH LETTER YADH;Lo;0;L;;;;;N;;;;; +2D39;TIFINAGH LETTER YADD;Lo;0;L;;;;;N;;;;; +2D3A;TIFINAGH LETTER YADDH;Lo;0;L;;;;;N;;;;; +2D3B;TIFINAGH LETTER YEY;Lo;0;L;;;;;N;;;;; +2D3C;TIFINAGH LETTER YAF;Lo;0;L;;;;;N;;;;; +2D3D;TIFINAGH LETTER YAK;Lo;0;L;;;;;N;;;;; +2D3E;TIFINAGH LETTER TUAREG YAK;Lo;0;L;;;;;N;;;;; +2D3F;TIFINAGH LETTER YAKHH;Lo;0;L;;;;;N;;;;; +2D40;TIFINAGH LETTER YAH;Lo;0;L;;;;;N;;Tuareg yab;;; +2D41;TIFINAGH LETTER BERBER ACADEMY YAH;Lo;0;L;;;;;N;;;;; +2D42;TIFINAGH LETTER TUAREG YAH;Lo;0;L;;;;;N;;;;; +2D43;TIFINAGH LETTER YAHH;Lo;0;L;;;;;N;;;;; +2D44;TIFINAGH LETTER YAA;Lo;0;L;;;;;N;;;;; +2D45;TIFINAGH LETTER YAKH;Lo;0;L;;;;;N;;;;; +2D46;TIFINAGH LETTER TUAREG YAKH;Lo;0;L;;;;;N;;;;; +2D47;TIFINAGH LETTER YAQ;Lo;0;L;;;;;N;;;;; +2D48;TIFINAGH LETTER TUAREG YAQ;Lo;0;L;;;;;N;;;;; +2D49;TIFINAGH LETTER YI;Lo;0;L;;;;;N;;;;; +2D4A;TIFINAGH LETTER YAZH;Lo;0;L;;;;;N;;;;; +2D4B;TIFINAGH LETTER AHAGGAR YAZH;Lo;0;L;;;;;N;;;;; +2D4C;TIFINAGH LETTER TUAREG YAZH;Lo;0;L;;;;;N;;;;; +2D4D;TIFINAGH LETTER YAL;Lo;0;L;;;;;N;;;;; +2D4E;TIFINAGH LETTER YAM;Lo;0;L;;;;;N;;;;; +2D4F;TIFINAGH LETTER YAN;Lo;0;L;;;;;N;;;;; +2D50;TIFINAGH LETTER TUAREG YAGN;Lo;0;L;;;;;N;;;;; +2D51;TIFINAGH LETTER TUAREG YANG;Lo;0;L;;;;;N;;;;; +2D52;TIFINAGH LETTER YAP;Lo;0;L;;;;;N;;;;; +2D53;TIFINAGH LETTER YU;Lo;0;L;;;;;N;;Tuareg yaw;;; +2D54;TIFINAGH LETTER YAR;Lo;0;L;;;;;N;;;;; +2D55;TIFINAGH LETTER YARR;Lo;0;L;;;;;N;;;;; +2D56;TIFINAGH LETTER YAGH;Lo;0;L;;;;;N;;;;; +2D57;TIFINAGH LETTER TUAREG YAGH;Lo;0;L;;;;;N;;;;; +2D58;TIFINAGH LETTER AYER YAGH;Lo;0;L;;;;;N;;Adrar yaj;;; +2D59;TIFINAGH LETTER YAS;Lo;0;L;;;;;N;;;;; +2D5A;TIFINAGH LETTER YASS;Lo;0;L;;;;;N;;;;; +2D5B;TIFINAGH LETTER YASH;Lo;0;L;;;;;N;;;;; +2D5C;TIFINAGH LETTER YAT;Lo;0;L;;;;;N;;;;; +2D5D;TIFINAGH LETTER YATH;Lo;0;L;;;;;N;;;;; +2D5E;TIFINAGH LETTER YACH;Lo;0;L;;;;;N;;;;; +2D5F;TIFINAGH LETTER YATT;Lo;0;L;;;;;N;;;;; +2D60;TIFINAGH LETTER YAV;Lo;0;L;;;;;N;;;;; +2D61;TIFINAGH LETTER YAW;Lo;0;L;;;;;N;;;;; +2D62;TIFINAGH LETTER YAY;Lo;0;L;;;;;N;;;;; +2D63;TIFINAGH LETTER YAZ;Lo;0;L;;;;;N;;;;; +2D64;TIFINAGH LETTER TAWELLEMET YAZ;Lo;0;L;;;;;N;;harpoon yaz;;; +2D65;TIFINAGH LETTER YAZZ;Lo;0;L;;;;;N;;;;; +2D6F;TIFINAGH MODIFIER LETTER LABIALIZATION MARK;Lm;0;L;<super> 2D61;;;;N;;tamatart;;; +2D80;ETHIOPIC SYLLABLE LOA;Lo;0;L;;;;;N;;;;; +2D81;ETHIOPIC SYLLABLE MOA;Lo;0;L;;;;;N;;;;; +2D82;ETHIOPIC SYLLABLE ROA;Lo;0;L;;;;;N;;;;; +2D83;ETHIOPIC SYLLABLE SOA;Lo;0;L;;;;;N;;;;; +2D84;ETHIOPIC SYLLABLE SHOA;Lo;0;L;;;;;N;;;;; +2D85;ETHIOPIC SYLLABLE BOA;Lo;0;L;;;;;N;;;;; +2D86;ETHIOPIC SYLLABLE TOA;Lo;0;L;;;;;N;;;;; +2D87;ETHIOPIC SYLLABLE COA;Lo;0;L;;;;;N;;;;; +2D88;ETHIOPIC SYLLABLE NOA;Lo;0;L;;;;;N;;;;; +2D89;ETHIOPIC SYLLABLE NYOA;Lo;0;L;;;;;N;;;;; +2D8A;ETHIOPIC SYLLABLE GLOTTAL OA;Lo;0;L;;;;;N;;;;; +2D8B;ETHIOPIC SYLLABLE ZOA;Lo;0;L;;;;;N;;;;; +2D8C;ETHIOPIC SYLLABLE DOA;Lo;0;L;;;;;N;;;;; +2D8D;ETHIOPIC SYLLABLE DDOA;Lo;0;L;;;;;N;;;;; +2D8E;ETHIOPIC SYLLABLE JOA;Lo;0;L;;;;;N;;;;; +2D8F;ETHIOPIC SYLLABLE THOA;Lo;0;L;;;;;N;;;;; +2D90;ETHIOPIC SYLLABLE CHOA;Lo;0;L;;;;;N;;;;; +2D91;ETHIOPIC SYLLABLE PHOA;Lo;0;L;;;;;N;;;;; +2D92;ETHIOPIC SYLLABLE POA;Lo;0;L;;;;;N;;;;; +2D93;ETHIOPIC SYLLABLE GGWA;Lo;0;L;;;;;N;;;;; +2D94;ETHIOPIC SYLLABLE GGWI;Lo;0;L;;;;;N;;;;; +2D95;ETHIOPIC SYLLABLE GGWEE;Lo;0;L;;;;;N;;;;; +2D96;ETHIOPIC SYLLABLE GGWE;Lo;0;L;;;;;N;;;;; +2DA0;ETHIOPIC SYLLABLE SSA;Lo;0;L;;;;;N;;;;; +2DA1;ETHIOPIC SYLLABLE SSU;Lo;0;L;;;;;N;;;;; +2DA2;ETHIOPIC SYLLABLE SSI;Lo;0;L;;;;;N;;;;; +2DA3;ETHIOPIC SYLLABLE SSAA;Lo;0;L;;;;;N;;;;; +2DA4;ETHIOPIC SYLLABLE SSEE;Lo;0;L;;;;;N;;;;; +2DA5;ETHIOPIC SYLLABLE SSE;Lo;0;L;;;;;N;;;;; +2DA6;ETHIOPIC SYLLABLE SSO;Lo;0;L;;;;;N;;;;; +2DA8;ETHIOPIC SYLLABLE CCA;Lo;0;L;;;;;N;;;;; +2DA9;ETHIOPIC SYLLABLE CCU;Lo;0;L;;;;;N;;;;; +2DAA;ETHIOPIC SYLLABLE CCI;Lo;0;L;;;;;N;;;;; +2DAB;ETHIOPIC SYLLABLE CCAA;Lo;0;L;;;;;N;;;;; +2DAC;ETHIOPIC SYLLABLE CCEE;Lo;0;L;;;;;N;;;;; +2DAD;ETHIOPIC SYLLABLE CCE;Lo;0;L;;;;;N;;;;; +2DAE;ETHIOPIC SYLLABLE CCO;Lo;0;L;;;;;N;;;;; +2DB0;ETHIOPIC SYLLABLE ZZA;Lo;0;L;;;;;N;;;;; +2DB1;ETHIOPIC SYLLABLE ZZU;Lo;0;L;;;;;N;;;;; +2DB2;ETHIOPIC SYLLABLE ZZI;Lo;0;L;;;;;N;;;;; +2DB3;ETHIOPIC SYLLABLE ZZAA;Lo;0;L;;;;;N;;;;; +2DB4;ETHIOPIC SYLLABLE ZZEE;Lo;0;L;;;;;N;;;;; +2DB5;ETHIOPIC SYLLABLE ZZE;Lo;0;L;;;;;N;;;;; +2DB6;ETHIOPIC SYLLABLE ZZO;Lo;0;L;;;;;N;;;;; +2DB8;ETHIOPIC SYLLABLE CCHA;Lo;0;L;;;;;N;;;;; +2DB9;ETHIOPIC SYLLABLE CCHU;Lo;0;L;;;;;N;;;;; +2DBA;ETHIOPIC SYLLABLE CCHI;Lo;0;L;;;;;N;;;;; +2DBB;ETHIOPIC SYLLABLE CCHAA;Lo;0;L;;;;;N;;;;; +2DBC;ETHIOPIC SYLLABLE CCHEE;Lo;0;L;;;;;N;;;;; +2DBD;ETHIOPIC SYLLABLE CCHE;Lo;0;L;;;;;N;;;;; +2DBE;ETHIOPIC SYLLABLE CCHO;Lo;0;L;;;;;N;;;;; +2DC0;ETHIOPIC SYLLABLE QYA;Lo;0;L;;;;;N;;;;; +2DC1;ETHIOPIC SYLLABLE QYU;Lo;0;L;;;;;N;;;;; +2DC2;ETHIOPIC SYLLABLE QYI;Lo;0;L;;;;;N;;;;; +2DC3;ETHIOPIC SYLLABLE QYAA;Lo;0;L;;;;;N;;;;; +2DC4;ETHIOPIC SYLLABLE QYEE;Lo;0;L;;;;;N;;;;; +2DC5;ETHIOPIC SYLLABLE QYE;Lo;0;L;;;;;N;;;;; +2DC6;ETHIOPIC SYLLABLE QYO;Lo;0;L;;;;;N;;;;; +2DC8;ETHIOPIC SYLLABLE KYA;Lo;0;L;;;;;N;;;;; +2DC9;ETHIOPIC SYLLABLE KYU;Lo;0;L;;;;;N;;;;; +2DCA;ETHIOPIC SYLLABLE KYI;Lo;0;L;;;;;N;;;;; +2DCB;ETHIOPIC SYLLABLE KYAA;Lo;0;L;;;;;N;;;;; +2DCC;ETHIOPIC SYLLABLE KYEE;Lo;0;L;;;;;N;;;;; +2DCD;ETHIOPIC SYLLABLE KYE;Lo;0;L;;;;;N;;;;; +2DCE;ETHIOPIC SYLLABLE KYO;Lo;0;L;;;;;N;;;;; +2DD0;ETHIOPIC SYLLABLE XYA;Lo;0;L;;;;;N;;;;; +2DD1;ETHIOPIC SYLLABLE XYU;Lo;0;L;;;;;N;;;;; +2DD2;ETHIOPIC SYLLABLE XYI;Lo;0;L;;;;;N;;;;; +2DD3;ETHIOPIC SYLLABLE XYAA;Lo;0;L;;;;;N;;;;; +2DD4;ETHIOPIC SYLLABLE XYEE;Lo;0;L;;;;;N;;;;; +2DD5;ETHIOPIC SYLLABLE XYE;Lo;0;L;;;;;N;;;;; +2DD6;ETHIOPIC SYLLABLE XYO;Lo;0;L;;;;;N;;;;; +2DD8;ETHIOPIC SYLLABLE GYA;Lo;0;L;;;;;N;;;;; +2DD9;ETHIOPIC SYLLABLE GYU;Lo;0;L;;;;;N;;;;; +2DDA;ETHIOPIC SYLLABLE GYI;Lo;0;L;;;;;N;;;;; +2DDB;ETHIOPIC SYLLABLE GYAA;Lo;0;L;;;;;N;;;;; +2DDC;ETHIOPIC SYLLABLE GYEE;Lo;0;L;;;;;N;;;;; +2DDD;ETHIOPIC SYLLABLE GYE;Lo;0;L;;;;;N;;;;; +2DDE;ETHIOPIC SYLLABLE GYO;Lo;0;L;;;;;N;;;;; +2DE0;COMBINING CYRILLIC LETTER BE;Mn;230;NSM;;;;;N;;;;; +2DE1;COMBINING CYRILLIC LETTER VE;Mn;230;NSM;;;;;N;;;;; +2DE2;COMBINING CYRILLIC LETTER GHE;Mn;230;NSM;;;;;N;;;;; +2DE3;COMBINING CYRILLIC LETTER DE;Mn;230;NSM;;;;;N;;;;; +2DE4;COMBINING CYRILLIC LETTER ZHE;Mn;230;NSM;;;;;N;;;;; +2DE5;COMBINING CYRILLIC LETTER ZE;Mn;230;NSM;;;;;N;;;;; +2DE6;COMBINING CYRILLIC LETTER KA;Mn;230;NSM;;;;;N;;;;; +2DE7;COMBINING CYRILLIC LETTER EL;Mn;230;NSM;;;;;N;;;;; +2DE8;COMBINING CYRILLIC LETTER EM;Mn;230;NSM;;;;;N;;;;; +2DE9;COMBINING CYRILLIC LETTER EN;Mn;230;NSM;;;;;N;;;;; +2DEA;COMBINING CYRILLIC LETTER O;Mn;230;NSM;;;;;N;;;;; +2DEB;COMBINING CYRILLIC LETTER PE;Mn;230;NSM;;;;;N;;;;; +2DEC;COMBINING CYRILLIC LETTER ER;Mn;230;NSM;;;;;N;;;;; +2DED;COMBINING CYRILLIC LETTER ES;Mn;230;NSM;;;;;N;;;;; +2DEE;COMBINING CYRILLIC LETTER TE;Mn;230;NSM;;;;;N;;;;; +2DEF;COMBINING CYRILLIC LETTER HA;Mn;230;NSM;;;;;N;;;;; +2DF0;COMBINING CYRILLIC LETTER TSE;Mn;230;NSM;;;;;N;;;;; +2DF1;COMBINING CYRILLIC LETTER CHE;Mn;230;NSM;;;;;N;;;;; +2DF2;COMBINING CYRILLIC LETTER SHA;Mn;230;NSM;;;;;N;;;;; +2DF3;COMBINING CYRILLIC LETTER SHCHA;Mn;230;NSM;;;;;N;;;;; +2DF4;COMBINING CYRILLIC LETTER FITA;Mn;230;NSM;;;;;N;;;;; +2DF5;COMBINING CYRILLIC LETTER ES-TE;Mn;230;NSM;;;;;N;;;;; +2DF6;COMBINING CYRILLIC LETTER A;Mn;230;NSM;;;;;N;;;;; +2DF7;COMBINING CYRILLIC LETTER IE;Mn;230;NSM;;;;;N;;;;; +2DF8;COMBINING CYRILLIC LETTER DJERV;Mn;230;NSM;;;;;N;;;;; +2DF9;COMBINING CYRILLIC LETTER MONOGRAPH UK;Mn;230;NSM;;;;;N;;;;; +2DFA;COMBINING CYRILLIC LETTER YAT;Mn;230;NSM;;;;;N;;;;; +2DFB;COMBINING CYRILLIC LETTER YU;Mn;230;NSM;;;;;N;;;;; +2DFC;COMBINING CYRILLIC LETTER IOTIFIED A;Mn;230;NSM;;;;;N;;;;; +2DFD;COMBINING CYRILLIC LETTER LITTLE YUS;Mn;230;NSM;;;;;N;;;;; +2DFE;COMBINING CYRILLIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;; +2DFF;COMBINING CYRILLIC LETTER IOTIFIED BIG YUS;Mn;230;NSM;;;;;N;;;;; +2E00;RIGHT ANGLE SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;; +2E01;RIGHT ANGLE DOTTED SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;; +2E02;LEFT SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;; +2E03;RIGHT SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;; +2E04;LEFT DOTTED SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;; +2E05;RIGHT DOTTED SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;; +2E06;RAISED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;; +2E07;RAISED DOTTED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;; +2E08;DOTTED TRANSPOSITION MARKER;Po;0;ON;;;;;N;;;;; +2E09;LEFT TRANSPOSITION BRACKET;Pi;0;ON;;;;;Y;;;;; +2E0A;RIGHT TRANSPOSITION BRACKET;Pf;0;ON;;;;;Y;;;;; +2E0B;RAISED SQUARE;Po;0;ON;;;;;N;;;;; +2E0C;LEFT RAISED OMISSION BRACKET;Pi;0;ON;;;;;Y;;;;; +2E0D;RIGHT RAISED OMISSION BRACKET;Pf;0;ON;;;;;Y;;;;; +2E0E;EDITORIAL CORONIS;Po;0;ON;;;;;N;;;;; +2E0F;PARAGRAPHOS;Po;0;ON;;;;;N;;;;; +2E10;FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;; +2E11;REVERSED FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;; +2E12;HYPODIASTOLE;Po;0;ON;;;;;N;;;;; +2E13;DOTTED OBELOS;Po;0;ON;;;;;N;;;;; +2E14;DOWNWARDS ANCORA;Po;0;ON;;;;;N;;;;; +2E15;UPWARDS ANCORA;Po;0;ON;;;;;N;;;;; +2E16;DOTTED RIGHT-POINTING ANGLE;Po;0;ON;;;;;N;;;;; +2E17;DOUBLE OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;; +2E18;INVERTED INTERROBANG;Po;0;ON;;;;;N;;;;; +2E19;PALM BRANCH;Po;0;ON;;;;;N;;;;; +2E1A;HYPHEN WITH DIAERESIS;Pd;0;ON;;;;;N;;;;; +2E1B;TILDE WITH RING ABOVE;Po;0;ON;;;;;N;;;;; +2E1C;LEFT LOW PARAPHRASE BRACKET;Pi;0;ON;;;;;Y;;;;; +2E1D;RIGHT LOW PARAPHRASE BRACKET;Pf;0;ON;;;;;Y;;;;; +2E1E;TILDE WITH DOT ABOVE;Po;0;ON;;;;;N;;;;; +2E1F;TILDE WITH DOT BELOW;Po;0;ON;;;;;N;;;;; +2E20;LEFT VERTICAL BAR WITH QUILL;Pi;0;ON;;;;;Y;;;;; +2E21;RIGHT VERTICAL BAR WITH QUILL;Pf;0;ON;;;;;Y;;;;; +2E22;TOP LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;; +2E23;TOP RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;; +2E24;BOTTOM LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;; +2E25;BOTTOM RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;; +2E26;LEFT SIDEWAYS U BRACKET;Ps;0;ON;;;;;Y;;;;; +2E27;RIGHT SIDEWAYS U BRACKET;Pe;0;ON;;;;;Y;;;;; +2E28;LEFT DOUBLE PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +2E29;RIGHT DOUBLE PARENTHESIS;Pe;0;ON;;;;;Y;;;;; +2E2A;TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +2E2B;ONE DOT OVER TWO DOTS PUNCTUATION;Po;0;ON;;;;;N;;;;; +2E2C;SQUARED FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +2E2D;FIVE DOT MARK;Po;0;ON;;;;;N;;;;; +2E2E;REVERSED QUESTION MARK;Po;0;ON;;;;;N;;;;; +2E2F;VERTICAL TILDE;Lm;0;ON;;;;;N;;;;; +2E30;RING POINT;Po;0;ON;;;;;N;;;;; 2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; 2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; 2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; @@ -8632,7 +10239,7 @@ 30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;; 30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;; 30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;; -30FB;KATAKANA MIDDLE DOT;Pc;0;ON;;;;;N;;;;; +30FB;KATAKANA MIDDLE DOT;Po;0;ON;;;;;N;;;;; 30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;; 30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;; 30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;; @@ -8677,6 +10284,7 @@ 312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;; 312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;; 312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;; +312D;BOPOMOFO LETTER IH;Lo;0;L;;;;;N;;;;; 3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;; 3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;; 3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;; @@ -8811,6 +10419,42 @@ 31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;; 31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;; 31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;; +31C0;CJK STROKE T;So;0;ON;;;;;N;;;;; +31C1;CJK STROKE WG;So;0;ON;;;;;N;;;;; +31C2;CJK STROKE XG;So;0;ON;;;;;N;;;;; +31C3;CJK STROKE BXG;So;0;ON;;;;;N;;;;; +31C4;CJK STROKE SW;So;0;ON;;;;;N;;;;; +31C5;CJK STROKE HZZ;So;0;ON;;;;;N;;;;; +31C6;CJK STROKE HZG;So;0;ON;;;;;N;;;;; +31C7;CJK STROKE HP;So;0;ON;;;;;N;;;;; +31C8;CJK STROKE HZWG;So;0;ON;;;;;N;;;;; +31C9;CJK STROKE SZWG;So;0;ON;;;;;N;;;;; +31CA;CJK STROKE HZT;So;0;ON;;;;;N;;;;; +31CB;CJK STROKE HZZP;So;0;ON;;;;;N;;;;; +31CC;CJK STROKE HPWG;So;0;ON;;;;;N;;;;; +31CD;CJK STROKE HZW;So;0;ON;;;;;N;;;;; +31CE;CJK STROKE HZZZ;So;0;ON;;;;;N;;;;; +31CF;CJK STROKE N;So;0;ON;;;;;N;;;;; +31D0;CJK STROKE H;So;0;ON;;;;;N;;;;; +31D1;CJK STROKE S;So;0;ON;;;;;N;;;;; +31D2;CJK STROKE P;So;0;ON;;;;;N;;;;; +31D3;CJK STROKE SP;So;0;ON;;;;;N;;;;; +31D4;CJK STROKE D;So;0;ON;;;;;N;;;;; +31D5;CJK STROKE HZ;So;0;ON;;;;;N;;;;; +31D6;CJK STROKE HG;So;0;ON;;;;;N;;;;; +31D7;CJK STROKE SZ;So;0;ON;;;;;N;;;;; +31D8;CJK STROKE SWZ;So;0;ON;;;;;N;;;;; +31D9;CJK STROKE ST;So;0;ON;;;;;N;;;;; +31DA;CJK STROKE SG;So;0;ON;;;;;N;;;;; +31DB;CJK STROKE PD;So;0;ON;;;;;N;;;;; +31DC;CJK STROKE PZ;So;0;ON;;;;;N;;;;; +31DD;CJK STROKE TN;So;0;ON;;;;;N;;;;; +31DE;CJK STROKE SZZ;So;0;ON;;;;;N;;;;; +31DF;CJK STROKE SWG;So;0;ON;;;;;N;;;;; +31E0;CJK STROKE HXWG;So;0;ON;;;;;N;;;;; +31E1;CJK STROKE HZZZG;So;0;ON;;;;;N;;;;; +31E2;CJK STROKE PG;So;0;ON;;;;;N;;;;; +31E3;CJK STROKE Q;So;0;ON;;;;;N;;;;; 31F0;KATAKANA LETTER SMALL KU;Lo;0;L;;;;;N;;;;; 31F1;KATAKANA LETTER SMALL SI;Lo;0;L;;;;;N;;;;; 31F2;KATAKANA LETTER SMALL SU;Lo;0;L;;;;;N;;;;; @@ -8940,6 +10584,7 @@ 327B;CIRCLED HANGUL HIEUH A;So;0;L;<circle> 1112 1161;;;;N;CIRCLED HANGUL HA;;;; 327C;CIRCLED KOREAN CHARACTER CHAMKO;So;0;ON;<circle> 110E 1161 11B7 1100 1169;;;;N;;;;; 327D;CIRCLED KOREAN CHARACTER JUEUI;So;0;ON;<circle> 110C 116E 110B 1174;;;;N;;;;; +327E;CIRCLED HANGUL IEUNG U;So;0;ON;<circle> 110B 116E;;;;N;;;;; 327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;; 3280;CIRCLED IDEOGRAPH ONE;No;0;L;<circle> 4E00;;;1;N;;;;; 3281;CIRCLED IDEOGRAPH TWO;No;0;L;<circle> 4E8C;;;2;N;;;;; @@ -9391,7 +11036,7 @@ 4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;; 4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;; 4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;; -9FA5;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; +9FC3;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; @@ -9413,7 +11058,7 @@ A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;; A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;; A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;; A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;; -A015;YI SYLLABLE WU;Lo;0;L;;;;;N;;;;; +A015;YI SYLLABLE WU;Lm;0;L;;;;;N;;;;; A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;; A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;; A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;; @@ -10612,6 +12257,879 @@ A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;; A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;; A4C5;YI RADICAL NBIE;So;0;ON;;;;;N;;;;; A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;; +A500;VAI SYLLABLE EE;Lo;0;L;;;;;N;;;;; +A501;VAI SYLLABLE EEN;Lo;0;L;;;;;N;;;;; +A502;VAI SYLLABLE HEE;Lo;0;L;;;;;N;;;;; +A503;VAI SYLLABLE WEE;Lo;0;L;;;;;N;;;;; +A504;VAI SYLLABLE WEEN;Lo;0;L;;;;;N;;;;; +A505;VAI SYLLABLE PEE;Lo;0;L;;;;;N;;;;; +A506;VAI SYLLABLE BHEE;Lo;0;L;;;;;N;;;;; +A507;VAI SYLLABLE BEE;Lo;0;L;;;;;N;;;;; +A508;VAI SYLLABLE MBEE;Lo;0;L;;;;;N;;;;; +A509;VAI SYLLABLE KPEE;Lo;0;L;;;;;N;;;;; +A50A;VAI SYLLABLE MGBEE;Lo;0;L;;;;;N;;;;; +A50B;VAI SYLLABLE GBEE;Lo;0;L;;;;;N;;;;; +A50C;VAI SYLLABLE FEE;Lo;0;L;;;;;N;;;;; +A50D;VAI SYLLABLE VEE;Lo;0;L;;;;;N;;;;; +A50E;VAI SYLLABLE TEE;Lo;0;L;;;;;N;;;;; +A50F;VAI SYLLABLE THEE;Lo;0;L;;;;;N;;;;; +A510;VAI SYLLABLE DHEE;Lo;0;L;;;;;N;;;;; +A511;VAI SYLLABLE DHHEE;Lo;0;L;;;;;N;;;;; +A512;VAI SYLLABLE LEE;Lo;0;L;;;;;N;;;;; +A513;VAI SYLLABLE REE;Lo;0;L;;;;;N;;;;; +A514;VAI SYLLABLE DEE;Lo;0;L;;;;;N;;;;; +A515;VAI SYLLABLE NDEE;Lo;0;L;;;;;N;;;;; +A516;VAI SYLLABLE SEE;Lo;0;L;;;;;N;;;;; +A517;VAI SYLLABLE SHEE;Lo;0;L;;;;;N;;;;; +A518;VAI SYLLABLE ZEE;Lo;0;L;;;;;N;;;;; +A519;VAI SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;; +A51A;VAI SYLLABLE CEE;Lo;0;L;;;;;N;;;;; +A51B;VAI SYLLABLE JEE;Lo;0;L;;;;;N;;;;; +A51C;VAI SYLLABLE NJEE;Lo;0;L;;;;;N;;;;; +A51D;VAI SYLLABLE YEE;Lo;0;L;;;;;N;;;;; +A51E;VAI SYLLABLE KEE;Lo;0;L;;;;;N;;;;; +A51F;VAI SYLLABLE NGGEE;Lo;0;L;;;;;N;;;;; +A520;VAI SYLLABLE GEE;Lo;0;L;;;;;N;;;;; +A521;VAI SYLLABLE MEE;Lo;0;L;;;;;N;;;;; +A522;VAI SYLLABLE NEE;Lo;0;L;;;;;N;;;;; +A523;VAI SYLLABLE NYEE;Lo;0;L;;;;;N;;;;; +A524;VAI SYLLABLE I;Lo;0;L;;;;;N;;;;; +A525;VAI SYLLABLE IN;Lo;0;L;;;;;N;;;;; +A526;VAI SYLLABLE HI;Lo;0;L;;;;;N;;;;; +A527;VAI SYLLABLE HIN;Lo;0;L;;;;;N;;;;; +A528;VAI SYLLABLE WI;Lo;0;L;;;;;N;;;;; +A529;VAI SYLLABLE WIN;Lo;0;L;;;;;N;;;;; +A52A;VAI SYLLABLE PI;Lo;0;L;;;;;N;;;;; +A52B;VAI SYLLABLE BHI;Lo;0;L;;;;;N;;;;; +A52C;VAI SYLLABLE BI;Lo;0;L;;;;;N;;;;; +A52D;VAI SYLLABLE MBI;Lo;0;L;;;;;N;;;;; +A52E;VAI SYLLABLE KPI;Lo;0;L;;;;;N;;;;; +A52F;VAI SYLLABLE MGBI;Lo;0;L;;;;;N;;;;; +A530;VAI SYLLABLE GBI;Lo;0;L;;;;;N;;;;; +A531;VAI SYLLABLE FI;Lo;0;L;;;;;N;;;;; +A532;VAI SYLLABLE VI;Lo;0;L;;;;;N;;;;; +A533;VAI SYLLABLE TI;Lo;0;L;;;;;N;;;;; +A534;VAI SYLLABLE THI;Lo;0;L;;;;;N;;;;; +A535;VAI SYLLABLE DHI;Lo;0;L;;;;;N;;;;; +A536;VAI SYLLABLE DHHI;Lo;0;L;;;;;N;;;;; +A537;VAI SYLLABLE LI;Lo;0;L;;;;;N;;;;; +A538;VAI SYLLABLE RI;Lo;0;L;;;;;N;;;;; +A539;VAI SYLLABLE DI;Lo;0;L;;;;;N;;;;; +A53A;VAI SYLLABLE NDI;Lo;0;L;;;;;N;;;;; +A53B;VAI SYLLABLE SI;Lo;0;L;;;;;N;;;;; +A53C;VAI SYLLABLE SHI;Lo;0;L;;;;;N;;;;; +A53D;VAI SYLLABLE ZI;Lo;0;L;;;;;N;;;;; +A53E;VAI SYLLABLE ZHI;Lo;0;L;;;;;N;;;;; +A53F;VAI SYLLABLE CI;Lo;0;L;;;;;N;;;;; +A540;VAI SYLLABLE JI;Lo;0;L;;;;;N;;;;; +A541;VAI SYLLABLE NJI;Lo;0;L;;;;;N;;;;; +A542;VAI SYLLABLE YI;Lo;0;L;;;;;N;;;;; +A543;VAI SYLLABLE KI;Lo;0;L;;;;;N;;;;; +A544;VAI SYLLABLE NGGI;Lo;0;L;;;;;N;;;;; +A545;VAI SYLLABLE GI;Lo;0;L;;;;;N;;;;; +A546;VAI SYLLABLE MI;Lo;0;L;;;;;N;;;;; +A547;VAI SYLLABLE NI;Lo;0;L;;;;;N;;;;; +A548;VAI SYLLABLE NYI;Lo;0;L;;;;;N;;;;; +A549;VAI SYLLABLE A;Lo;0;L;;;;;N;;;;; +A54A;VAI SYLLABLE AN;Lo;0;L;;;;;N;;;;; +A54B;VAI SYLLABLE NGAN;Lo;0;L;;;;;N;;;;; +A54C;VAI SYLLABLE HA;Lo;0;L;;;;;N;;;;; +A54D;VAI SYLLABLE HAN;Lo;0;L;;;;;N;;;;; +A54E;VAI SYLLABLE WA;Lo;0;L;;;;;N;;;;; +A54F;VAI SYLLABLE WAN;Lo;0;L;;;;;N;;;;; +A550;VAI SYLLABLE PA;Lo;0;L;;;;;N;;;;; +A551;VAI SYLLABLE BHA;Lo;0;L;;;;;N;;;;; +A552;VAI SYLLABLE BA;Lo;0;L;;;;;N;;;;; +A553;VAI SYLLABLE MBA;Lo;0;L;;;;;N;;;;; +A554;VAI SYLLABLE KPA;Lo;0;L;;;;;N;;;;; +A555;VAI SYLLABLE KPAN;Lo;0;L;;;;;N;;;;; +A556;VAI SYLLABLE MGBA;Lo;0;L;;;;;N;;;;; +A557;VAI SYLLABLE GBA;Lo;0;L;;;;;N;;;;; +A558;VAI SYLLABLE FA;Lo;0;L;;;;;N;;;;; +A559;VAI SYLLABLE VA;Lo;0;L;;;;;N;;;;; +A55A;VAI SYLLABLE TA;Lo;0;L;;;;;N;;;;; +A55B;VAI SYLLABLE THA;Lo;0;L;;;;;N;;;;; +A55C;VAI SYLLABLE DHA;Lo;0;L;;;;;N;;;;; +A55D;VAI SYLLABLE DHHA;Lo;0;L;;;;;N;;;;; +A55E;VAI SYLLABLE LA;Lo;0;L;;;;;N;;;;; +A55F;VAI SYLLABLE RA;Lo;0;L;;;;;N;;;;; +A560;VAI SYLLABLE DA;Lo;0;L;;;;;N;;;;; +A561;VAI SYLLABLE NDA;Lo;0;L;;;;;N;;;;; +A562;VAI SYLLABLE SA;Lo;0;L;;;;;N;;;;; +A563;VAI SYLLABLE SHA;Lo;0;L;;;;;N;;;;; +A564;VAI SYLLABLE ZA;Lo;0;L;;;;;N;;;;; +A565;VAI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; +A566;VAI SYLLABLE CA;Lo;0;L;;;;;N;;;;; +A567;VAI SYLLABLE JA;Lo;0;L;;;;;N;;;;; +A568;VAI SYLLABLE NJA;Lo;0;L;;;;;N;;;;; +A569;VAI SYLLABLE YA;Lo;0;L;;;;;N;;;;; +A56A;VAI SYLLABLE KA;Lo;0;L;;;;;N;;;;; +A56B;VAI SYLLABLE KAN;Lo;0;L;;;;;N;;;;; +A56C;VAI SYLLABLE NGGA;Lo;0;L;;;;;N;;;;; +A56D;VAI SYLLABLE GA;Lo;0;L;;;;;N;;;;; +A56E;VAI SYLLABLE MA;Lo;0;L;;;;;N;;;;; +A56F;VAI SYLLABLE NA;Lo;0;L;;;;;N;;;;; +A570;VAI SYLLABLE NYA;Lo;0;L;;;;;N;;;;; +A571;VAI SYLLABLE OO;Lo;0;L;;;;;N;;;;; +A572;VAI SYLLABLE OON;Lo;0;L;;;;;N;;;;; +A573;VAI SYLLABLE HOO;Lo;0;L;;;;;N;;;;; +A574;VAI SYLLABLE WOO;Lo;0;L;;;;;N;;;;; +A575;VAI SYLLABLE WOON;Lo;0;L;;;;;N;;;;; +A576;VAI SYLLABLE POO;Lo;0;L;;;;;N;;;;; +A577;VAI SYLLABLE BHOO;Lo;0;L;;;;;N;;;;; +A578;VAI SYLLABLE BOO;Lo;0;L;;;;;N;;;;; +A579;VAI SYLLABLE MBOO;Lo;0;L;;;;;N;;;;; +A57A;VAI SYLLABLE KPOO;Lo;0;L;;;;;N;;;;; +A57B;VAI SYLLABLE MGBOO;Lo;0;L;;;;;N;;;;; +A57C;VAI SYLLABLE GBOO;Lo;0;L;;;;;N;;;;; +A57D;VAI SYLLABLE FOO;Lo;0;L;;;;;N;;;;; +A57E;VAI SYLLABLE VOO;Lo;0;L;;;;;N;;;;; +A57F;VAI SYLLABLE TOO;Lo;0;L;;;;;N;;;;; +A580;VAI SYLLABLE THOO;Lo;0;L;;;;;N;;;;; +A581;VAI SYLLABLE DHOO;Lo;0;L;;;;;N;;;;; +A582;VAI SYLLABLE DHHOO;Lo;0;L;;;;;N;;;;; +A583;VAI SYLLABLE LOO;Lo;0;L;;;;;N;;;;; +A584;VAI SYLLABLE ROO;Lo;0;L;;;;;N;;;;; +A585;VAI SYLLABLE DOO;Lo;0;L;;;;;N;;;;; +A586;VAI SYLLABLE NDOO;Lo;0;L;;;;;N;;;;; +A587;VAI SYLLABLE SOO;Lo;0;L;;;;;N;;;;; +A588;VAI SYLLABLE SHOO;Lo;0;L;;;;;N;;;;; +A589;VAI SYLLABLE ZOO;Lo;0;L;;;;;N;;;;; +A58A;VAI SYLLABLE ZHOO;Lo;0;L;;;;;N;;;;; +A58B;VAI SYLLABLE COO;Lo;0;L;;;;;N;;;;; +A58C;VAI SYLLABLE JOO;Lo;0;L;;;;;N;;;;; +A58D;VAI SYLLABLE NJOO;Lo;0;L;;;;;N;;;;; +A58E;VAI SYLLABLE YOO;Lo;0;L;;;;;N;;;;; +A58F;VAI SYLLABLE KOO;Lo;0;L;;;;;N;;;;; +A590;VAI SYLLABLE NGGOO;Lo;0;L;;;;;N;;;;; +A591;VAI SYLLABLE GOO;Lo;0;L;;;;;N;;;;; +A592;VAI SYLLABLE MOO;Lo;0;L;;;;;N;;;;; +A593;VAI SYLLABLE NOO;Lo;0;L;;;;;N;;;;; +A594;VAI SYLLABLE NYOO;Lo;0;L;;;;;N;;;;; +A595;VAI SYLLABLE U;Lo;0;L;;;;;N;;;;; +A596;VAI SYLLABLE UN;Lo;0;L;;;;;N;;;;; +A597;VAI SYLLABLE HU;Lo;0;L;;;;;N;;;;; +A598;VAI SYLLABLE HUN;Lo;0;L;;;;;N;;;;; +A599;VAI SYLLABLE WU;Lo;0;L;;;;;N;;;;; +A59A;VAI SYLLABLE WUN;Lo;0;L;;;;;N;;;;; +A59B;VAI SYLLABLE PU;Lo;0;L;;;;;N;;;;; +A59C;VAI SYLLABLE BHU;Lo;0;L;;;;;N;;;;; +A59D;VAI SYLLABLE BU;Lo;0;L;;;;;N;;;;; +A59E;VAI SYLLABLE MBU;Lo;0;L;;;;;N;;;;; +A59F;VAI SYLLABLE KPU;Lo;0;L;;;;;N;;;;; +A5A0;VAI SYLLABLE MGBU;Lo;0;L;;;;;N;;;;; +A5A1;VAI SYLLABLE GBU;Lo;0;L;;;;;N;;;;; +A5A2;VAI SYLLABLE FU;Lo;0;L;;;;;N;;;;; +A5A3;VAI SYLLABLE VU;Lo;0;L;;;;;N;;;;; +A5A4;VAI SYLLABLE TU;Lo;0;L;;;;;N;;;;; +A5A5;VAI SYLLABLE THU;Lo;0;L;;;;;N;;;;; +A5A6;VAI SYLLABLE DHU;Lo;0;L;;;;;N;;;;; +A5A7;VAI SYLLABLE DHHU;Lo;0;L;;;;;N;;;;; +A5A8;VAI SYLLABLE LU;Lo;0;L;;;;;N;;;;; +A5A9;VAI SYLLABLE RU;Lo;0;L;;;;;N;;;;; +A5AA;VAI SYLLABLE DU;Lo;0;L;;;;;N;;;;; +A5AB;VAI SYLLABLE NDU;Lo;0;L;;;;;N;;;;; +A5AC;VAI SYLLABLE SU;Lo;0;L;;;;;N;;;;; +A5AD;VAI SYLLABLE SHU;Lo;0;L;;;;;N;;;;; +A5AE;VAI SYLLABLE ZU;Lo;0;L;;;;;N;;;;; +A5AF;VAI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; +A5B0;VAI SYLLABLE CU;Lo;0;L;;;;;N;;;;; +A5B1;VAI SYLLABLE JU;Lo;0;L;;;;;N;;;;; +A5B2;VAI SYLLABLE NJU;Lo;0;L;;;;;N;;;;; +A5B3;VAI SYLLABLE YU;Lo;0;L;;;;;N;;;;; +A5B4;VAI SYLLABLE KU;Lo;0;L;;;;;N;;;;; +A5B5;VAI SYLLABLE NGGU;Lo;0;L;;;;;N;;;;; +A5B6;VAI SYLLABLE GU;Lo;0;L;;;;;N;;;;; +A5B7;VAI SYLLABLE MU;Lo;0;L;;;;;N;;;;; +A5B8;VAI SYLLABLE NU;Lo;0;L;;;;;N;;;;; +A5B9;VAI SYLLABLE NYU;Lo;0;L;;;;;N;;;;; +A5BA;VAI SYLLABLE O;Lo;0;L;;;;;N;;;;; +A5BB;VAI SYLLABLE ON;Lo;0;L;;;;;N;;;;; +A5BC;VAI SYLLABLE NGON;Lo;0;L;;;;;N;;;;; +A5BD;VAI SYLLABLE HO;Lo;0;L;;;;;N;;;;; +A5BE;VAI SYLLABLE HON;Lo;0;L;;;;;N;;;;; +A5BF;VAI SYLLABLE WO;Lo;0;L;;;;;N;;;;; +A5C0;VAI SYLLABLE WON;Lo;0;L;;;;;N;;;;; +A5C1;VAI SYLLABLE PO;Lo;0;L;;;;;N;;;;; +A5C2;VAI SYLLABLE BHO;Lo;0;L;;;;;N;;;;; +A5C3;VAI SYLLABLE BO;Lo;0;L;;;;;N;;;;; +A5C4;VAI SYLLABLE MBO;Lo;0;L;;;;;N;;;;; +A5C5;VAI SYLLABLE KPO;Lo;0;L;;;;;N;;;;; +A5C6;VAI SYLLABLE MGBO;Lo;0;L;;;;;N;;;;; +A5C7;VAI SYLLABLE GBO;Lo;0;L;;;;;N;;;;; +A5C8;VAI SYLLABLE GBON;Lo;0;L;;;;;N;;;;; +A5C9;VAI SYLLABLE FO;Lo;0;L;;;;;N;;;;; +A5CA;VAI SYLLABLE VO;Lo;0;L;;;;;N;;;;; +A5CB;VAI SYLLABLE TO;Lo;0;L;;;;;N;;;;; +A5CC;VAI SYLLABLE THO;Lo;0;L;;;;;N;;;;; +A5CD;VAI SYLLABLE DHO;Lo;0;L;;;;;N;;;;; +A5CE;VAI SYLLABLE DHHO;Lo;0;L;;;;;N;;;;; +A5CF;VAI SYLLABLE LO;Lo;0;L;;;;;N;;;;; +A5D0;VAI SYLLABLE RO;Lo;0;L;;;;;N;;;;; +A5D1;VAI SYLLABLE DO;Lo;0;L;;;;;N;;;;; +A5D2;VAI SYLLABLE NDO;Lo;0;L;;;;;N;;;;; +A5D3;VAI SYLLABLE SO;Lo;0;L;;;;;N;;;;; +A5D4;VAI SYLLABLE SHO;Lo;0;L;;;;;N;;;;; +A5D5;VAI SYLLABLE ZO;Lo;0;L;;;;;N;;;;; +A5D6;VAI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; +A5D7;VAI SYLLABLE CO;Lo;0;L;;;;;N;;;;; +A5D8;VAI SYLLABLE JO;Lo;0;L;;;;;N;;;;; +A5D9;VAI SYLLABLE NJO;Lo;0;L;;;;;N;;;;; +A5DA;VAI SYLLABLE YO;Lo;0;L;;;;;N;;;;; +A5DB;VAI SYLLABLE KO;Lo;0;L;;;;;N;;;;; +A5DC;VAI SYLLABLE NGGO;Lo;0;L;;;;;N;;;;; +A5DD;VAI SYLLABLE GO;Lo;0;L;;;;;N;;;;; +A5DE;VAI SYLLABLE MO;Lo;0;L;;;;;N;;;;; +A5DF;VAI SYLLABLE NO;Lo;0;L;;;;;N;;;;; +A5E0;VAI SYLLABLE NYO;Lo;0;L;;;;;N;;;;; +A5E1;VAI SYLLABLE E;Lo;0;L;;;;;N;;;;; +A5E2;VAI SYLLABLE EN;Lo;0;L;;;;;N;;;;; +A5E3;VAI SYLLABLE NGEN;Lo;0;L;;;;;N;;;;; +A5E4;VAI SYLLABLE HE;Lo;0;L;;;;;N;;;;; +A5E5;VAI SYLLABLE HEN;Lo;0;L;;;;;N;;;;; +A5E6;VAI SYLLABLE WE;Lo;0;L;;;;;N;;;;; +A5E7;VAI SYLLABLE WEN;Lo;0;L;;;;;N;;;;; +A5E8;VAI SYLLABLE PE;Lo;0;L;;;;;N;;;;; +A5E9;VAI SYLLABLE BHE;Lo;0;L;;;;;N;;;;; +A5EA;VAI SYLLABLE BE;Lo;0;L;;;;;N;;;;; +A5EB;VAI SYLLABLE MBE;Lo;0;L;;;;;N;;;;; +A5EC;VAI SYLLABLE KPE;Lo;0;L;;;;;N;;;;; +A5ED;VAI SYLLABLE KPEN;Lo;0;L;;;;;N;;;;; +A5EE;VAI SYLLABLE MGBE;Lo;0;L;;;;;N;;;;; +A5EF;VAI SYLLABLE GBE;Lo;0;L;;;;;N;;;;; +A5F0;VAI SYLLABLE GBEN;Lo;0;L;;;;;N;;;;; +A5F1;VAI SYLLABLE FE;Lo;0;L;;;;;N;;;;; +A5F2;VAI SYLLABLE VE;Lo;0;L;;;;;N;;;;; +A5F3;VAI SYLLABLE TE;Lo;0;L;;;;;N;;;;; +A5F4;VAI SYLLABLE THE;Lo;0;L;;;;;N;;;;; +A5F5;VAI SYLLABLE DHE;Lo;0;L;;;;;N;;;;; +A5F6;VAI SYLLABLE DHHE;Lo;0;L;;;;;N;;;;; +A5F7;VAI SYLLABLE LE;Lo;0;L;;;;;N;;;;; +A5F8;VAI SYLLABLE RE;Lo;0;L;;;;;N;;;;; +A5F9;VAI SYLLABLE DE;Lo;0;L;;;;;N;;;;; +A5FA;VAI SYLLABLE NDE;Lo;0;L;;;;;N;;;;; +A5FB;VAI SYLLABLE SE;Lo;0;L;;;;;N;;;;; +A5FC;VAI SYLLABLE SHE;Lo;0;L;;;;;N;;;;; +A5FD;VAI SYLLABLE ZE;Lo;0;L;;;;;N;;;;; +A5FE;VAI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; +A5FF;VAI SYLLABLE CE;Lo;0;L;;;;;N;;;;; +A600;VAI SYLLABLE JE;Lo;0;L;;;;;N;;;;; +A601;VAI SYLLABLE NJE;Lo;0;L;;;;;N;;;;; +A602;VAI SYLLABLE YE;Lo;0;L;;;;;N;;;;; +A603;VAI SYLLABLE KE;Lo;0;L;;;;;N;;;;; +A604;VAI SYLLABLE NGGE;Lo;0;L;;;;;N;;;;; +A605;VAI SYLLABLE NGGEN;Lo;0;L;;;;;N;;;;; +A606;VAI SYLLABLE GE;Lo;0;L;;;;;N;;;;; +A607;VAI SYLLABLE GEN;Lo;0;L;;;;;N;;;;; +A608;VAI SYLLABLE ME;Lo;0;L;;;;;N;;;;; +A609;VAI SYLLABLE NE;Lo;0;L;;;;;N;;;;; +A60A;VAI SYLLABLE NYE;Lo;0;L;;;;;N;;;;; +A60B;VAI SYLLABLE NG;Lo;0;L;;;;;N;;;;; +A60C;VAI SYLLABLE LENGTHENER;Lm;0;L;;;;;N;;;;; +A60D;VAI COMMA;Po;0;ON;;;;;N;;;;; +A60E;VAI FULL STOP;Po;0;ON;;;;;N;;;;; +A60F;VAI QUESTION MARK;Po;0;ON;;;;;N;;;;; +A610;VAI SYLLABLE NDOLE FA;Lo;0;L;;;;;N;;;;; +A611;VAI SYLLABLE NDOLE KA;Lo;0;L;;;;;N;;;;; +A612;VAI SYLLABLE NDOLE SOO;Lo;0;L;;;;;N;;;;; +A613;VAI SYMBOL FEENG;Lo;0;L;;;;;N;;;;; +A614;VAI SYMBOL KEENG;Lo;0;L;;;;;N;;;;; +A615;VAI SYMBOL TING;Lo;0;L;;;;;N;;;;; +A616;VAI SYMBOL NII;Lo;0;L;;;;;N;;;;; +A617;VAI SYMBOL BANG;Lo;0;L;;;;;N;;;;; +A618;VAI SYMBOL FAA;Lo;0;L;;;;;N;;;;; +A619;VAI SYMBOL TAA;Lo;0;L;;;;;N;;;;; +A61A;VAI SYMBOL DANG;Lo;0;L;;;;;N;;;;; +A61B;VAI SYMBOL DOONG;Lo;0;L;;;;;N;;;;; +A61C;VAI SYMBOL KUNG;Lo;0;L;;;;;N;;;;; +A61D;VAI SYMBOL TONG;Lo;0;L;;;;;N;;;;; +A61E;VAI SYMBOL DO-O;Lo;0;L;;;;;N;;;;; +A61F;VAI SYMBOL JONG;Lo;0;L;;;;;N;;;;; +A620;VAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +A621;VAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +A622;VAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +A623;VAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +A624;VAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +A625;VAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +A626;VAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +A627;VAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +A628;VAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +A629;VAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +A62A;VAI SYLLABLE NDOLE MA;Lo;0;L;;;;;N;;;;; +A62B;VAI SYLLABLE NDOLE DO;Lo;0;L;;;;;N;;;;; +A640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641; +A641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640 +A642;CYRILLIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;A643; +A643;CYRILLIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;A642;;A642 +A644;CYRILLIC CAPITAL LETTER REVERSED DZE;Lu;0;L;;;;;N;;;;A645; +A645;CYRILLIC SMALL LETTER REVERSED DZE;Ll;0;L;;;;;N;;;A644;;A644 +A646;CYRILLIC CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;A647; +A647;CYRILLIC SMALL LETTER IOTA;Ll;0;L;;;;;N;;;A646;;A646 +A648;CYRILLIC CAPITAL LETTER DJERV;Lu;0;L;;;;;N;;;;A649; +A649;CYRILLIC SMALL LETTER DJERV;Ll;0;L;;;;;N;;;A648;;A648 +A64A;CYRILLIC CAPITAL LETTER MONOGRAPH UK;Lu;0;L;;;;;N;;;;A64B; +A64B;CYRILLIC SMALL LETTER MONOGRAPH UK;Ll;0;L;;;;;N;;;A64A;;A64A +A64C;CYRILLIC CAPITAL LETTER BROAD OMEGA;Lu;0;L;;;;;N;;;;A64D; +A64D;CYRILLIC SMALL LETTER BROAD OMEGA;Ll;0;L;;;;;N;;;A64C;;A64C +A64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F; +A64F;CYRILLIC SMALL LETTER NEUTRAL YER;Ll;0;L;;;;;N;;;A64E;;A64E +A650;CYRILLIC CAPITAL LETTER YERU WITH BACK YER;Lu;0;L;;;;;N;;;;A651; +A651;CYRILLIC SMALL LETTER YERU WITH BACK YER;Ll;0;L;;;;;N;;;A650;;A650 +A652;CYRILLIC CAPITAL LETTER IOTIFIED YAT;Lu;0;L;;;;;N;;;;A653; +A653;CYRILLIC SMALL LETTER IOTIFIED YAT;Ll;0;L;;;;;N;;;A652;;A652 +A654;CYRILLIC CAPITAL LETTER REVERSED YU;Lu;0;L;;;;;N;;;;A655; +A655;CYRILLIC SMALL LETTER REVERSED YU;Ll;0;L;;;;;N;;;A654;;A654 +A656;CYRILLIC CAPITAL LETTER IOTIFIED A;Lu;0;L;;;;;N;;;;A657; +A657;CYRILLIC SMALL LETTER IOTIFIED A;Ll;0;L;;;;;N;;;A656;;A656 +A658;CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A659; +A659;CYRILLIC SMALL LETTER CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A658;;A658 +A65A;CYRILLIC CAPITAL LETTER BLENDED YUS;Lu;0;L;;;;;N;;;;A65B; +A65B;CYRILLIC SMALL LETTER BLENDED YUS;Ll;0;L;;;;;N;;;A65A;;A65A +A65C;CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A65D; +A65D;CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A65C;;A65C +A65E;CYRILLIC CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;A65F; +A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E +A662;CYRILLIC CAPITAL LETTER SOFT DE;Lu;0;L;;;;;N;;;;A663; +A663;CYRILLIC SMALL LETTER SOFT DE;Ll;0;L;;;;;N;;;A662;;A662 +A664;CYRILLIC CAPITAL LETTER SOFT EL;Lu;0;L;;;;;N;;;;A665; +A665;CYRILLIC SMALL LETTER SOFT EL;Ll;0;L;;;;;N;;;A664;;A664 +A666;CYRILLIC CAPITAL LETTER SOFT EM;Lu;0;L;;;;;N;;;;A667; +A667;CYRILLIC SMALL LETTER SOFT EM;Ll;0;L;;;;;N;;;A666;;A666 +A668;CYRILLIC CAPITAL LETTER MONOCULAR O;Lu;0;L;;;;;N;;;;A669; +A669;CYRILLIC SMALL LETTER MONOCULAR O;Ll;0;L;;;;;N;;;A668;;A668 +A66A;CYRILLIC CAPITAL LETTER BINOCULAR O;Lu;0;L;;;;;N;;;;A66B; +A66B;CYRILLIC SMALL LETTER BINOCULAR O;Ll;0;L;;;;;N;;;A66A;;A66A +A66C;CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O;Lu;0;L;;;;;N;;;;A66D; +A66D;CYRILLIC SMALL LETTER DOUBLE MONOCULAR O;Ll;0;L;;;;;N;;;A66C;;A66C +A66E;CYRILLIC LETTER MULTIOCULAR O;Lo;0;L;;;;;N;;;;; +A66F;COMBINING CYRILLIC VZMET;Mn;230;NSM;;;;;N;;;;; +A670;COMBINING CYRILLIC TEN MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; +A671;COMBINING CYRILLIC HUNDRED MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; +A672;COMBINING CYRILLIC THOUSAND MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; +A673;SLAVONIC ASTERISK;Po;0;ON;;;;;N;;;;; +A67C;COMBINING CYRILLIC KAVYKA;Mn;230;NSM;;;;;N;;;;; +A67D;COMBINING CYRILLIC PAYEROK;Mn;230;NSM;;;;;N;;;;; +A67E;CYRILLIC KAVYKA;Po;0;ON;;;;;N;;;;; +A67F;CYRILLIC PAYEROK;Lm;0;ON;;;;;N;;;;; +A680;CYRILLIC CAPITAL LETTER DWE;Lu;0;L;;;;;N;;;;A681; +A681;CYRILLIC SMALL LETTER DWE;Ll;0;L;;;;;N;;;A680;;A680 +A682;CYRILLIC CAPITAL LETTER DZWE;Lu;0;L;;;;;N;;;;A683; +A683;CYRILLIC SMALL LETTER DZWE;Ll;0;L;;;;;N;;;A682;;A682 +A684;CYRILLIC CAPITAL LETTER ZHWE;Lu;0;L;;;;;N;;;;A685; +A685;CYRILLIC SMALL LETTER ZHWE;Ll;0;L;;;;;N;;;A684;;A684 +A686;CYRILLIC CAPITAL LETTER CCHE;Lu;0;L;;;;;N;;;;A687; +A687;CYRILLIC SMALL LETTER CCHE;Ll;0;L;;;;;N;;;A686;;A686 +A688;CYRILLIC CAPITAL LETTER DZZE;Lu;0;L;;;;;N;;;;A689; +A689;CYRILLIC SMALL LETTER DZZE;Ll;0;L;;;;;N;;;A688;;A688 +A68A;CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;A68B; +A68B;CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;A68A;;A68A +A68C;CYRILLIC CAPITAL LETTER TWE;Lu;0;L;;;;;N;;;;A68D; +A68D;CYRILLIC SMALL LETTER TWE;Ll;0;L;;;;;N;;;A68C;;A68C +A68E;CYRILLIC CAPITAL LETTER TSWE;Lu;0;L;;;;;N;;;;A68F; +A68F;CYRILLIC SMALL LETTER TSWE;Ll;0;L;;;;;N;;;A68E;;A68E +A690;CYRILLIC CAPITAL LETTER TSSE;Lu;0;L;;;;;N;;;;A691; +A691;CYRILLIC SMALL LETTER TSSE;Ll;0;L;;;;;N;;;A690;;A690 +A692;CYRILLIC CAPITAL LETTER TCHE;Lu;0;L;;;;;N;;;;A693; +A693;CYRILLIC SMALL LETTER TCHE;Ll;0;L;;;;;N;;;A692;;A692 +A694;CYRILLIC CAPITAL LETTER HWE;Lu;0;L;;;;;N;;;;A695; +A695;CYRILLIC SMALL LETTER HWE;Ll;0;L;;;;;N;;;A694;;A694 +A696;CYRILLIC CAPITAL LETTER SHWE;Lu;0;L;;;;;N;;;;A697; +A697;CYRILLIC SMALL LETTER SHWE;Ll;0;L;;;;;N;;;A696;;A696 +A700;MODIFIER LETTER CHINESE TONE YIN PING;Sk;0;ON;;;;;N;;;;; +A701;MODIFIER LETTER CHINESE TONE YANG PING;Sk;0;ON;;;;;N;;;;; +A702;MODIFIER LETTER CHINESE TONE YIN SHANG;Sk;0;ON;;;;;N;;;;; +A703;MODIFIER LETTER CHINESE TONE YANG SHANG;Sk;0;ON;;;;;N;;;;; +A704;MODIFIER LETTER CHINESE TONE YIN QU;Sk;0;ON;;;;;N;;;;; +A705;MODIFIER LETTER CHINESE TONE YANG QU;Sk;0;ON;;;;;N;;;;; +A706;MODIFIER LETTER CHINESE TONE YIN RU;Sk;0;ON;;;;;N;;;;; +A707;MODIFIER LETTER CHINESE TONE YANG RU;Sk;0;ON;;;;;N;;;;; +A708;MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A709;MODIFIER LETTER HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A70A;MODIFIER LETTER MID DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A70B;MODIFIER LETTER LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A70C;MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A70D;MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A70E;MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A70F;MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A710;MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A711;MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A712;MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A713;MODIFIER LETTER HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A714;MODIFIER LETTER MID LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A715;MODIFIER LETTER LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A716;MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A717;MODIFIER LETTER DOT VERTICAL BAR;Lm;0;ON;;;;;N;;;;; +A718;MODIFIER LETTER DOT SLASH;Lm;0;ON;;;;;N;;;;; +A719;MODIFIER LETTER DOT HORIZONTAL BAR;Lm;0;ON;;;;;N;;;;; +A71A;MODIFIER LETTER LOWER RIGHT CORNER ANGLE;Lm;0;ON;;;;;N;;;;; +A71B;MODIFIER LETTER RAISED UP ARROW;Lm;0;ON;;;;;N;;;;; +A71C;MODIFIER LETTER RAISED DOWN ARROW;Lm;0;ON;;;;;N;;;;; +A71D;MODIFIER LETTER RAISED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;; +A71E;MODIFIER LETTER RAISED INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;; +A71F;MODIFIER LETTER LOW INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;; +A720;MODIFIER LETTER STRESS AND HIGH TONE;Sk;0;ON;;;;;N;;;;; +A721;MODIFIER LETTER STRESS AND LOW TONE;Sk;0;ON;;;;;N;;;;; +A722;LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF;Lu;0;L;;;;;N;;;;A723; +A723;LATIN SMALL LETTER EGYPTOLOGICAL ALEF;Ll;0;L;;;;;N;;;A722;;A722 +A724;LATIN CAPITAL LETTER EGYPTOLOGICAL AIN;Lu;0;L;;;;;N;;;;A725; +A725;LATIN SMALL LETTER EGYPTOLOGICAL AIN;Ll;0;L;;;;;N;;;A724;;A724 +A726;LATIN CAPITAL LETTER HENG;Lu;0;L;;;;;N;;;;A727; +A727;LATIN SMALL LETTER HENG;Ll;0;L;;;;;N;;;A726;;A726 +A728;LATIN CAPITAL LETTER TZ;Lu;0;L;;;;;N;;;;A729; +A729;LATIN SMALL LETTER TZ;Ll;0;L;;;;;N;;;A728;;A728 +A72A;LATIN CAPITAL LETTER TRESILLO;Lu;0;L;;;;;N;;;;A72B; +A72B;LATIN SMALL LETTER TRESILLO;Ll;0;L;;;;;N;;;A72A;;A72A +A72C;LATIN CAPITAL LETTER CUATRILLO;Lu;0;L;;;;;N;;;;A72D; +A72D;LATIN SMALL LETTER CUATRILLO;Ll;0;L;;;;;N;;;A72C;;A72C +A72E;LATIN CAPITAL LETTER CUATRILLO WITH COMMA;Lu;0;L;;;;;N;;;;A72F; +A72F;LATIN SMALL LETTER CUATRILLO WITH COMMA;Ll;0;L;;;;;N;;;A72E;;A72E +A730;LATIN LETTER SMALL CAPITAL F;Ll;0;L;;;;;N;;;;; +A731;LATIN LETTER SMALL CAPITAL S;Ll;0;L;;;;;N;;;;; +A732;LATIN CAPITAL LETTER AA;Lu;0;L;;;;;N;;;;A733; +A733;LATIN SMALL LETTER AA;Ll;0;L;;;;;N;;;A732;;A732 +A734;LATIN CAPITAL LETTER AO;Lu;0;L;;;;;N;;;;A735; +A735;LATIN SMALL LETTER AO;Ll;0;L;;;;;N;;;A734;;A734 +A736;LATIN CAPITAL LETTER AU;Lu;0;L;;;;;N;;;;A737; +A737;LATIN SMALL LETTER AU;Ll;0;L;;;;;N;;;A736;;A736 +A738;LATIN CAPITAL LETTER AV;Lu;0;L;;;;;N;;;;A739; +A739;LATIN SMALL LETTER AV;Ll;0;L;;;;;N;;;A738;;A738 +A73A;LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR;Lu;0;L;;;;;N;;;;A73B; +A73B;LATIN SMALL LETTER AV WITH HORIZONTAL BAR;Ll;0;L;;;;;N;;;A73A;;A73A +A73C;LATIN CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;A73D; +A73D;LATIN SMALL LETTER AY;Ll;0;L;;;;;N;;;A73C;;A73C +A73E;LATIN CAPITAL LETTER REVERSED C WITH DOT;Lu;0;L;;;;;N;;;;A73F; +A73F;LATIN SMALL LETTER REVERSED C WITH DOT;Ll;0;L;;;;;N;;;A73E;;A73E +A740;LATIN CAPITAL LETTER K WITH STROKE;Lu;0;L;;;;;N;;;;A741; +A741;LATIN SMALL LETTER K WITH STROKE;Ll;0;L;;;;;N;;;A740;;A740 +A742;LATIN CAPITAL LETTER K WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A743; +A743;LATIN SMALL LETTER K WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A742;;A742 +A744;LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A745; +A745;LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE;Ll;0;L;;;;;N;;;A744;;A744 +A746;LATIN CAPITAL LETTER BROKEN L;Lu;0;L;;;;;N;;;;A747; +A747;LATIN SMALL LETTER BROKEN L;Ll;0;L;;;;;N;;;A746;;A746 +A748;LATIN CAPITAL LETTER L WITH HIGH STROKE;Lu;0;L;;;;;N;;;;A749; +A749;LATIN SMALL LETTER L WITH HIGH STROKE;Ll;0;L;;;;;N;;;A748;;A748 +A74A;LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY;Lu;0;L;;;;;N;;;;A74B; +A74B;LATIN SMALL LETTER O WITH LONG STROKE OVERLAY;Ll;0;L;;;;;N;;;A74A;;A74A +A74C;LATIN CAPITAL LETTER O WITH LOOP;Lu;0;L;;;;;N;;;;A74D; +A74D;LATIN SMALL LETTER O WITH LOOP;Ll;0;L;;;;;N;;;A74C;;A74C +A74E;LATIN CAPITAL LETTER OO;Lu;0;L;;;;;N;;;;A74F; +A74F;LATIN SMALL LETTER OO;Ll;0;L;;;;;N;;;A74E;;A74E +A750;LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A751; +A751;LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A750;;A750 +A752;LATIN CAPITAL LETTER P WITH FLOURISH;Lu;0;L;;;;;N;;;;A753; +A753;LATIN SMALL LETTER P WITH FLOURISH;Ll;0;L;;;;;N;;;A752;;A752 +A754;LATIN CAPITAL LETTER P WITH SQUIRREL TAIL;Lu;0;L;;;;;N;;;;A755; +A755;LATIN SMALL LETTER P WITH SQUIRREL TAIL;Ll;0;L;;;;;N;;;A754;;A754 +A756;LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A757; +A757;LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A756;;A756 +A758;LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A759; +A759;LATIN SMALL LETTER Q WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A758;;A758 +A75A;LATIN CAPITAL LETTER R ROTUNDA;Lu;0;L;;;;;N;;;;A75B; +A75B;LATIN SMALL LETTER R ROTUNDA;Ll;0;L;;;;;N;;;A75A;;A75A +A75C;LATIN CAPITAL LETTER RUM ROTUNDA;Lu;0;L;;;;;N;;;;A75D; +A75D;LATIN SMALL LETTER RUM ROTUNDA;Ll;0;L;;;;;N;;;A75C;;A75C +A75E;LATIN CAPITAL LETTER V WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A75F; +A75F;LATIN SMALL LETTER V WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A75E;;A75E +A760;LATIN CAPITAL LETTER VY;Lu;0;L;;;;;N;;;;A761; +A761;LATIN SMALL LETTER VY;Ll;0;L;;;;;N;;;A760;;A760 +A762;LATIN CAPITAL LETTER VISIGOTHIC Z;Lu;0;L;;;;;N;;;;A763; +A763;LATIN SMALL LETTER VISIGOTHIC Z;Ll;0;L;;;;;N;;;A762;;A762 +A764;LATIN CAPITAL LETTER THORN WITH STROKE;Lu;0;L;;;;;N;;;;A765; +A765;LATIN SMALL LETTER THORN WITH STROKE;Ll;0;L;;;;;N;;;A764;;A764 +A766;LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A767; +A767;LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A766;;A766 +A768;LATIN CAPITAL LETTER VEND;Lu;0;L;;;;;N;;;;A769; +A769;LATIN SMALL LETTER VEND;Ll;0;L;;;;;N;;;A768;;A768 +A76A;LATIN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;A76B; +A76B;LATIN SMALL LETTER ET;Ll;0;L;;;;;N;;;A76A;;A76A +A76C;LATIN CAPITAL LETTER IS;Lu;0;L;;;;;N;;;;A76D; +A76D;LATIN SMALL LETTER IS;Ll;0;L;;;;;N;;;A76C;;A76C +A76E;LATIN CAPITAL LETTER CON;Lu;0;L;;;;;N;;;;A76F; +A76F;LATIN SMALL LETTER CON;Ll;0;L;;;;;N;;;A76E;;A76E +A770;MODIFIER LETTER US;Lm;0;L;<super> A76F;;;;N;;;;; +A771;LATIN SMALL LETTER DUM;Ll;0;L;;;;;N;;;;; +A772;LATIN SMALL LETTER LUM;Ll;0;L;;;;;N;;;;; +A773;LATIN SMALL LETTER MUM;Ll;0;L;;;;;N;;;;; +A774;LATIN SMALL LETTER NUM;Ll;0;L;;;;;N;;;;; +A775;LATIN SMALL LETTER RUM;Ll;0;L;;;;;N;;;;; +A776;LATIN LETTER SMALL CAPITAL RUM;Ll;0;L;;;;;N;;;;; +A777;LATIN SMALL LETTER TUM;Ll;0;L;;;;;N;;;;; +A778;LATIN SMALL LETTER UM;Ll;0;L;;;;;N;;;;; +A779;LATIN CAPITAL LETTER INSULAR D;Lu;0;L;;;;;N;;;;A77A; +A77A;LATIN SMALL LETTER INSULAR D;Ll;0;L;;;;;N;;;A779;;A779 +A77B;LATIN CAPITAL LETTER INSULAR F;Lu;0;L;;;;;N;;;;A77C; +A77C;LATIN SMALL LETTER INSULAR F;Ll;0;L;;;;;N;;;A77B;;A77B +A77D;LATIN CAPITAL LETTER INSULAR G;Lu;0;L;;;;;N;;;;1D79; +A77E;LATIN CAPITAL LETTER TURNED INSULAR G;Lu;0;L;;;;;N;;;;A77F; +A77F;LATIN SMALL LETTER TURNED INSULAR G;Ll;0;L;;;;;N;;;A77E;;A77E +A780;LATIN CAPITAL LETTER TURNED L;Lu;0;L;;;;;N;;;;A781; +A781;LATIN SMALL LETTER TURNED L;Ll;0;L;;;;;N;;;A780;;A780 +A782;LATIN CAPITAL LETTER INSULAR R;Lu;0;L;;;;;N;;;;A783; +A783;LATIN SMALL LETTER INSULAR R;Ll;0;L;;;;;N;;;A782;;A782 +A784;LATIN CAPITAL LETTER INSULAR S;Lu;0;L;;;;;N;;;;A785; +A785;LATIN SMALL LETTER INSULAR S;Ll;0;L;;;;;N;;;A784;;A784 +A786;LATIN CAPITAL LETTER INSULAR T;Lu;0;L;;;;;N;;;;A787; +A787;LATIN SMALL LETTER INSULAR T;Ll;0;L;;;;;N;;;A786;;A786 +A788;MODIFIER LETTER LOW CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;;;;; +A789;MODIFIER LETTER COLON;Sk;0;L;;;;;N;;;;; +A78A;MODIFIER LETTER SHORT EQUALS SIGN;Sk;0;L;;;;;N;;;;; +A78B;LATIN CAPITAL LETTER SALTILLO;Lu;0;L;;;;;N;;;;A78C; +A78C;LATIN SMALL LETTER SALTILLO;Ll;0;L;;;;;N;;;A78B;;A78B +A7FB;LATIN EPIGRAPHIC LETTER REVERSED F;Lo;0;L;;;;;N;;;;; +A7FC;LATIN EPIGRAPHIC LETTER REVERSED P;Lo;0;L;;;;;N;;;;; +A7FD;LATIN EPIGRAPHIC LETTER INVERTED M;Lo;0;L;;;;;N;;;;; +A7FE;LATIN EPIGRAPHIC LETTER I LONGA;Lo;0;L;;;;;N;;;;; +A7FF;LATIN EPIGRAPHIC LETTER ARCHAIC M;Lo;0;L;;;;;N;;;;; +A800;SYLOTI NAGRI LETTER A;Lo;0;L;;;;;N;;;;; +A801;SYLOTI NAGRI LETTER I;Lo;0;L;;;;;N;;;;; +A802;SYLOTI NAGRI SIGN DVISVARA;Mn;0;NSM;;;;;N;;;;; +A803;SYLOTI NAGRI LETTER U;Lo;0;L;;;;;N;;;;; +A804;SYLOTI NAGRI LETTER E;Lo;0;L;;;;;N;;;;; +A805;SYLOTI NAGRI LETTER O;Lo;0;L;;;;;N;;;;; +A806;SYLOTI NAGRI SIGN HASANTA;Mn;9;NSM;;;;;N;;;;; +A807;SYLOTI NAGRI LETTER KO;Lo;0;L;;;;;N;;;;; +A808;SYLOTI NAGRI LETTER KHO;Lo;0;L;;;;;N;;;;; +A809;SYLOTI NAGRI LETTER GO;Lo;0;L;;;;;N;;;;; +A80A;SYLOTI NAGRI LETTER GHO;Lo;0;L;;;;;N;;;;; +A80B;SYLOTI NAGRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +A80C;SYLOTI NAGRI LETTER CO;Lo;0;L;;;;;N;;;;; +A80D;SYLOTI NAGRI LETTER CHO;Lo;0;L;;;;;N;;;;; +A80E;SYLOTI NAGRI LETTER JO;Lo;0;L;;;;;N;;;;; +A80F;SYLOTI NAGRI LETTER JHO;Lo;0;L;;;;;N;;;;; +A810;SYLOTI NAGRI LETTER TTO;Lo;0;L;;;;;N;;;;; +A811;SYLOTI NAGRI LETTER TTHO;Lo;0;L;;;;;N;;;;; +A812;SYLOTI NAGRI LETTER DDO;Lo;0;L;;;;;N;;;;; +A813;SYLOTI NAGRI LETTER DDHO;Lo;0;L;;;;;N;;;;; +A814;SYLOTI NAGRI LETTER TO;Lo;0;L;;;;;N;;;;; +A815;SYLOTI NAGRI LETTER THO;Lo;0;L;;;;;N;;;;; +A816;SYLOTI NAGRI LETTER DO;Lo;0;L;;;;;N;;;;; +A817;SYLOTI NAGRI LETTER DHO;Lo;0;L;;;;;N;;;;; +A818;SYLOTI NAGRI LETTER NO;Lo;0;L;;;;;N;;;;; +A819;SYLOTI NAGRI LETTER PO;Lo;0;L;;;;;N;;;;; +A81A;SYLOTI NAGRI LETTER PHO;Lo;0;L;;;;;N;;;;; +A81B;SYLOTI NAGRI LETTER BO;Lo;0;L;;;;;N;;;;; +A81C;SYLOTI NAGRI LETTER BHO;Lo;0;L;;;;;N;;;;; +A81D;SYLOTI NAGRI LETTER MO;Lo;0;L;;;;;N;;;;; +A81E;SYLOTI NAGRI LETTER RO;Lo;0;L;;;;;N;;;;; +A81F;SYLOTI NAGRI LETTER LO;Lo;0;L;;;;;N;;;;; +A820;SYLOTI NAGRI LETTER RRO;Lo;0;L;;;;;N;;;;; +A821;SYLOTI NAGRI LETTER SO;Lo;0;L;;;;;N;;;;; +A822;SYLOTI NAGRI LETTER HO;Lo;0;L;;;;;N;;;;; +A823;SYLOTI NAGRI VOWEL SIGN A;Mc;0;L;;;;;N;;;;; +A824;SYLOTI NAGRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +A825;SYLOTI NAGRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +A826;SYLOTI NAGRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +A827;SYLOTI NAGRI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +A828;SYLOTI NAGRI POETRY MARK-1;So;0;ON;;;;;N;;;;; +A829;SYLOTI NAGRI POETRY MARK-2;So;0;ON;;;;;N;;;;; +A82A;SYLOTI NAGRI POETRY MARK-3;So;0;ON;;;;;N;;;;; +A82B;SYLOTI NAGRI POETRY MARK-4;So;0;ON;;;;;N;;;;; +A840;PHAGS-PA LETTER KA;Lo;0;L;;;;;N;;;;; +A841;PHAGS-PA LETTER KHA;Lo;0;L;;;;;N;;;;; +A842;PHAGS-PA LETTER GA;Lo;0;L;;;;;N;;;;; +A843;PHAGS-PA LETTER NGA;Lo;0;L;;;;;N;;;;; +A844;PHAGS-PA LETTER CA;Lo;0;L;;;;;N;;;;; +A845;PHAGS-PA LETTER CHA;Lo;0;L;;;;;N;;;;; +A846;PHAGS-PA LETTER JA;Lo;0;L;;;;;N;;;;; +A847;PHAGS-PA LETTER NYA;Lo;0;L;;;;;N;;;;; +A848;PHAGS-PA LETTER TA;Lo;0;L;;;;;N;;;;; +A849;PHAGS-PA LETTER THA;Lo;0;L;;;;;N;;;;; +A84A;PHAGS-PA LETTER DA;Lo;0;L;;;;;N;;;;; +A84B;PHAGS-PA LETTER NA;Lo;0;L;;;;;N;;;;; +A84C;PHAGS-PA LETTER PA;Lo;0;L;;;;;N;;;;; +A84D;PHAGS-PA LETTER PHA;Lo;0;L;;;;;N;;;;; +A84E;PHAGS-PA LETTER BA;Lo;0;L;;;;;N;;;;; +A84F;PHAGS-PA LETTER MA;Lo;0;L;;;;;N;;;;; +A850;PHAGS-PA LETTER TSA;Lo;0;L;;;;;N;;;;; +A851;PHAGS-PA LETTER TSHA;Lo;0;L;;;;;N;;;;; +A852;PHAGS-PA LETTER DZA;Lo;0;L;;;;;N;;;;; +A853;PHAGS-PA LETTER WA;Lo;0;L;;;;;N;;;;; +A854;PHAGS-PA LETTER ZHA;Lo;0;L;;;;;N;;;;; +A855;PHAGS-PA LETTER ZA;Lo;0;L;;;;;N;;;;; +A856;PHAGS-PA LETTER SMALL A;Lo;0;L;;;;;N;;;;; +A857;PHAGS-PA LETTER YA;Lo;0;L;;;;;N;;;;; +A858;PHAGS-PA LETTER RA;Lo;0;L;;;;;N;;;;; +A859;PHAGS-PA LETTER LA;Lo;0;L;;;;;N;;;;; +A85A;PHAGS-PA LETTER SHA;Lo;0;L;;;;;N;;;;; +A85B;PHAGS-PA LETTER SA;Lo;0;L;;;;;N;;;;; +A85C;PHAGS-PA LETTER HA;Lo;0;L;;;;;N;;;;; +A85D;PHAGS-PA LETTER A;Lo;0;L;;;;;N;;;;; +A85E;PHAGS-PA LETTER I;Lo;0;L;;;;;N;;;;; +A85F;PHAGS-PA LETTER U;Lo;0;L;;;;;N;;;;; +A860;PHAGS-PA LETTER E;Lo;0;L;;;;;N;;;;; +A861;PHAGS-PA LETTER O;Lo;0;L;;;;;N;;;;; +A862;PHAGS-PA LETTER QA;Lo;0;L;;;;;N;;;;; +A863;PHAGS-PA LETTER XA;Lo;0;L;;;;;N;;;;; +A864;PHAGS-PA LETTER FA;Lo;0;L;;;;;N;;;;; +A865;PHAGS-PA LETTER GGA;Lo;0;L;;;;;N;;;;; +A866;PHAGS-PA LETTER EE;Lo;0;L;;;;;N;;;;; +A867;PHAGS-PA SUBJOINED LETTER WA;Lo;0;L;;;;;N;;;;; +A868;PHAGS-PA SUBJOINED LETTER YA;Lo;0;L;;;;;N;;;;; +A869;PHAGS-PA LETTER TTA;Lo;0;L;;;;;N;;;;; +A86A;PHAGS-PA LETTER TTHA;Lo;0;L;;;;;N;;;;; +A86B;PHAGS-PA LETTER DDA;Lo;0;L;;;;;N;;;;; +A86C;PHAGS-PA LETTER NNA;Lo;0;L;;;;;N;;;;; +A86D;PHAGS-PA LETTER ALTERNATE YA;Lo;0;L;;;;;N;;;;; +A86E;PHAGS-PA LETTER VOICELESS SHA;Lo;0;L;;;;;N;;;;; +A86F;PHAGS-PA LETTER VOICED HA;Lo;0;L;;;;;N;;;;; +A870;PHAGS-PA LETTER ASPIRATED FA;Lo;0;L;;;;;N;;;;; +A871;PHAGS-PA SUBJOINED LETTER RA;Lo;0;L;;;;;N;;;;; +A872;PHAGS-PA SUPERFIXED LETTER RA;Lo;0;L;;;;;N;;;;; +A873;PHAGS-PA LETTER CANDRABINDU;Lo;0;L;;;;;N;;;;; +A874;PHAGS-PA SINGLE HEAD MARK;Po;0;ON;;;;;N;;;;; +A875;PHAGS-PA DOUBLE HEAD MARK;Po;0;ON;;;;;N;;;;; +A876;PHAGS-PA MARK SHAD;Po;0;ON;;;;;N;;;;; +A877;PHAGS-PA MARK DOUBLE SHAD;Po;0;ON;;;;;N;;;;; +A880;SAURASHTRA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +A881;SAURASHTRA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +A882;SAURASHTRA LETTER A;Lo;0;L;;;;;N;;;;; +A883;SAURASHTRA LETTER AA;Lo;0;L;;;;;N;;;;; +A884;SAURASHTRA LETTER I;Lo;0;L;;;;;N;;;;; +A885;SAURASHTRA LETTER II;Lo;0;L;;;;;N;;;;; +A886;SAURASHTRA LETTER U;Lo;0;L;;;;;N;;;;; +A887;SAURASHTRA LETTER UU;Lo;0;L;;;;;N;;;;; +A888;SAURASHTRA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +A889;SAURASHTRA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +A88A;SAURASHTRA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +A88B;SAURASHTRA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +A88C;SAURASHTRA LETTER E;Lo;0;L;;;;;N;;;;; +A88D;SAURASHTRA LETTER EE;Lo;0;L;;;;;N;;;;; +A88E;SAURASHTRA LETTER AI;Lo;0;L;;;;;N;;;;; +A88F;SAURASHTRA LETTER O;Lo;0;L;;;;;N;;;;; +A890;SAURASHTRA LETTER OO;Lo;0;L;;;;;N;;;;; +A891;SAURASHTRA LETTER AU;Lo;0;L;;;;;N;;;;; +A892;SAURASHTRA LETTER KA;Lo;0;L;;;;;N;;;;; +A893;SAURASHTRA LETTER KHA;Lo;0;L;;;;;N;;;;; +A894;SAURASHTRA LETTER GA;Lo;0;L;;;;;N;;;;; +A895;SAURASHTRA LETTER GHA;Lo;0;L;;;;;N;;;;; +A896;SAURASHTRA LETTER NGA;Lo;0;L;;;;;N;;;;; +A897;SAURASHTRA LETTER CA;Lo;0;L;;;;;N;;;;; +A898;SAURASHTRA LETTER CHA;Lo;0;L;;;;;N;;;;; +A899;SAURASHTRA LETTER JA;Lo;0;L;;;;;N;;;;; +A89A;SAURASHTRA LETTER JHA;Lo;0;L;;;;;N;;;;; +A89B;SAURASHTRA LETTER NYA;Lo;0;L;;;;;N;;;;; +A89C;SAURASHTRA LETTER TTA;Lo;0;L;;;;;N;;;;; +A89D;SAURASHTRA LETTER TTHA;Lo;0;L;;;;;N;;;;; +A89E;SAURASHTRA LETTER DDA;Lo;0;L;;;;;N;;;;; +A89F;SAURASHTRA LETTER DDHA;Lo;0;L;;;;;N;;;;; +A8A0;SAURASHTRA LETTER NNA;Lo;0;L;;;;;N;;;;; +A8A1;SAURASHTRA LETTER TA;Lo;0;L;;;;;N;;;;; +A8A2;SAURASHTRA LETTER THA;Lo;0;L;;;;;N;;;;; +A8A3;SAURASHTRA LETTER DA;Lo;0;L;;;;;N;;;;; +A8A4;SAURASHTRA LETTER DHA;Lo;0;L;;;;;N;;;;; +A8A5;SAURASHTRA LETTER NA;Lo;0;L;;;;;N;;;;; +A8A6;SAURASHTRA LETTER PA;Lo;0;L;;;;;N;;;;; +A8A7;SAURASHTRA LETTER PHA;Lo;0;L;;;;;N;;;;; +A8A8;SAURASHTRA LETTER BA;Lo;0;L;;;;;N;;;;; +A8A9;SAURASHTRA LETTER BHA;Lo;0;L;;;;;N;;;;; +A8AA;SAURASHTRA LETTER MA;Lo;0;L;;;;;N;;;;; +A8AB;SAURASHTRA LETTER YA;Lo;0;L;;;;;N;;;;; +A8AC;SAURASHTRA LETTER RA;Lo;0;L;;;;;N;;;;; +A8AD;SAURASHTRA LETTER LA;Lo;0;L;;;;;N;;;;; +A8AE;SAURASHTRA LETTER VA;Lo;0;L;;;;;N;;;;; +A8AF;SAURASHTRA LETTER SHA;Lo;0;L;;;;;N;;;;; +A8B0;SAURASHTRA LETTER SSA;Lo;0;L;;;;;N;;;;; +A8B1;SAURASHTRA LETTER SA;Lo;0;L;;;;;N;;;;; +A8B2;SAURASHTRA LETTER HA;Lo;0;L;;;;;N;;;;; +A8B3;SAURASHTRA LETTER LLA;Lo;0;L;;;;;N;;;;; +A8B4;SAURASHTRA CONSONANT SIGN HAARU;Mc;0;L;;;;;N;;;;; +A8B5;SAURASHTRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +A8B6;SAURASHTRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +A8B7;SAURASHTRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +A8B8;SAURASHTRA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +A8B9;SAURASHTRA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +A8BA;SAURASHTRA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +A8BB;SAURASHTRA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +A8BC;SAURASHTRA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;; +A8BD;SAURASHTRA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;; +A8BE;SAURASHTRA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +A8BF;SAURASHTRA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +A8C0;SAURASHTRA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +A8C1;SAURASHTRA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +A8C2;SAURASHTRA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +A8C3;SAURASHTRA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +A8C4;SAURASHTRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +A8CE;SAURASHTRA DANDA;Po;0;L;;;;;N;;;;; +A8CF;SAURASHTRA DOUBLE DANDA;Po;0;L;;;;;N;;;;; +A8D0;SAURASHTRA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +A8D1;SAURASHTRA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +A8D2;SAURASHTRA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +A8D3;SAURASHTRA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +A8D4;SAURASHTRA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +A8D5;SAURASHTRA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +A8D6;SAURASHTRA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +A8D7;SAURASHTRA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +A8D8;SAURASHTRA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +A8D9;SAURASHTRA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +A903;KAYAH LI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +A904;KAYAH LI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +A905;KAYAH LI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +A906;KAYAH LI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +A907;KAYAH LI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +A908;KAYAH LI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +A909;KAYAH LI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +A90A;KAYAH LI LETTER KA;Lo;0;L;;;;;N;;;;; +A90B;KAYAH LI LETTER KHA;Lo;0;L;;;;;N;;;;; +A90C;KAYAH LI LETTER GA;Lo;0;L;;;;;N;;;;; +A90D;KAYAH LI LETTER NGA;Lo;0;L;;;;;N;;;;; +A90E;KAYAH LI LETTER SA;Lo;0;L;;;;;N;;;;; +A90F;KAYAH LI LETTER SHA;Lo;0;L;;;;;N;;;;; +A910;KAYAH LI LETTER ZA;Lo;0;L;;;;;N;;;;; +A911;KAYAH LI LETTER NYA;Lo;0;L;;;;;N;;;;; +A912;KAYAH LI LETTER TA;Lo;0;L;;;;;N;;;;; +A913;KAYAH LI LETTER HTA;Lo;0;L;;;;;N;;;;; +A914;KAYAH LI LETTER NA;Lo;0;L;;;;;N;;;;; +A915;KAYAH LI LETTER PA;Lo;0;L;;;;;N;;;;; +A916;KAYAH LI LETTER PHA;Lo;0;L;;;;;N;;;;; +A917;KAYAH LI LETTER MA;Lo;0;L;;;;;N;;;;; +A918;KAYAH LI LETTER DA;Lo;0;L;;;;;N;;;;; +A919;KAYAH LI LETTER BA;Lo;0;L;;;;;N;;;;; +A91A;KAYAH LI LETTER RA;Lo;0;L;;;;;N;;;;; +A91B;KAYAH LI LETTER YA;Lo;0;L;;;;;N;;;;; +A91C;KAYAH LI LETTER LA;Lo;0;L;;;;;N;;;;; +A91D;KAYAH LI LETTER WA;Lo;0;L;;;;;N;;;;; +A91E;KAYAH LI LETTER THA;Lo;0;L;;;;;N;;;;; +A91F;KAYAH LI LETTER HA;Lo;0;L;;;;;N;;;;; +A920;KAYAH LI LETTER VA;Lo;0;L;;;;;N;;;;; +A921;KAYAH LI LETTER CA;Lo;0;L;;;;;N;;;;; +A922;KAYAH LI LETTER A;Lo;0;L;;;;;N;;;;; +A923;KAYAH LI LETTER OE;Lo;0;L;;;;;N;;;;; +A924;KAYAH LI LETTER I;Lo;0;L;;;;;N;;;;; +A925;KAYAH LI LETTER OO;Lo;0;L;;;;;N;;;;; +A926;KAYAH LI VOWEL UE;Mn;0;NSM;;;;;N;;;;; +A927;KAYAH LI VOWEL E;Mn;0;NSM;;;;;N;;;;; +A928;KAYAH LI VOWEL U;Mn;0;NSM;;;;;N;;;;; +A929;KAYAH LI VOWEL EE;Mn;0;NSM;;;;;N;;;;; +A92A;KAYAH LI VOWEL O;Mn;0;NSM;;;;;N;;;;; +A92B;KAYAH LI TONE PLOPHU;Mn;220;NSM;;;;;N;;;;; +A92C;KAYAH LI TONE CALYA;Mn;220;NSM;;;;;N;;;;; +A92D;KAYAH LI TONE CALYA PLOPHU;Mn;220;NSM;;;;;N;;;;; +A92E;KAYAH LI SIGN CWI;Po;0;L;;;;;N;;;;; +A92F;KAYAH LI SIGN SHYA;Po;0;L;;;;;N;;;;; +A930;REJANG LETTER KA;Lo;0;L;;;;;N;;;;; +A931;REJANG LETTER GA;Lo;0;L;;;;;N;;;;; +A932;REJANG LETTER NGA;Lo;0;L;;;;;N;;;;; +A933;REJANG LETTER TA;Lo;0;L;;;;;N;;;;; +A934;REJANG LETTER DA;Lo;0;L;;;;;N;;;;; +A935;REJANG LETTER NA;Lo;0;L;;;;;N;;;;; +A936;REJANG LETTER PA;Lo;0;L;;;;;N;;;;; +A937;REJANG LETTER BA;Lo;0;L;;;;;N;;;;; +A938;REJANG LETTER MA;Lo;0;L;;;;;N;;;;; +A939;REJANG LETTER CA;Lo;0;L;;;;;N;;;;; +A93A;REJANG LETTER JA;Lo;0;L;;;;;N;;;;; +A93B;REJANG LETTER NYA;Lo;0;L;;;;;N;;;;; +A93C;REJANG LETTER SA;Lo;0;L;;;;;N;;;;; +A93D;REJANG LETTER RA;Lo;0;L;;;;;N;;;;; +A93E;REJANG LETTER LA;Lo;0;L;;;;;N;;;;; +A93F;REJANG LETTER YA;Lo;0;L;;;;;N;;;;; +A940;REJANG LETTER WA;Lo;0;L;;;;;N;;;;; +A941;REJANG LETTER HA;Lo;0;L;;;;;N;;;;; +A942;REJANG LETTER MBA;Lo;0;L;;;;;N;;;;; +A943;REJANG LETTER NGGA;Lo;0;L;;;;;N;;;;; +A944;REJANG LETTER NDA;Lo;0;L;;;;;N;;;;; +A945;REJANG LETTER NYJA;Lo;0;L;;;;;N;;;;; +A946;REJANG LETTER A;Lo;0;L;;;;;N;;;;; +A947;REJANG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +A948;REJANG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +A949;REJANG VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +A94A;REJANG VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +A94B;REJANG VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +A94C;REJANG VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +A94D;REJANG VOWEL SIGN EU;Mn;0;NSM;;;;;N;;;;; +A94E;REJANG VOWEL SIGN EA;Mn;0;NSM;;;;;N;;;;; +A94F;REJANG CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;; +A950;REJANG CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;; +A951;REJANG CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;; +A952;REJANG CONSONANT SIGN H;Mc;0;L;;;;;N;;;;; +A953;REJANG VIRAMA;Mc;9;L;;;;;N;;;;; +A95F;REJANG SECTION MARK;Po;0;L;;;;;N;;;;; +AA00;CHAM LETTER A;Lo;0;L;;;;;N;;;;; +AA01;CHAM LETTER I;Lo;0;L;;;;;N;;;;; +AA02;CHAM LETTER U;Lo;0;L;;;;;N;;;;; +AA03;CHAM LETTER E;Lo;0;L;;;;;N;;;;; +AA04;CHAM LETTER AI;Lo;0;L;;;;;N;;;;; +AA05;CHAM LETTER O;Lo;0;L;;;;;N;;;;; +AA06;CHAM LETTER KA;Lo;0;L;;;;;N;;;;; +AA07;CHAM LETTER KHA;Lo;0;L;;;;;N;;;;; +AA08;CHAM LETTER GA;Lo;0;L;;;;;N;;;;; +AA09;CHAM LETTER GHA;Lo;0;L;;;;;N;;;;; +AA0A;CHAM LETTER NGUE;Lo;0;L;;;;;N;;;;; +AA0B;CHAM LETTER NGA;Lo;0;L;;;;;N;;;;; +AA0C;CHAM LETTER CHA;Lo;0;L;;;;;N;;;;; +AA0D;CHAM LETTER CHHA;Lo;0;L;;;;;N;;;;; +AA0E;CHAM LETTER JA;Lo;0;L;;;;;N;;;;; +AA0F;CHAM LETTER JHA;Lo;0;L;;;;;N;;;;; +AA10;CHAM LETTER NHUE;Lo;0;L;;;;;N;;;;; +AA11;CHAM LETTER NHA;Lo;0;L;;;;;N;;;;; +AA12;CHAM LETTER NHJA;Lo;0;L;;;;;N;;;;; +AA13;CHAM LETTER TA;Lo;0;L;;;;;N;;;;; +AA14;CHAM LETTER THA;Lo;0;L;;;;;N;;;;; +AA15;CHAM LETTER DA;Lo;0;L;;;;;N;;;;; +AA16;CHAM LETTER DHA;Lo;0;L;;;;;N;;;;; +AA17;CHAM LETTER NUE;Lo;0;L;;;;;N;;;;; +AA18;CHAM LETTER NA;Lo;0;L;;;;;N;;;;; +AA19;CHAM LETTER DDA;Lo;0;L;;;;;N;;;;; +AA1A;CHAM LETTER PA;Lo;0;L;;;;;N;;;;; +AA1B;CHAM LETTER PPA;Lo;0;L;;;;;N;;;;; +AA1C;CHAM LETTER PHA;Lo;0;L;;;;;N;;;;; +AA1D;CHAM LETTER BA;Lo;0;L;;;;;N;;;;; +AA1E;CHAM LETTER BHA;Lo;0;L;;;;;N;;;;; +AA1F;CHAM LETTER MUE;Lo;0;L;;;;;N;;;;; +AA20;CHAM LETTER MA;Lo;0;L;;;;;N;;;;; +AA21;CHAM LETTER BBA;Lo;0;L;;;;;N;;;;; +AA22;CHAM LETTER YA;Lo;0;L;;;;;N;;;;; +AA23;CHAM LETTER RA;Lo;0;L;;;;;N;;;;; +AA24;CHAM LETTER LA;Lo;0;L;;;;;N;;;;; +AA25;CHAM LETTER VA;Lo;0;L;;;;;N;;;;; +AA26;CHAM LETTER SSA;Lo;0;L;;;;;N;;;;; +AA27;CHAM LETTER SA;Lo;0;L;;;;;N;;;;; +AA28;CHAM LETTER HA;Lo;0;L;;;;;N;;;;; +AA29;CHAM VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +AA2A;CHAM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +AA2B;CHAM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +AA2C;CHAM VOWEL SIGN EI;Mn;0;NSM;;;;;N;;;;; +AA2D;CHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +AA2E;CHAM VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +AA2F;CHAM VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +AA30;CHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +AA31;CHAM VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +AA32;CHAM VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +AA33;CHAM CONSONANT SIGN YA;Mc;0;L;;;;;N;;;;; +AA34;CHAM CONSONANT SIGN RA;Mc;0;L;;;;;N;;;;; +AA35;CHAM CONSONANT SIGN LA;Mn;0;NSM;;;;;N;;;;; +AA36;CHAM CONSONANT SIGN WA;Mn;0;NSM;;;;;N;;;;; +AA40;CHAM LETTER FINAL K;Lo;0;L;;;;;N;;;;; +AA41;CHAM LETTER FINAL G;Lo;0;L;;;;;N;;;;; +AA42;CHAM LETTER FINAL NG;Lo;0;L;;;;;N;;;;; +AA43;CHAM CONSONANT SIGN FINAL NG;Mn;0;NSM;;;;;N;;;;; +AA44;CHAM LETTER FINAL CH;Lo;0;L;;;;;N;;;;; +AA45;CHAM LETTER FINAL T;Lo;0;L;;;;;N;;;;; +AA46;CHAM LETTER FINAL N;Lo;0;L;;;;;N;;;;; +AA47;CHAM LETTER FINAL P;Lo;0;L;;;;;N;;;;; +AA48;CHAM LETTER FINAL Y;Lo;0;L;;;;;N;;;;; +AA49;CHAM LETTER FINAL R;Lo;0;L;;;;;N;;;;; +AA4A;CHAM LETTER FINAL L;Lo;0;L;;;;;N;;;;; +AA4B;CHAM LETTER FINAL SS;Lo;0;L;;;;;N;;;;; +AA4C;CHAM CONSONANT SIGN FINAL M;Mn;0;NSM;;;;;N;;;;; +AA4D;CHAM CONSONANT SIGN FINAL H;Mc;0;L;;;;;N;;;;; +AA50;CHAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +AA51;CHAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +AA52;CHAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +AA53;CHAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +AA54;CHAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +AA55;CHAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +AA56;CHAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +AA57;CHAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +AA58;CHAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +AA59;CHAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +AA5C;CHAM PUNCTUATION SPIRAL;Po;0;L;;;;;N;;;;; +AA5D;CHAM PUNCTUATION DANDA;Po;0;L;;;;;N;;;;; +AA5E;CHAM PUNCTUATION DOUBLE DANDA;Po;0;L;;;;;N;;;;; +AA5F;CHAM PUNCTUATION TRIPLE DANDA;Po;0;L;;;;;N;;;;; AC00;<Hangul Syllable, First>;Lo;0;L;;;;;N;;;;; D7A3;<Hangul Syllable, Last>;Lo;0;L;;;;;N;;;;; D800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;; @@ -10729,7 +13247,7 @@ F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;; F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;; F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;; F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;; -F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;;N;;;;; +F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;3;N;;;;; F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;; F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;; F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;; @@ -10737,12 +13255,12 @@ F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;; F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;; F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;; F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;; -F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;;N;;;;; +F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;10;N;;;;; F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;; F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;; F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;; F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;; -F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;;N;;;;; +F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;2;N;;;;; F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;; F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;; F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;; @@ -10800,7 +13318,7 @@ F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;; F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;; F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;; F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;; -F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;;N;;;;; +F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;0;N;;;;; F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;; F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;; F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;; @@ -10831,9 +13349,9 @@ F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;; F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;; F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;; F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;; -F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;;N;;;;; +F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;6;N;;;;; F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;; -F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;;N;;;;; +F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;6;N;;;;; F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;; F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;; F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;; @@ -10875,7 +13393,7 @@ F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;; F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;; F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;; F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;; -F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;;N;;;;; +F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;10;N;;;;; F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;; F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;; FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;; @@ -10983,6 +13501,112 @@ FA67;CJK COMPATIBILITY IDEOGRAPH-FA67;Lo;0;L;9038;;;;N;;;;; FA68;CJK COMPATIBILITY IDEOGRAPH-FA68;Lo;0;L;96E3;;;;N;;;;; FA69;CJK COMPATIBILITY IDEOGRAPH-FA69;Lo;0;L;97FF;;;;N;;;;; FA6A;CJK COMPATIBILITY IDEOGRAPH-FA6A;Lo;0;L;983B;;;;N;;;;; +FA70;CJK COMPATIBILITY IDEOGRAPH-FA70;Lo;0;L;4E26;;;;N;;;;; +FA71;CJK COMPATIBILITY IDEOGRAPH-FA71;Lo;0;L;51B5;;;;N;;;;; +FA72;CJK COMPATIBILITY IDEOGRAPH-FA72;Lo;0;L;5168;;;;N;;;;; +FA73;CJK COMPATIBILITY IDEOGRAPH-FA73;Lo;0;L;4F80;;;;N;;;;; +FA74;CJK COMPATIBILITY IDEOGRAPH-FA74;Lo;0;L;5145;;;;N;;;;; +FA75;CJK COMPATIBILITY IDEOGRAPH-FA75;Lo;0;L;5180;;;;N;;;;; +FA76;CJK COMPATIBILITY IDEOGRAPH-FA76;Lo;0;L;52C7;;;;N;;;;; +FA77;CJK COMPATIBILITY IDEOGRAPH-FA77;Lo;0;L;52FA;;;;N;;;;; +FA78;CJK COMPATIBILITY IDEOGRAPH-FA78;Lo;0;L;559D;;;;N;;;;; +FA79;CJK COMPATIBILITY IDEOGRAPH-FA79;Lo;0;L;5555;;;;N;;;;; +FA7A;CJK COMPATIBILITY IDEOGRAPH-FA7A;Lo;0;L;5599;;;;N;;;;; +FA7B;CJK COMPATIBILITY IDEOGRAPH-FA7B;Lo;0;L;55E2;;;;N;;;;; +FA7C;CJK COMPATIBILITY IDEOGRAPH-FA7C;Lo;0;L;585A;;;;N;;;;; +FA7D;CJK COMPATIBILITY IDEOGRAPH-FA7D;Lo;0;L;58B3;;;;N;;;;; +FA7E;CJK COMPATIBILITY IDEOGRAPH-FA7E;Lo;0;L;5944;;;;N;;;;; +FA7F;CJK COMPATIBILITY IDEOGRAPH-FA7F;Lo;0;L;5954;;;;N;;;;; +FA80;CJK COMPATIBILITY IDEOGRAPH-FA80;Lo;0;L;5A62;;;;N;;;;; +FA81;CJK COMPATIBILITY IDEOGRAPH-FA81;Lo;0;L;5B28;;;;N;;;;; +FA82;CJK COMPATIBILITY IDEOGRAPH-FA82;Lo;0;L;5ED2;;;;N;;;;; +FA83;CJK COMPATIBILITY IDEOGRAPH-FA83;Lo;0;L;5ED9;;;;N;;;;; +FA84;CJK COMPATIBILITY IDEOGRAPH-FA84;Lo;0;L;5F69;;;;N;;;;; +FA85;CJK COMPATIBILITY IDEOGRAPH-FA85;Lo;0;L;5FAD;;;;N;;;;; +FA86;CJK COMPATIBILITY IDEOGRAPH-FA86;Lo;0;L;60D8;;;;N;;;;; +FA87;CJK COMPATIBILITY IDEOGRAPH-FA87;Lo;0;L;614E;;;;N;;;;; +FA88;CJK COMPATIBILITY IDEOGRAPH-FA88;Lo;0;L;6108;;;;N;;;;; +FA89;CJK COMPATIBILITY IDEOGRAPH-FA89;Lo;0;L;618E;;;;N;;;;; +FA8A;CJK COMPATIBILITY IDEOGRAPH-FA8A;Lo;0;L;6160;;;;N;;;;; +FA8B;CJK COMPATIBILITY IDEOGRAPH-FA8B;Lo;0;L;61F2;;;;N;;;;; +FA8C;CJK COMPATIBILITY IDEOGRAPH-FA8C;Lo;0;L;6234;;;;N;;;;; +FA8D;CJK COMPATIBILITY IDEOGRAPH-FA8D;Lo;0;L;63C4;;;;N;;;;; +FA8E;CJK COMPATIBILITY IDEOGRAPH-FA8E;Lo;0;L;641C;;;;N;;;;; +FA8F;CJK COMPATIBILITY IDEOGRAPH-FA8F;Lo;0;L;6452;;;;N;;;;; +FA90;CJK COMPATIBILITY IDEOGRAPH-FA90;Lo;0;L;6556;;;;N;;;;; +FA91;CJK COMPATIBILITY IDEOGRAPH-FA91;Lo;0;L;6674;;;;N;;;;; +FA92;CJK COMPATIBILITY IDEOGRAPH-FA92;Lo;0;L;6717;;;;N;;;;; +FA93;CJK COMPATIBILITY IDEOGRAPH-FA93;Lo;0;L;671B;;;;N;;;;; +FA94;CJK COMPATIBILITY IDEOGRAPH-FA94;Lo;0;L;6756;;;;N;;;;; +FA95;CJK COMPATIBILITY IDEOGRAPH-FA95;Lo;0;L;6B79;;;;N;;;;; +FA96;CJK COMPATIBILITY IDEOGRAPH-FA96;Lo;0;L;6BBA;;;;N;;;;; +FA97;CJK COMPATIBILITY IDEOGRAPH-FA97;Lo;0;L;6D41;;;;N;;;;; +FA98;CJK COMPATIBILITY IDEOGRAPH-FA98;Lo;0;L;6EDB;;;;N;;;;; +FA99;CJK COMPATIBILITY IDEOGRAPH-FA99;Lo;0;L;6ECB;;;;N;;;;; +FA9A;CJK COMPATIBILITY IDEOGRAPH-FA9A;Lo;0;L;6F22;;;;N;;;;; +FA9B;CJK COMPATIBILITY IDEOGRAPH-FA9B;Lo;0;L;701E;;;;N;;;;; +FA9C;CJK COMPATIBILITY IDEOGRAPH-FA9C;Lo;0;L;716E;;;;N;;;;; +FA9D;CJK COMPATIBILITY IDEOGRAPH-FA9D;Lo;0;L;77A7;;;;N;;;;; +FA9E;CJK COMPATIBILITY IDEOGRAPH-FA9E;Lo;0;L;7235;;;;N;;;;; +FA9F;CJK COMPATIBILITY IDEOGRAPH-FA9F;Lo;0;L;72AF;;;;N;;;;; +FAA0;CJK COMPATIBILITY IDEOGRAPH-FAA0;Lo;0;L;732A;;;;N;;;;; +FAA1;CJK COMPATIBILITY IDEOGRAPH-FAA1;Lo;0;L;7471;;;;N;;;;; +FAA2;CJK COMPATIBILITY IDEOGRAPH-FAA2;Lo;0;L;7506;;;;N;;;;; +FAA3;CJK COMPATIBILITY IDEOGRAPH-FAA3;Lo;0;L;753B;;;;N;;;;; +FAA4;CJK COMPATIBILITY IDEOGRAPH-FAA4;Lo;0;L;761D;;;;N;;;;; +FAA5;CJK COMPATIBILITY IDEOGRAPH-FAA5;Lo;0;L;761F;;;;N;;;;; +FAA6;CJK COMPATIBILITY IDEOGRAPH-FAA6;Lo;0;L;76CA;;;;N;;;;; +FAA7;CJK COMPATIBILITY IDEOGRAPH-FAA7;Lo;0;L;76DB;;;;N;;;;; +FAA8;CJK COMPATIBILITY IDEOGRAPH-FAA8;Lo;0;L;76F4;;;;N;;;;; +FAA9;CJK COMPATIBILITY IDEOGRAPH-FAA9;Lo;0;L;774A;;;;N;;;;; +FAAA;CJK COMPATIBILITY IDEOGRAPH-FAAA;Lo;0;L;7740;;;;N;;;;; +FAAB;CJK COMPATIBILITY IDEOGRAPH-FAAB;Lo;0;L;78CC;;;;N;;;;; +FAAC;CJK COMPATIBILITY IDEOGRAPH-FAAC;Lo;0;L;7AB1;;;;N;;;;; +FAAD;CJK COMPATIBILITY IDEOGRAPH-FAAD;Lo;0;L;7BC0;;;;N;;;;; +FAAE;CJK COMPATIBILITY IDEOGRAPH-FAAE;Lo;0;L;7C7B;;;;N;;;;; +FAAF;CJK COMPATIBILITY IDEOGRAPH-FAAF;Lo;0;L;7D5B;;;;N;;;;; +FAB0;CJK COMPATIBILITY IDEOGRAPH-FAB0;Lo;0;L;7DF4;;;;N;;;;; +FAB1;CJK COMPATIBILITY IDEOGRAPH-FAB1;Lo;0;L;7F3E;;;;N;;;;; +FAB2;CJK COMPATIBILITY IDEOGRAPH-FAB2;Lo;0;L;8005;;;;N;;;;; +FAB3;CJK COMPATIBILITY IDEOGRAPH-FAB3;Lo;0;L;8352;;;;N;;;;; +FAB4;CJK COMPATIBILITY IDEOGRAPH-FAB4;Lo;0;L;83EF;;;;N;;;;; +FAB5;CJK COMPATIBILITY IDEOGRAPH-FAB5;Lo;0;L;8779;;;;N;;;;; +FAB6;CJK COMPATIBILITY IDEOGRAPH-FAB6;Lo;0;L;8941;;;;N;;;;; +FAB7;CJK COMPATIBILITY IDEOGRAPH-FAB7;Lo;0;L;8986;;;;N;;;;; +FAB8;CJK COMPATIBILITY IDEOGRAPH-FAB8;Lo;0;L;8996;;;;N;;;;; +FAB9;CJK COMPATIBILITY IDEOGRAPH-FAB9;Lo;0;L;8ABF;;;;N;;;;; +FABA;CJK COMPATIBILITY IDEOGRAPH-FABA;Lo;0;L;8AF8;;;;N;;;;; +FABB;CJK COMPATIBILITY IDEOGRAPH-FABB;Lo;0;L;8ACB;;;;N;;;;; +FABC;CJK COMPATIBILITY IDEOGRAPH-FABC;Lo;0;L;8B01;;;;N;;;;; +FABD;CJK COMPATIBILITY IDEOGRAPH-FABD;Lo;0;L;8AFE;;;;N;;;;; +FABE;CJK COMPATIBILITY IDEOGRAPH-FABE;Lo;0;L;8AED;;;;N;;;;; +FABF;CJK COMPATIBILITY IDEOGRAPH-FABF;Lo;0;L;8B39;;;;N;;;;; +FAC0;CJK COMPATIBILITY IDEOGRAPH-FAC0;Lo;0;L;8B8A;;;;N;;;;; +FAC1;CJK COMPATIBILITY IDEOGRAPH-FAC1;Lo;0;L;8D08;;;;N;;;;; +FAC2;CJK COMPATIBILITY IDEOGRAPH-FAC2;Lo;0;L;8F38;;;;N;;;;; +FAC3;CJK COMPATIBILITY IDEOGRAPH-FAC3;Lo;0;L;9072;;;;N;;;;; +FAC4;CJK COMPATIBILITY IDEOGRAPH-FAC4;Lo;0;L;9199;;;;N;;;;; +FAC5;CJK COMPATIBILITY IDEOGRAPH-FAC5;Lo;0;L;9276;;;;N;;;;; +FAC6;CJK COMPATIBILITY IDEOGRAPH-FAC6;Lo;0;L;967C;;;;N;;;;; +FAC7;CJK COMPATIBILITY IDEOGRAPH-FAC7;Lo;0;L;96E3;;;;N;;;;; +FAC8;CJK COMPATIBILITY IDEOGRAPH-FAC8;Lo;0;L;9756;;;;N;;;;; +FAC9;CJK COMPATIBILITY IDEOGRAPH-FAC9;Lo;0;L;97DB;;;;N;;;;; +FACA;CJK COMPATIBILITY IDEOGRAPH-FACA;Lo;0;L;97FF;;;;N;;;;; +FACB;CJK COMPATIBILITY IDEOGRAPH-FACB;Lo;0;L;980B;;;;N;;;;; +FACC;CJK COMPATIBILITY IDEOGRAPH-FACC;Lo;0;L;983B;;;;N;;;;; +FACD;CJK COMPATIBILITY IDEOGRAPH-FACD;Lo;0;L;9B12;;;;N;;;;; +FACE;CJK COMPATIBILITY IDEOGRAPH-FACE;Lo;0;L;9F9C;;;;N;;;;; +FACF;CJK COMPATIBILITY IDEOGRAPH-FACF;Lo;0;L;2284A;;;;N;;;;; +FAD0;CJK COMPATIBILITY IDEOGRAPH-FAD0;Lo;0;L;22844;;;;N;;;;; +FAD1;CJK COMPATIBILITY IDEOGRAPH-FAD1;Lo;0;L;233D5;;;;N;;;;; +FAD2;CJK COMPATIBILITY IDEOGRAPH-FAD2;Lo;0;L;3B9D;;;;N;;;;; +FAD3;CJK COMPATIBILITY IDEOGRAPH-FAD3;Lo;0;L;4018;;;;N;;;;; +FAD4;CJK COMPATIBILITY IDEOGRAPH-FAD4;Lo;0;L;4039;;;;N;;;;; +FAD5;CJK COMPATIBILITY IDEOGRAPH-FAD5;Lo;0;L;25249;;;;N;;;;; +FAD6;CJK COMPATIBILITY IDEOGRAPH-FAD6;Lo;0;L;25CD0;;;;N;;;;; +FAD7;CJK COMPATIBILITY IDEOGRAPH-FAD7;Lo;0;L;27ED3;;;;N;;;;; +FAD8;CJK COMPATIBILITY IDEOGRAPH-FAD8;Lo;0;L;9F43;;;;N;;;;; +FAD9;CJK COMPATIBILITY IDEOGRAPH-FAD9;Lo;0;L;9F8E;;;;N;;;;; FB00;LATIN SMALL LIGATURE FF;Ll;0;L;<compat> 0066 0066;;;;N;;;;; FB01;LATIN SMALL LIGATURE FI;Ll;0;L;<compat> 0066 0069;;;;N;;;;; FB02;LATIN SMALL LIGATURE FL;Ll;0;L;<compat> 0066 006C;;;;N;;;;; @@ -11007,7 +13631,7 @@ FB25;HEBREW LETTER WIDE LAMED;Lo;0;R;<font> 05DC;;;;N;;;;; FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R;<font> 05DD;;;;N;;;;; FB27;HEBREW LETTER WIDE RESH;Lo;0;R;<font> 05E8;;;;N;;;;; FB28;HEBREW LETTER WIDE TAV;Lo;0;R;<font> 05EA;;;;N;;;;; -FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ET;<font> 002B;;;;N;;;;; +FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ES;<font> 002B;;;;N;;;;; FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;; FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;; FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;; @@ -11652,10 +14276,23 @@ FE0C;VARIATION SELECTOR-13;Mn;0;NSM;;;;;N;;;;; FE0D;VARIATION SELECTOR-14;Mn;0;NSM;;;;;N;;;;; FE0E;VARIATION SELECTOR-15;Mn;0;NSM;;;;;N;;;;; FE0F;VARIATION SELECTOR-16;Mn;0;NSM;;;;;N;;;;; +FE10;PRESENTATION FORM FOR VERTICAL COMMA;Po;0;ON;<vertical> 002C;;;;N;;;;; +FE11;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA;Po;0;ON;<vertical> 3001;;;;N;;;;; +FE12;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP;Po;0;ON;<vertical> 3002;;;;N;;;;; +FE13;PRESENTATION FORM FOR VERTICAL COLON;Po;0;ON;<vertical> 003A;;;;N;;;;; +FE14;PRESENTATION FORM FOR VERTICAL SEMICOLON;Po;0;ON;<vertical> 003B;;;;N;;;;; +FE15;PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK;Po;0;ON;<vertical> 0021;;;;N;;;;; +FE16;PRESENTATION FORM FOR VERTICAL QUESTION MARK;Po;0;ON;<vertical> 003F;;;;N;;;;; +FE17;PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;<vertical> 3016;;;;N;;;;; +FE18;PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET;Pe;0;ON;<vertical> 3017;;;;N;;;;; +FE19;PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS;Po;0;ON;<vertical> 2026;;;;N;;;;; FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;; FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;; FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE24;COMBINING MACRON LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE25;COMBINING MACRON RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE26;COMBINING CONJOINING MACRON;Mn;230;NSM;;;;;N;;;;; FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON;<vertical> 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;; FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON;<vertical> 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;; FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON;<vertical> 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;; @@ -11696,19 +14333,19 @@ FE55;SMALL COLON;Po;0;CS;<small> 003A;;;;N;;;;; FE56;SMALL QUESTION MARK;Po;0;ON;<small> 003F;;;;N;;;;; FE57;SMALL EXCLAMATION MARK;Po;0;ON;<small> 0021;;;;N;;;;; FE58;SMALL EM DASH;Pd;0;ON;<small> 2014;;;;N;;;;; -FE59;SMALL LEFT PARENTHESIS;Ps;0;ON;<small> 0028;;;;N;SMALL OPENING PARENTHESIS;;;; -FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON;<small> 0029;;;;N;SMALL CLOSING PARENTHESIS;;;; -FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON;<small> 007B;;;;N;SMALL OPENING CURLY BRACKET;;;; -FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON;<small> 007D;;;;N;SMALL CLOSING CURLY BRACKET;;;; -FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<small> 3014;;;;N;SMALL OPENING TORTOISE SHELL BRACKET;;;; -FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<small> 3015;;;;N;SMALL CLOSING TORTOISE SHELL BRACKET;;;; +FE59;SMALL LEFT PARENTHESIS;Ps;0;ON;<small> 0028;;;;Y;SMALL OPENING PARENTHESIS;;;; +FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON;<small> 0029;;;;Y;SMALL CLOSING PARENTHESIS;;;; +FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON;<small> 007B;;;;Y;SMALL OPENING CURLY BRACKET;;;; +FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON;<small> 007D;;;;Y;SMALL CLOSING CURLY BRACKET;;;; +FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<small> 3014;;;;Y;SMALL OPENING TORTOISE SHELL BRACKET;;;; +FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<small> 3015;;;;Y;SMALL CLOSING TORTOISE SHELL BRACKET;;;; FE5F;SMALL NUMBER SIGN;Po;0;ET;<small> 0023;;;;N;;;;; FE60;SMALL AMPERSAND;Po;0;ON;<small> 0026;;;;N;;;;; FE61;SMALL ASTERISK;Po;0;ON;<small> 002A;;;;N;;;;; -FE62;SMALL PLUS SIGN;Sm;0;ET;<small> 002B;;;;N;;;;; -FE63;SMALL HYPHEN-MINUS;Pd;0;ET;<small> 002D;;;;N;;;;; -FE64;SMALL LESS-THAN SIGN;Sm;0;ON;<small> 003C;;;;N;;;;; -FE65;SMALL GREATER-THAN SIGN;Sm;0;ON;<small> 003E;;;;N;;;;; +FE62;SMALL PLUS SIGN;Sm;0;ES;<small> 002B;;;;N;;;;; +FE63;SMALL HYPHEN-MINUS;Pd;0;ES;<small> 002D;;;;N;;;;; +FE64;SMALL LESS-THAN SIGN;Sm;0;ON;<small> 003C;;;;Y;;;;; +FE65;SMALL GREATER-THAN SIGN;Sm;0;ON;<small> 003E;;;;Y;;;;; FE66;SMALL EQUALS SIGN;Sm;0;ON;<small> 003D;;;;N;;;;; FE68;SMALL REVERSE SOLIDUS;Po;0;ON;<small> 005C;;;;N;SMALL BACKSLASH;;;; FE69;SMALL DOLLAR SIGN;Sc;0;ET;<small> 0024;;;;N;;;;; @@ -11865,11 +14502,11 @@ FF07;FULLWIDTH APOSTROPHE;Po;0;ON;<wide> 0027;;;;N;;;;; FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON;<wide> 0028;;;;Y;FULLWIDTH OPENING PARENTHESIS;;;; FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON;<wide> 0029;;;;Y;FULLWIDTH CLOSING PARENTHESIS;;;; FF0A;FULLWIDTH ASTERISK;Po;0;ON;<wide> 002A;;;;N;;;;; -FF0B;FULLWIDTH PLUS SIGN;Sm;0;ET;<wide> 002B;;;;N;;;;; +FF0B;FULLWIDTH PLUS SIGN;Sm;0;ES;<wide> 002B;;;;N;;;;; FF0C;FULLWIDTH COMMA;Po;0;CS;<wide> 002C;;;;N;;;;; -FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ET;<wide> 002D;;;;N;;;;; +FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ES;<wide> 002D;;;;N;;;;; FF0E;FULLWIDTH FULL STOP;Po;0;CS;<wide> 002E;;;;N;FULLWIDTH PERIOD;;;; -FF0F;FULLWIDTH SOLIDUS;Po;0;ES;<wide> 002F;;;;N;FULLWIDTH SLASH;;;; +FF0F;FULLWIDTH SOLIDUS;Po;0;CS;<wide> 002F;;;;N;FULLWIDTH SLASH;;;; FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;; FF11;FULLWIDTH DIGIT ONE;Nd;0;EN;<wide> 0031;1;1;1;N;;;;; FF12;FULLWIDTH DIGIT TWO;Nd;0;EN;<wide> 0032;2;2;2;N;;;;; @@ -11955,7 +14592,7 @@ FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON;<narrow> 3002;;;;N;HALFWIDTH IDEOGR FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON;<narrow> 300C;;;;Y;HALFWIDTH OPENING CORNER BRACKET;;;; FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON;<narrow> 300D;;;;Y;HALFWIDTH CLOSING CORNER BRACKET;;;; FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON;<narrow> 3001;;;;N;;;;; -FF65;HALFWIDTH KATAKANA MIDDLE DOT;Pc;0;ON;<narrow> 30FB;;;;N;;;;; +FF65;HALFWIDTH KATAKANA MIDDLE DOT;Po;0;ON;<narrow> 30FB;;;;N;;;;; FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L;<narrow> 30F2;;;;N;;;;; FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L;<narrow> 30A1;;;;N;;;;; FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L;<narrow> 30A3;;;;N;;;;; @@ -12080,9 +14717,9 @@ FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON;<narrow> 2192;;;;N;;;;; FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON;<narrow> 2193;;;;N;;;;; FFED;HALFWIDTH BLACK SQUARE;So;0;ON;<narrow> 25A0;;;;N;;;;; FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON;<narrow> 25CB;;;;N;;;;; -FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;BN;;;;;N;;;;; -FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;BN;;;;;N;;;;; -FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;BN;;;;;N;;;;; +FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;ON;;;;;N;;;;; +FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;ON;;;;;N;;;;; +FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;ON;;;;;N;;;;; FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10000;LINEAR B SYLLABLE B008 A;Lo;0;L;;;;;N;;;;; @@ -12353,6 +14990,217 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1013D;AEGEAN LIQUID MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;; 1013E;AEGEAN MEASURE SECOND SUBUNIT;So;0;L;;;;;N;;;;; 1013F;AEGEAN MEASURE THIRD SUBUNIT;So;0;L;;;;;N;;;;; +10140;GREEK ACROPHONIC ATTIC ONE QUARTER;Nl;0;ON;;;;1/4;N;;;;; +10141;GREEK ACROPHONIC ATTIC ONE HALF;Nl;0;ON;;;;1/2;N;;;;; +10142;GREEK ACROPHONIC ATTIC ONE DRACHMA;Nl;0;ON;;;;1;N;;;;; +10143;GREEK ACROPHONIC ATTIC FIVE;Nl;0;ON;;;;5;N;;;;; +10144;GREEK ACROPHONIC ATTIC FIFTY;Nl;0;ON;;;;50;N;;;;; +10145;GREEK ACROPHONIC ATTIC FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +10146;GREEK ACROPHONIC ATTIC FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;; +10147;GREEK ACROPHONIC ATTIC FIFTY THOUSAND;Nl;0;ON;;;;50000;N;;;;; +10148;GREEK ACROPHONIC ATTIC FIVE TALENTS;Nl;0;ON;;;;5;N;;;;; +10149;GREEK ACROPHONIC ATTIC TEN TALENTS;Nl;0;ON;;;;10;N;;;;; +1014A;GREEK ACROPHONIC ATTIC FIFTY TALENTS;Nl;0;ON;;;;50;N;;;;; +1014B;GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS;Nl;0;ON;;;;100;N;;;;; +1014C;GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS;Nl;0;ON;;;;500;N;;;;; +1014D;GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS;Nl;0;ON;;;;1000;N;;;;; +1014E;GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS;Nl;0;ON;;;;5000;N;;;;; +1014F;GREEK ACROPHONIC ATTIC FIVE STATERS;Nl;0;ON;;;;5;N;;;;; +10150;GREEK ACROPHONIC ATTIC TEN STATERS;Nl;0;ON;;;;10;N;;;;; +10151;GREEK ACROPHONIC ATTIC FIFTY STATERS;Nl;0;ON;;;;50;N;;;;; +10152;GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS;Nl;0;ON;;;;100;N;;;;; +10153;GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS;Nl;0;ON;;;;500;N;;;;; +10154;GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS;Nl;0;ON;;;;1000;N;;;;; +10155;GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS;Nl;0;ON;;;;10000;N;;;;; +10156;GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS;Nl;0;ON;;;;50000;N;;;;; +10157;GREEK ACROPHONIC ATTIC TEN MNAS;Nl;0;ON;;;;10;N;;;;; +10158;GREEK ACROPHONIC HERAEUM ONE PLETHRON;Nl;0;ON;;;;1;N;;;;; +10159;GREEK ACROPHONIC THESPIAN ONE;Nl;0;ON;;;;1;N;;;;; +1015A;GREEK ACROPHONIC HERMIONIAN ONE;Nl;0;ON;;;;1;N;;;;; +1015B;GREEK ACROPHONIC EPIDAUREAN TWO;Nl;0;ON;;;;2;N;;;;; +1015C;GREEK ACROPHONIC THESPIAN TWO;Nl;0;ON;;;;2;N;;;;; +1015D;GREEK ACROPHONIC CYRENAIC TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;; +1015E;GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;; +1015F;GREEK ACROPHONIC TROEZENIAN FIVE;Nl;0;ON;;;;5;N;;;;; +10160;GREEK ACROPHONIC TROEZENIAN TEN;Nl;0;ON;;;;10;N;;;;; +10161;GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM;Nl;0;ON;;;;10;N;;;;; +10162;GREEK ACROPHONIC HERMIONIAN TEN;Nl;0;ON;;;;10;N;;;;; +10163;GREEK ACROPHONIC MESSENIAN TEN;Nl;0;ON;;;;10;N;;;;; +10164;GREEK ACROPHONIC THESPIAN TEN;Nl;0;ON;;;;10;N;;;;; +10165;GREEK ACROPHONIC THESPIAN THIRTY;Nl;0;ON;;;;30;N;;;;; +10166;GREEK ACROPHONIC TROEZENIAN FIFTY;Nl;0;ON;;;;50;N;;;;; +10167;GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM;Nl;0;ON;;;;50;N;;;;; +10168;GREEK ACROPHONIC HERMIONIAN FIFTY;Nl;0;ON;;;;50;N;;;;; +10169;GREEK ACROPHONIC THESPIAN FIFTY;Nl;0;ON;;;;50;N;;;;; +1016A;GREEK ACROPHONIC THESPIAN ONE HUNDRED;Nl;0;ON;;;;100;N;;;;; +1016B;GREEK ACROPHONIC THESPIAN THREE HUNDRED;Nl;0;ON;;;;300;N;;;;; +1016C;GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +1016D;GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +1016E;GREEK ACROPHONIC THESPIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +1016F;GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +10170;GREEK ACROPHONIC NAXIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +10171;GREEK ACROPHONIC THESPIAN ONE THOUSAND;Nl;0;ON;;;;1000;N;;;;; +10172;GREEK ACROPHONIC THESPIAN FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;; +10173;GREEK ACROPHONIC DELPHIC FIVE MNAS;Nl;0;ON;;;;5;N;;;;; +10174;GREEK ACROPHONIC STRATIAN FIFTY MNAS;Nl;0;ON;;;;50;N;;;;; +10175;GREEK ONE HALF SIGN;No;0;ON;;;;1/2;N;;;;; +10176;GREEK ONE HALF SIGN ALTERNATE FORM;No;0;ON;;;;1/2;N;;;;; +10177;GREEK TWO THIRDS SIGN;No;0;ON;;;;2/3;N;;;;; +10178;GREEK THREE QUARTERS SIGN;No;0;ON;;;;3/4;N;;;;; +10179;GREEK YEAR SIGN;So;0;ON;;;;;N;;;;; +1017A;GREEK TALENT SIGN;So;0;ON;;;;;N;;;;; +1017B;GREEK DRACHMA SIGN;So;0;ON;;;;;N;;;;; +1017C;GREEK OBOL SIGN;So;0;ON;;;;;N;;;;; +1017D;GREEK TWO OBOLS SIGN;So;0;ON;;;;;N;;;;; +1017E;GREEK THREE OBOLS SIGN;So;0;ON;;;;;N;;;;; +1017F;GREEK FOUR OBOLS SIGN;So;0;ON;;;;;N;;;;; +10180;GREEK FIVE OBOLS SIGN;So;0;ON;;;;;N;;;;; +10181;GREEK METRETES SIGN;So;0;ON;;;;;N;;;;; +10182;GREEK KYATHOS BASE SIGN;So;0;ON;;;;;N;;;;; +10183;GREEK LITRA SIGN;So;0;ON;;;;;N;;;;; +10184;GREEK OUNKIA SIGN;So;0;ON;;;;;N;;;;; +10185;GREEK XESTES SIGN;So;0;ON;;;;;N;;;;; +10186;GREEK ARTABE SIGN;So;0;ON;;;;;N;;;;; +10187;GREEK AROURA SIGN;So;0;ON;;;;;N;;;;; +10188;GREEK GRAMMA SIGN;So;0;ON;;;;;N;;;;; +10189;GREEK TRYBLION BASE SIGN;So;0;ON;;;;;N;;;;; +1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;; +10190;ROMAN SEXTANS SIGN;So;0;ON;;;;;N;;;;; +10191;ROMAN UNCIA SIGN;So;0;ON;;;;;N;;;;; +10192;ROMAN SEMUNCIA SIGN;So;0;ON;;;;;N;;;;; +10193;ROMAN SEXTULA SIGN;So;0;ON;;;;;N;;;;; +10194;ROMAN DIMIDIA SEXTULA SIGN;So;0;ON;;;;;N;;;;; +10195;ROMAN SILIQUA SIGN;So;0;ON;;;;;N;;;;; +10196;ROMAN DENARIUS SIGN;So;0;ON;;;;;N;;;;; +10197;ROMAN QUINARIUS SIGN;So;0;ON;;;;;N;;;;; +10198;ROMAN SESTERTIUS SIGN;So;0;ON;;;;;N;;;;; +10199;ROMAN DUPONDIUS SIGN;So;0;ON;;;;;N;;;;; +1019A;ROMAN AS SIGN;So;0;ON;;;;;N;;;;; +1019B;ROMAN CENTURIAL SIGN;So;0;ON;;;;;N;;;;; +101D0;PHAISTOS DISC SIGN PEDESTRIAN;So;0;L;;;;;N;;;;; +101D1;PHAISTOS DISC SIGN PLUMED HEAD;So;0;L;;;;;N;;;;; +101D2;PHAISTOS DISC SIGN TATTOOED HEAD;So;0;L;;;;;N;;;;; +101D3;PHAISTOS DISC SIGN CAPTIVE;So;0;L;;;;;N;;;;; +101D4;PHAISTOS DISC SIGN CHILD;So;0;L;;;;;N;;;;; +101D5;PHAISTOS DISC SIGN WOMAN;So;0;L;;;;;N;;;;; +101D6;PHAISTOS DISC SIGN HELMET;So;0;L;;;;;N;;;;; +101D7;PHAISTOS DISC SIGN GAUNTLET;So;0;L;;;;;N;;;;; +101D8;PHAISTOS DISC SIGN TIARA;So;0;L;;;;;N;;;;; +101D9;PHAISTOS DISC SIGN ARROW;So;0;L;;;;;N;;;;; +101DA;PHAISTOS DISC SIGN BOW;So;0;L;;;;;N;;;;; +101DB;PHAISTOS DISC SIGN SHIELD;So;0;L;;;;;N;;;;; +101DC;PHAISTOS DISC SIGN CLUB;So;0;L;;;;;N;;;;; +101DD;PHAISTOS DISC SIGN MANACLES;So;0;L;;;;;N;;;;; +101DE;PHAISTOS DISC SIGN MATTOCK;So;0;L;;;;;N;;;;; +101DF;PHAISTOS DISC SIGN SAW;So;0;L;;;;;N;;;;; +101E0;PHAISTOS DISC SIGN LID;So;0;L;;;;;N;;;;; +101E1;PHAISTOS DISC SIGN BOOMERANG;So;0;L;;;;;N;;;;; +101E2;PHAISTOS DISC SIGN CARPENTRY PLANE;So;0;L;;;;;N;;;;; +101E3;PHAISTOS DISC SIGN DOLIUM;So;0;L;;;;;N;;;;; +101E4;PHAISTOS DISC SIGN COMB;So;0;L;;;;;N;;;;; +101E5;PHAISTOS DISC SIGN SLING;So;0;L;;;;;N;;;;; +101E6;PHAISTOS DISC SIGN COLUMN;So;0;L;;;;;N;;;;; +101E7;PHAISTOS DISC SIGN BEEHIVE;So;0;L;;;;;N;;;;; +101E8;PHAISTOS DISC SIGN SHIP;So;0;L;;;;;N;;;;; +101E9;PHAISTOS DISC SIGN HORN;So;0;L;;;;;N;;;;; +101EA;PHAISTOS DISC SIGN HIDE;So;0;L;;;;;N;;;;; +101EB;PHAISTOS DISC SIGN BULLS LEG;So;0;L;;;;;N;;;;; +101EC;PHAISTOS DISC SIGN CAT;So;0;L;;;;;N;;;;; +101ED;PHAISTOS DISC SIGN RAM;So;0;L;;;;;N;;;;; +101EE;PHAISTOS DISC SIGN EAGLE;So;0;L;;;;;N;;;;; +101EF;PHAISTOS DISC SIGN DOVE;So;0;L;;;;;N;;;;; +101F0;PHAISTOS DISC SIGN TUNNY;So;0;L;;;;;N;;;;; +101F1;PHAISTOS DISC SIGN BEE;So;0;L;;;;;N;;;;; +101F2;PHAISTOS DISC SIGN PLANE TREE;So;0;L;;;;;N;;;;; +101F3;PHAISTOS DISC SIGN VINE;So;0;L;;;;;N;;;;; +101F4;PHAISTOS DISC SIGN PAPYRUS;So;0;L;;;;;N;;;;; +101F5;PHAISTOS DISC SIGN ROSETTE;So;0;L;;;;;N;;;;; +101F6;PHAISTOS DISC SIGN LILY;So;0;L;;;;;N;;;;; +101F7;PHAISTOS DISC SIGN OX BACK;So;0;L;;;;;N;;;;; +101F8;PHAISTOS DISC SIGN FLUTE;So;0;L;;;;;N;;;;; +101F9;PHAISTOS DISC SIGN GRATER;So;0;L;;;;;N;;;;; +101FA;PHAISTOS DISC SIGN STRAINER;So;0;L;;;;;N;;;;; +101FB;PHAISTOS DISC SIGN SMALL AXE;So;0;L;;;;;N;;;;; +101FC;PHAISTOS DISC SIGN WAVY BAND;So;0;L;;;;;N;;;;; +101FD;PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE;Mn;220;NSM;;;;;N;;;;; +10280;LYCIAN LETTER A;Lo;0;L;;;;;N;;;;; +10281;LYCIAN LETTER E;Lo;0;L;;;;;N;;;;; +10282;LYCIAN LETTER B;Lo;0;L;;;;;N;;;;; +10283;LYCIAN LETTER BH;Lo;0;L;;;;;N;;;;; +10284;LYCIAN LETTER G;Lo;0;L;;;;;N;;;;; +10285;LYCIAN LETTER D;Lo;0;L;;;;;N;;;;; +10286;LYCIAN LETTER I;Lo;0;L;;;;;N;;;;; +10287;LYCIAN LETTER W;Lo;0;L;;;;;N;;;;; +10288;LYCIAN LETTER Z;Lo;0;L;;;;;N;;;;; +10289;LYCIAN LETTER TH;Lo;0;L;;;;;N;;;;; +1028A;LYCIAN LETTER J;Lo;0;L;;;;;N;;;;; +1028B;LYCIAN LETTER K;Lo;0;L;;;;;N;;;;; +1028C;LYCIAN LETTER Q;Lo;0;L;;;;;N;;;;; +1028D;LYCIAN LETTER L;Lo;0;L;;;;;N;;;;; +1028E;LYCIAN LETTER M;Lo;0;L;;;;;N;;;;; +1028F;LYCIAN LETTER N;Lo;0;L;;;;;N;;;;; +10290;LYCIAN LETTER MM;Lo;0;L;;;;;N;;;;; +10291;LYCIAN LETTER NN;Lo;0;L;;;;;N;;;;; +10292;LYCIAN LETTER U;Lo;0;L;;;;;N;;;;; +10293;LYCIAN LETTER P;Lo;0;L;;;;;N;;;;; +10294;LYCIAN LETTER KK;Lo;0;L;;;;;N;;;;; +10295;LYCIAN LETTER R;Lo;0;L;;;;;N;;;;; +10296;LYCIAN LETTER S;Lo;0;L;;;;;N;;;;; +10297;LYCIAN LETTER T;Lo;0;L;;;;;N;;;;; +10298;LYCIAN LETTER TT;Lo;0;L;;;;;N;;;;; +10299;LYCIAN LETTER AN;Lo;0;L;;;;;N;;;;; +1029A;LYCIAN LETTER EN;Lo;0;L;;;;;N;;;;; +1029B;LYCIAN LETTER H;Lo;0;L;;;;;N;;;;; +1029C;LYCIAN LETTER X;Lo;0;L;;;;;N;;;;; +102A0;CARIAN LETTER A;Lo;0;L;;;;;N;;;;; +102A1;CARIAN LETTER P2;Lo;0;L;;;;;N;;;;; +102A2;CARIAN LETTER D;Lo;0;L;;;;;N;;;;; +102A3;CARIAN LETTER L;Lo;0;L;;;;;N;;;;; +102A4;CARIAN LETTER UUU;Lo;0;L;;;;;N;;;;; +102A5;CARIAN LETTER R;Lo;0;L;;;;;N;;;;; +102A6;CARIAN LETTER LD;Lo;0;L;;;;;N;;;;; +102A7;CARIAN LETTER A2;Lo;0;L;;;;;N;;;;; +102A8;CARIAN LETTER Q;Lo;0;L;;;;;N;;;;; +102A9;CARIAN LETTER B;Lo;0;L;;;;;N;;;;; +102AA;CARIAN LETTER M;Lo;0;L;;;;;N;;;;; +102AB;CARIAN LETTER O;Lo;0;L;;;;;N;;;;; +102AC;CARIAN LETTER D2;Lo;0;L;;;;;N;;;;; +102AD;CARIAN LETTER T;Lo;0;L;;;;;N;;;;; +102AE;CARIAN LETTER SH;Lo;0;L;;;;;N;;;;; +102AF;CARIAN LETTER SH2;Lo;0;L;;;;;N;;;;; +102B0;CARIAN LETTER S;Lo;0;L;;;;;N;;;;; +102B1;CARIAN LETTER C-18;Lo;0;L;;;;;N;;;;; +102B2;CARIAN LETTER U;Lo;0;L;;;;;N;;;;; +102B3;CARIAN LETTER NN;Lo;0;L;;;;;N;;;;; +102B4;CARIAN LETTER X;Lo;0;L;;;;;N;;;;; +102B5;CARIAN LETTER N;Lo;0;L;;;;;N;;;;; +102B6;CARIAN LETTER TT2;Lo;0;L;;;;;N;;;;; +102B7;CARIAN LETTER P;Lo;0;L;;;;;N;;;;; +102B8;CARIAN LETTER SS;Lo;0;L;;;;;N;;;;; +102B9;CARIAN LETTER I;Lo;0;L;;;;;N;;;;; +102BA;CARIAN LETTER E;Lo;0;L;;;;;N;;;;; +102BB;CARIAN LETTER UUUU;Lo;0;L;;;;;N;;;;; +102BC;CARIAN LETTER K;Lo;0;L;;;;;N;;;;; +102BD;CARIAN LETTER K2;Lo;0;L;;;;;N;;;;; +102BE;CARIAN LETTER ND;Lo;0;L;;;;;N;;;;; +102BF;CARIAN LETTER UU;Lo;0;L;;;;;N;;;;; +102C0;CARIAN LETTER G;Lo;0;L;;;;;N;;;;; +102C1;CARIAN LETTER G2;Lo;0;L;;;;;N;;;;; +102C2;CARIAN LETTER ST;Lo;0;L;;;;;N;;;;; +102C3;CARIAN LETTER ST2;Lo;0;L;;;;;N;;;;; +102C4;CARIAN LETTER NG;Lo;0;L;;;;;N;;;;; +102C5;CARIAN LETTER II;Lo;0;L;;;;;N;;;;; +102C6;CARIAN LETTER C-39;Lo;0;L;;;;;N;;;;; +102C7;CARIAN LETTER TT;Lo;0;L;;;;;N;;;;; +102C8;CARIAN LETTER UUU2;Lo;0;L;;;;;N;;;;; +102C9;CARIAN LETTER RR;Lo;0;L;;;;;N;;;;; +102CA;CARIAN LETTER MB;Lo;0;L;;;;;N;;;;; +102CB;CARIAN LETTER MB2;Lo;0;L;;;;;N;;;;; +102CC;CARIAN LETTER MB3;Lo;0;L;;;;;N;;;;; +102CD;CARIAN LETTER MB4;Lo;0;L;;;;;N;;;;; +102CE;CARIAN LETTER LD2;Lo;0;L;;;;;N;;;;; +102CF;CARIAN LETTER E2;Lo;0;L;;;;;N;;;;; +102D0;CARIAN LETTER UUU3;Lo;0;L;;;;;N;;;;; 10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;; 10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;; 10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;; @@ -12405,7 +15253,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;; 1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;; 10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;; -10341;GOTHIC LETTER NINETY;Lo;0;L;;;;;N;;;;; +10341;GOTHIC LETTER NINETY;Nl;0;L;;;;90;N;;;;; 10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;; 10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;; 10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;; @@ -12414,7 +15262,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;; 10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;; 10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;; -1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;;N;;;;; +1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;900;N;;;;; 10380;UGARITIC LETTER ALPA;Lo;0;L;;;;;N;;;;; 10381;UGARITIC LETTER BETA;Lo;0;L;;;;;N;;;;; 10382;UGARITIC LETTER GAMLA;Lo;0;L;;;;;N;;;;; @@ -12446,6 +15294,56 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1039C;UGARITIC LETTER U;Lo;0;L;;;;;N;;;;; 1039D;UGARITIC LETTER SSU;Lo;0;L;;;;;N;;;;; 1039F;UGARITIC WORD DIVIDER;Po;0;L;;;;;N;;;;; +103A0;OLD PERSIAN SIGN A;Lo;0;L;;;;;N;;;;; +103A1;OLD PERSIAN SIGN I;Lo;0;L;;;;;N;;;;; +103A2;OLD PERSIAN SIGN U;Lo;0;L;;;;;N;;;;; +103A3;OLD PERSIAN SIGN KA;Lo;0;L;;;;;N;;;;; +103A4;OLD PERSIAN SIGN KU;Lo;0;L;;;;;N;;;;; +103A5;OLD PERSIAN SIGN GA;Lo;0;L;;;;;N;;;;; +103A6;OLD PERSIAN SIGN GU;Lo;0;L;;;;;N;;;;; +103A7;OLD PERSIAN SIGN XA;Lo;0;L;;;;;N;;;;; +103A8;OLD PERSIAN SIGN CA;Lo;0;L;;;;;N;;;;; +103A9;OLD PERSIAN SIGN JA;Lo;0;L;;;;;N;;;;; +103AA;OLD PERSIAN SIGN JI;Lo;0;L;;;;;N;;;;; +103AB;OLD PERSIAN SIGN TA;Lo;0;L;;;;;N;;;;; +103AC;OLD PERSIAN SIGN TU;Lo;0;L;;;;;N;;;;; +103AD;OLD PERSIAN SIGN DA;Lo;0;L;;;;;N;;;;; +103AE;OLD PERSIAN SIGN DI;Lo;0;L;;;;;N;;;;; +103AF;OLD PERSIAN SIGN DU;Lo;0;L;;;;;N;;;;; +103B0;OLD PERSIAN SIGN THA;Lo;0;L;;;;;N;;;;; +103B1;OLD PERSIAN SIGN PA;Lo;0;L;;;;;N;;;;; +103B2;OLD PERSIAN SIGN BA;Lo;0;L;;;;;N;;;;; +103B3;OLD PERSIAN SIGN FA;Lo;0;L;;;;;N;;;;; +103B4;OLD PERSIAN SIGN NA;Lo;0;L;;;;;N;;;;; +103B5;OLD PERSIAN SIGN NU;Lo;0;L;;;;;N;;;;; +103B6;OLD PERSIAN SIGN MA;Lo;0;L;;;;;N;;;;; +103B7;OLD PERSIAN SIGN MI;Lo;0;L;;;;;N;;;;; +103B8;OLD PERSIAN SIGN MU;Lo;0;L;;;;;N;;;;; +103B9;OLD PERSIAN SIGN YA;Lo;0;L;;;;;N;;;;; +103BA;OLD PERSIAN SIGN VA;Lo;0;L;;;;;N;;;;; +103BB;OLD PERSIAN SIGN VI;Lo;0;L;;;;;N;;;;; +103BC;OLD PERSIAN SIGN RA;Lo;0;L;;;;;N;;;;; +103BD;OLD PERSIAN SIGN RU;Lo;0;L;;;;;N;;;;; +103BE;OLD PERSIAN SIGN LA;Lo;0;L;;;;;N;;;;; +103BF;OLD PERSIAN SIGN SA;Lo;0;L;;;;;N;;;;; +103C0;OLD PERSIAN SIGN ZA;Lo;0;L;;;;;N;;;;; +103C1;OLD PERSIAN SIGN SHA;Lo;0;L;;;;;N;;;;; +103C2;OLD PERSIAN SIGN SSA;Lo;0;L;;;;;N;;;;; +103C3;OLD PERSIAN SIGN HA;Lo;0;L;;;;;N;;;;; +103C8;OLD PERSIAN SIGN AURAMAZDAA;Lo;0;L;;;;;N;;;;; +103C9;OLD PERSIAN SIGN AURAMAZDAA-2;Lo;0;L;;;;;N;;;;; +103CA;OLD PERSIAN SIGN AURAMAZDAAHA;Lo;0;L;;;;;N;;;;; +103CB;OLD PERSIAN SIGN XSHAAYATHIYA;Lo;0;L;;;;;N;;;;; +103CC;OLD PERSIAN SIGN DAHYAAUSH;Lo;0;L;;;;;N;;;;; +103CD;OLD PERSIAN SIGN DAHYAAUSH-2;Lo;0;L;;;;;N;;;;; +103CE;OLD PERSIAN SIGN BAGA;Lo;0;L;;;;;N;;;;; +103CF;OLD PERSIAN SIGN BUUMISH;Lo;0;L;;;;;N;;;;; +103D0;OLD PERSIAN WORD DIVIDER;Po;0;L;;;;;N;;;;; +103D1;OLD PERSIAN NUMBER ONE;Nl;0;L;;;;1;N;;;;; +103D2;OLD PERSIAN NUMBER TWO;Nl;0;L;;;;2;N;;;;; +103D3;OLD PERSIAN NUMBER TEN;Nl;0;L;;;;10;N;;;;; +103D4;OLD PERSIAN NUMBER TWENTY;Nl;0;L;;;;20;N;;;;; +103D5;OLD PERSIAN NUMBER HUNDRED;Nl;0;L;;;;100;N;;;;; 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428; 10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429; 10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A; @@ -12669,6 +15567,1107 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10838;CYPRIOT SYLLABLE XE;Lo;0;R;;;;;N;;;;; 1083C;CYPRIOT SYLLABLE ZA;Lo;0;R;;;;;N;;;;; 1083F;CYPRIOT SYLLABLE ZO;Lo;0;R;;;;;N;;;;; +10900;PHOENICIAN LETTER ALF;Lo;0;R;;;;;N;;;;; +10901;PHOENICIAN LETTER BET;Lo;0;R;;;;;N;;;;; +10902;PHOENICIAN LETTER GAML;Lo;0;R;;;;;N;;;;; +10903;PHOENICIAN LETTER DELT;Lo;0;R;;;;;N;;;;; +10904;PHOENICIAN LETTER HE;Lo;0;R;;;;;N;;;;; +10905;PHOENICIAN LETTER WAU;Lo;0;R;;;;;N;;;;; +10906;PHOENICIAN LETTER ZAI;Lo;0;R;;;;;N;;;;; +10907;PHOENICIAN LETTER HET;Lo;0;R;;;;;N;;;;; +10908;PHOENICIAN LETTER TET;Lo;0;R;;;;;N;;;;; +10909;PHOENICIAN LETTER YOD;Lo;0;R;;;;;N;;;;; +1090A;PHOENICIAN LETTER KAF;Lo;0;R;;;;;N;;;;; +1090B;PHOENICIAN LETTER LAMD;Lo;0;R;;;;;N;;;;; +1090C;PHOENICIAN LETTER MEM;Lo;0;R;;;;;N;;;;; +1090D;PHOENICIAN LETTER NUN;Lo;0;R;;;;;N;;;;; +1090E;PHOENICIAN LETTER SEMK;Lo;0;R;;;;;N;;;;; +1090F;PHOENICIAN LETTER AIN;Lo;0;R;;;;;N;;;;; +10910;PHOENICIAN LETTER PE;Lo;0;R;;;;;N;;;;; +10911;PHOENICIAN LETTER SADE;Lo;0;R;;;;;N;;;;; +10912;PHOENICIAN LETTER QOF;Lo;0;R;;;;;N;;;;; +10913;PHOENICIAN LETTER ROSH;Lo;0;R;;;;;N;;;;; +10914;PHOENICIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +10915;PHOENICIAN LETTER TAU;Lo;0;R;;;;;N;;;;; +10916;PHOENICIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10917;PHOENICIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10918;PHOENICIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10919;PHOENICIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +1091F;PHOENICIAN WORD SEPARATOR;Po;0;ON;;;;;N;;;;; +10920;LYDIAN LETTER A;Lo;0;R;;;;;N;;;;; +10921;LYDIAN LETTER B;Lo;0;R;;;;;N;;;;; +10922;LYDIAN LETTER G;Lo;0;R;;;;;N;;;;; +10923;LYDIAN LETTER D;Lo;0;R;;;;;N;;;;; +10924;LYDIAN LETTER E;Lo;0;R;;;;;N;;;;; +10925;LYDIAN LETTER V;Lo;0;R;;;;;N;;;;; +10926;LYDIAN LETTER I;Lo;0;R;;;;;N;;;;; +10927;LYDIAN LETTER Y;Lo;0;R;;;;;N;;;;; +10928;LYDIAN LETTER K;Lo;0;R;;;;;N;;;;; +10929;LYDIAN LETTER L;Lo;0;R;;;;;N;;;;; +1092A;LYDIAN LETTER M;Lo;0;R;;;;;N;;;;; +1092B;LYDIAN LETTER N;Lo;0;R;;;;;N;;;;; +1092C;LYDIAN LETTER O;Lo;0;R;;;;;N;;;;; +1092D;LYDIAN LETTER R;Lo;0;R;;;;;N;;;;; +1092E;LYDIAN LETTER SS;Lo;0;R;;;;;N;;;;; +1092F;LYDIAN LETTER T;Lo;0;R;;;;;N;;;;; +10930;LYDIAN LETTER U;Lo;0;R;;;;;N;;;;; +10931;LYDIAN LETTER F;Lo;0;R;;;;;N;;;;; +10932;LYDIAN LETTER Q;Lo;0;R;;;;;N;;;;; +10933;LYDIAN LETTER S;Lo;0;R;;;;;N;;;;; +10934;LYDIAN LETTER TT;Lo;0;R;;;;;N;;;;; +10935;LYDIAN LETTER AN;Lo;0;R;;;;;N;;;;; +10936;LYDIAN LETTER EN;Lo;0;R;;;;;N;;;;; +10937;LYDIAN LETTER LY;Lo;0;R;;;;;N;;;;; +10938;LYDIAN LETTER NN;Lo;0;R;;;;;N;;;;; +10939;LYDIAN LETTER C;Lo;0;R;;;;;N;;;;; +1093F;LYDIAN TRIANGULAR MARK;Po;0;R;;;;;N;;;;; +10A00;KHAROSHTHI LETTER A;Lo;0;R;;;;;N;;;;; +10A01;KHAROSHTHI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +10A02;KHAROSHTHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +10A03;KHAROSHTHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +10A05;KHAROSHTHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +10A06;KHAROSHTHI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +10A0C;KHAROSHTHI VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +10A0D;KHAROSHTHI SIGN DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;; +10A0E;KHAROSHTHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +10A0F;KHAROSHTHI SIGN VISARGA;Mn;230;NSM;;;;;N;;;;; +10A10;KHAROSHTHI LETTER KA;Lo;0;R;;;;;N;;;;; +10A11;KHAROSHTHI LETTER KHA;Lo;0;R;;;;;N;;;;; +10A12;KHAROSHTHI LETTER GA;Lo;0;R;;;;;N;;;;; +10A13;KHAROSHTHI LETTER GHA;Lo;0;R;;;;;N;;;;; +10A15;KHAROSHTHI LETTER CA;Lo;0;R;;;;;N;;;;; +10A16;KHAROSHTHI LETTER CHA;Lo;0;R;;;;;N;;;;; +10A17;KHAROSHTHI LETTER JA;Lo;0;R;;;;;N;;;;; +10A19;KHAROSHTHI LETTER NYA;Lo;0;R;;;;;N;;;;; +10A1A;KHAROSHTHI LETTER TTA;Lo;0;R;;;;;N;;;;; +10A1B;KHAROSHTHI LETTER TTHA;Lo;0;R;;;;;N;;;;; +10A1C;KHAROSHTHI LETTER DDA;Lo;0;R;;;;;N;;;;; +10A1D;KHAROSHTHI LETTER DDHA;Lo;0;R;;;;;N;;;;; +10A1E;KHAROSHTHI LETTER NNA;Lo;0;R;;;;;N;;;;; +10A1F;KHAROSHTHI LETTER TA;Lo;0;R;;;;;N;;;;; +10A20;KHAROSHTHI LETTER THA;Lo;0;R;;;;;N;;;;; +10A21;KHAROSHTHI LETTER DA;Lo;0;R;;;;;N;;;;; +10A22;KHAROSHTHI LETTER DHA;Lo;0;R;;;;;N;;;;; +10A23;KHAROSHTHI LETTER NA;Lo;0;R;;;;;N;;;;; +10A24;KHAROSHTHI LETTER PA;Lo;0;R;;;;;N;;;;; +10A25;KHAROSHTHI LETTER PHA;Lo;0;R;;;;;N;;;;; +10A26;KHAROSHTHI LETTER BA;Lo;0;R;;;;;N;;;;; +10A27;KHAROSHTHI LETTER BHA;Lo;0;R;;;;;N;;;;; +10A28;KHAROSHTHI LETTER MA;Lo;0;R;;;;;N;;;;; +10A29;KHAROSHTHI LETTER YA;Lo;0;R;;;;;N;;;;; +10A2A;KHAROSHTHI LETTER RA;Lo;0;R;;;;;N;;;;; +10A2B;KHAROSHTHI LETTER LA;Lo;0;R;;;;;N;;;;; +10A2C;KHAROSHTHI LETTER VA;Lo;0;R;;;;;N;;;;; +10A2D;KHAROSHTHI LETTER SHA;Lo;0;R;;;;;N;;;;; +10A2E;KHAROSHTHI LETTER SSA;Lo;0;R;;;;;N;;;;; +10A2F;KHAROSHTHI LETTER SA;Lo;0;R;;;;;N;;;;; +10A30;KHAROSHTHI LETTER ZA;Lo;0;R;;;;;N;;;;; +10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;; +10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;; +10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;; +10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;; +10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;; +10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;; +10A3F;KHAROSHTHI VIRAMA;Mn;9;NSM;;;;;N;;;;; +10A40;KHAROSHTHI DIGIT ONE;No;0;R;;;1;1;N;;;;; +10A41;KHAROSHTHI DIGIT TWO;No;0;R;;;2;2;N;;;;; +10A42;KHAROSHTHI DIGIT THREE;No;0;R;;;3;3;N;;;;; +10A43;KHAROSHTHI DIGIT FOUR;No;0;R;;;4;4;N;;;;; +10A44;KHAROSHTHI NUMBER TEN;No;0;R;;;;10;N;;;;; +10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;; +10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;; +10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;; +10A53;KHAROSHTHI PUNCTUATION CRESCENT BAR;Po;0;R;;;;;N;;;;; +10A54;KHAROSHTHI PUNCTUATION MANGALAM;Po;0;R;;;;;N;;;;; +10A55;KHAROSHTHI PUNCTUATION LOTUS;Po;0;R;;;;;N;;;;; +10A56;KHAROSHTHI PUNCTUATION DANDA;Po;0;R;;;;;N;;;;; +10A57;KHAROSHTHI PUNCTUATION DOUBLE DANDA;Po;0;R;;;;;N;;;;; +10A58;KHAROSHTHI PUNCTUATION LINES;Po;0;R;;;;;N;;;;; +12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;; +12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;; +12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;; +12003;CUNEIFORM SIGN A TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12004;CUNEIFORM SIGN A TIMES HA;Lo;0;L;;;;;N;;;;; +12005;CUNEIFORM SIGN A TIMES IGI;Lo;0;L;;;;;N;;;;; +12006;CUNEIFORM SIGN A TIMES LAGAR GUNU;Lo;0;L;;;;;N;;;;; +12007;CUNEIFORM SIGN A TIMES MUSH;Lo;0;L;;;;;N;;;;; +12008;CUNEIFORM SIGN A TIMES SAG;Lo;0;L;;;;;N;;;;; +12009;CUNEIFORM SIGN A2;Lo;0;L;;;;;N;;;;; +1200A;CUNEIFORM SIGN AB;Lo;0;L;;;;;N;;;;; +1200B;CUNEIFORM SIGN AB TIMES ASH2;Lo;0;L;;;;;N;;;;; +1200C;CUNEIFORM SIGN AB TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;; +1200D;CUNEIFORM SIGN AB TIMES GAL;Lo;0;L;;;;;N;;;;; +1200E;CUNEIFORM SIGN AB TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1200F;CUNEIFORM SIGN AB TIMES HA;Lo;0;L;;;;;N;;;;; +12010;CUNEIFORM SIGN AB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +12011;CUNEIFORM SIGN AB TIMES IMIN;Lo;0;L;;;;;N;;;;; +12012;CUNEIFORM SIGN AB TIMES LAGAB;Lo;0;L;;;;;N;;;;; +12013;CUNEIFORM SIGN AB TIMES SHESH;Lo;0;L;;;;;N;;;;; +12014;CUNEIFORM SIGN AB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;; +12015;CUNEIFORM SIGN AB GUNU;Lo;0;L;;;;;N;;;;; +12016;CUNEIFORM SIGN AB2;Lo;0;L;;;;;N;;;;; +12017;CUNEIFORM SIGN AB2 TIMES BALAG;Lo;0;L;;;;;N;;;;; +12018;CUNEIFORM SIGN AB2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12019;CUNEIFORM SIGN AB2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; +1201A;CUNEIFORM SIGN AB2 TIMES SHA3;Lo;0;L;;;;;N;;;;; +1201B;CUNEIFORM SIGN AB2 TIMES TAK4;Lo;0;L;;;;;N;;;;; +1201C;CUNEIFORM SIGN AD;Lo;0;L;;;;;N;;;;; +1201D;CUNEIFORM SIGN AK;Lo;0;L;;;;;N;;;;; +1201E;CUNEIFORM SIGN AK TIMES ERIN2;Lo;0;L;;;;;N;;;;; +1201F;CUNEIFORM SIGN AK TIMES SHITA PLUS GISH;Lo;0;L;;;;;N;;;;; +12020;CUNEIFORM SIGN AL;Lo;0;L;;;;;N;;;;; +12021;CUNEIFORM SIGN AL TIMES AL;Lo;0;L;;;;;N;;;;; +12022;CUNEIFORM SIGN AL TIMES DIM2;Lo;0;L;;;;;N;;;;; +12023;CUNEIFORM SIGN AL TIMES GISH;Lo;0;L;;;;;N;;;;; +12024;CUNEIFORM SIGN AL TIMES HA;Lo;0;L;;;;;N;;;;; +12025;CUNEIFORM SIGN AL TIMES KAD3;Lo;0;L;;;;;N;;;;; +12026;CUNEIFORM SIGN AL TIMES KI;Lo;0;L;;;;;N;;;;; +12027;CUNEIFORM SIGN AL TIMES SHE;Lo;0;L;;;;;N;;;;; +12028;CUNEIFORM SIGN AL TIMES USH;Lo;0;L;;;;;N;;;;; +12029;CUNEIFORM SIGN ALAN;Lo;0;L;;;;;N;;;;; +1202A;CUNEIFORM SIGN ALEPH;Lo;0;L;;;;;N;;;;; +1202B;CUNEIFORM SIGN AMAR;Lo;0;L;;;;;N;;;;; +1202C;CUNEIFORM SIGN AMAR TIMES SHE;Lo;0;L;;;;;N;;;;; +1202D;CUNEIFORM SIGN AN;Lo;0;L;;;;;N;;;;; +1202E;CUNEIFORM SIGN AN OVER AN;Lo;0;L;;;;;N;;;;; +1202F;CUNEIFORM SIGN AN THREE TIMES;Lo;0;L;;;;;N;;;;; +12030;CUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGA;Lo;0;L;;;;;N;;;;; +12031;CUNEIFORM SIGN AN PLUS NAGA SQUARED;Lo;0;L;;;;;N;;;;; +12032;CUNEIFORM SIGN ANSHE;Lo;0;L;;;;;N;;;;; +12033;CUNEIFORM SIGN APIN;Lo;0;L;;;;;N;;;;; +12034;CUNEIFORM SIGN ARAD;Lo;0;L;;;;;N;;;;; +12035;CUNEIFORM SIGN ARAD TIMES KUR;Lo;0;L;;;;;N;;;;; +12036;CUNEIFORM SIGN ARKAB;Lo;0;L;;;;;N;;;;; +12037;CUNEIFORM SIGN ASAL2;Lo;0;L;;;;;N;;;;; +12038;CUNEIFORM SIGN ASH;Lo;0;L;;;;;N;;;;; +12039;CUNEIFORM SIGN ASH ZIDA TENU;Lo;0;L;;;;;N;;;;; +1203A;CUNEIFORM SIGN ASH KABA TENU;Lo;0;L;;;;;N;;;;; +1203B;CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP;Lo;0;L;;;;;N;;;;; +1203C;CUNEIFORM SIGN ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;; +1203D;CUNEIFORM SIGN ASH OVER ASH OVER ASH CROSSING ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;; +1203E;CUNEIFORM SIGN ASH2;Lo;0;L;;;;;N;;;;; +1203F;CUNEIFORM SIGN ASHGAB;Lo;0;L;;;;;N;;;;; +12040;CUNEIFORM SIGN BA;Lo;0;L;;;;;N;;;;; +12041;CUNEIFORM SIGN BAD;Lo;0;L;;;;;N;;;;; +12042;CUNEIFORM SIGN BAG3;Lo;0;L;;;;;N;;;;; +12043;CUNEIFORM SIGN BAHAR2;Lo;0;L;;;;;N;;;;; +12044;CUNEIFORM SIGN BAL;Lo;0;L;;;;;N;;;;; +12045;CUNEIFORM SIGN BAL OVER BAL;Lo;0;L;;;;;N;;;;; +12046;CUNEIFORM SIGN BALAG;Lo;0;L;;;;;N;;;;; +12047;CUNEIFORM SIGN BAR;Lo;0;L;;;;;N;;;;; +12048;CUNEIFORM SIGN BARA2;Lo;0;L;;;;;N;;;;; +12049;CUNEIFORM SIGN BI;Lo;0;L;;;;;N;;;;; +1204A;CUNEIFORM SIGN BI TIMES A;Lo;0;L;;;;;N;;;;; +1204B;CUNEIFORM SIGN BI TIMES GAR;Lo;0;L;;;;;N;;;;; +1204C;CUNEIFORM SIGN BI TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +1204D;CUNEIFORM SIGN BU;Lo;0;L;;;;;N;;;;; +1204E;CUNEIFORM SIGN BU OVER BU AB;Lo;0;L;;;;;N;;;;; +1204F;CUNEIFORM SIGN BU OVER BU UN;Lo;0;L;;;;;N;;;;; +12050;CUNEIFORM SIGN BU CROSSING BU;Lo;0;L;;;;;N;;;;; +12051;CUNEIFORM SIGN BULUG;Lo;0;L;;;;;N;;;;; +12052;CUNEIFORM SIGN BULUG OVER BULUG;Lo;0;L;;;;;N;;;;; +12053;CUNEIFORM SIGN BUR;Lo;0;L;;;;;N;;;;; +12054;CUNEIFORM SIGN BUR2;Lo;0;L;;;;;N;;;;; +12055;CUNEIFORM SIGN DA;Lo;0;L;;;;;N;;;;; +12056;CUNEIFORM SIGN DAG;Lo;0;L;;;;;N;;;;; +12057;CUNEIFORM SIGN DAG KISIM5 TIMES A PLUS MASH;Lo;0;L;;;;;N;;;;; +12058;CUNEIFORM SIGN DAG KISIM5 TIMES AMAR;Lo;0;L;;;;;N;;;;; +12059;CUNEIFORM SIGN DAG KISIM5 TIMES BALAG;Lo;0;L;;;;;N;;;;; +1205A;CUNEIFORM SIGN DAG KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;; +1205B;CUNEIFORM SIGN DAG KISIM5 TIMES GA;Lo;0;L;;;;;N;;;;; +1205C;CUNEIFORM SIGN DAG KISIM5 TIMES GA PLUS MASH;Lo;0;L;;;;;N;;;;; +1205D;CUNEIFORM SIGN DAG KISIM5 TIMES GI;Lo;0;L;;;;;N;;;;; +1205E;CUNEIFORM SIGN DAG KISIM5 TIMES GIR2;Lo;0;L;;;;;N;;;;; +1205F;CUNEIFORM SIGN DAG KISIM5 TIMES GUD;Lo;0;L;;;;;N;;;;; +12060;CUNEIFORM SIGN DAG KISIM5 TIMES HA;Lo;0;L;;;;;N;;;;; +12061;CUNEIFORM SIGN DAG KISIM5 TIMES IR;Lo;0;L;;;;;N;;;;; +12062;CUNEIFORM SIGN DAG KISIM5 TIMES IR PLUS LU;Lo;0;L;;;;;N;;;;; +12063;CUNEIFORM SIGN DAG KISIM5 TIMES KAK;Lo;0;L;;;;;N;;;;; +12064;CUNEIFORM SIGN DAG KISIM5 TIMES LA;Lo;0;L;;;;;N;;;;; +12065;CUNEIFORM SIGN DAG KISIM5 TIMES LU;Lo;0;L;;;;;N;;;;; +12066;CUNEIFORM SIGN DAG KISIM5 TIMES LU PLUS MASH2;Lo;0;L;;;;;N;;;;; +12067;CUNEIFORM SIGN DAG KISIM5 TIMES LUM;Lo;0;L;;;;;N;;;;; +12068;CUNEIFORM SIGN DAG KISIM5 TIMES NE;Lo;0;L;;;;;N;;;;; +12069;CUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;; +1206A;CUNEIFORM SIGN DAG KISIM5 TIMES SI;Lo;0;L;;;;;N;;;;; +1206B;CUNEIFORM SIGN DAG KISIM5 TIMES TAK4;Lo;0;L;;;;;N;;;;; +1206C;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS GIR2;Lo;0;L;;;;;N;;;;; +1206D;CUNEIFORM SIGN DAG KISIM5 TIMES USH;Lo;0;L;;;;;N;;;;; +1206E;CUNEIFORM SIGN DAM;Lo;0;L;;;;;N;;;;; +1206F;CUNEIFORM SIGN DAR;Lo;0;L;;;;;N;;;;; +12070;CUNEIFORM SIGN DARA3;Lo;0;L;;;;;N;;;;; +12071;CUNEIFORM SIGN DARA4;Lo;0;L;;;;;N;;;;; +12072;CUNEIFORM SIGN DI;Lo;0;L;;;;;N;;;;; +12073;CUNEIFORM SIGN DIB;Lo;0;L;;;;;N;;;;; +12074;CUNEIFORM SIGN DIM;Lo;0;L;;;;;N;;;;; +12075;CUNEIFORM SIGN DIM TIMES SHE;Lo;0;L;;;;;N;;;;; +12076;CUNEIFORM SIGN DIM2;Lo;0;L;;;;;N;;;;; +12077;CUNEIFORM SIGN DIN;Lo;0;L;;;;;N;;;;; +12078;CUNEIFORM SIGN DIN KASKAL U GUNU DISH;Lo;0;L;;;;;N;;;;; +12079;CUNEIFORM SIGN DISH;Lo;0;L;;;;;N;;;;; +1207A;CUNEIFORM SIGN DU;Lo;0;L;;;;;N;;;;; +1207B;CUNEIFORM SIGN DU OVER DU;Lo;0;L;;;;;N;;;;; +1207C;CUNEIFORM SIGN DU GUNU;Lo;0;L;;;;;N;;;;; +1207D;CUNEIFORM SIGN DU SHESHIG;Lo;0;L;;;;;N;;;;; +1207E;CUNEIFORM SIGN DUB;Lo;0;L;;;;;N;;;;; +1207F;CUNEIFORM SIGN DUB TIMES ESH2;Lo;0;L;;;;;N;;;;; +12080;CUNEIFORM SIGN DUB2;Lo;0;L;;;;;N;;;;; +12081;CUNEIFORM SIGN DUG;Lo;0;L;;;;;N;;;;; +12082;CUNEIFORM SIGN DUGUD;Lo;0;L;;;;;N;;;;; +12083;CUNEIFORM SIGN DUH;Lo;0;L;;;;;N;;;;; +12084;CUNEIFORM SIGN DUN;Lo;0;L;;;;;N;;;;; +12085;CUNEIFORM SIGN DUN3;Lo;0;L;;;;;N;;;;; +12086;CUNEIFORM SIGN DUN3 GUNU;Lo;0;L;;;;;N;;;;; +12087;CUNEIFORM SIGN DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;; +12088;CUNEIFORM SIGN DUN4;Lo;0;L;;;;;N;;;;; +12089;CUNEIFORM SIGN DUR2;Lo;0;L;;;;;N;;;;; +1208A;CUNEIFORM SIGN E;Lo;0;L;;;;;N;;;;; +1208B;CUNEIFORM SIGN E TIMES PAP;Lo;0;L;;;;;N;;;;; +1208C;CUNEIFORM SIGN E OVER E NUN OVER NUN;Lo;0;L;;;;;N;;;;; +1208D;CUNEIFORM SIGN E2;Lo;0;L;;;;;N;;;;; +1208E;CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DA;Lo;0;L;;;;;N;;;;; +1208F;CUNEIFORM SIGN E2 TIMES GAR;Lo;0;L;;;;;N;;;;; +12090;CUNEIFORM SIGN E2 TIMES MI;Lo;0;L;;;;;N;;;;; +12091;CUNEIFORM SIGN E2 TIMES SAL;Lo;0;L;;;;;N;;;;; +12092;CUNEIFORM SIGN E2 TIMES SHE;Lo;0;L;;;;;N;;;;; +12093;CUNEIFORM SIGN E2 TIMES U;Lo;0;L;;;;;N;;;;; +12094;CUNEIFORM SIGN EDIN;Lo;0;L;;;;;N;;;;; +12095;CUNEIFORM SIGN EGIR;Lo;0;L;;;;;N;;;;; +12096;CUNEIFORM SIGN EL;Lo;0;L;;;;;N;;;;; +12097;CUNEIFORM SIGN EN;Lo;0;L;;;;;N;;;;; +12098;CUNEIFORM SIGN EN TIMES GAN2;Lo;0;L;;;;;N;;;;; +12099;CUNEIFORM SIGN EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1209A;CUNEIFORM SIGN EN TIMES ME;Lo;0;L;;;;;N;;;;; +1209B;CUNEIFORM SIGN EN CROSSING EN;Lo;0;L;;;;;N;;;;; +1209C;CUNEIFORM SIGN EN OPPOSING EN;Lo;0;L;;;;;N;;;;; +1209D;CUNEIFORM SIGN EN SQUARED;Lo;0;L;;;;;N;;;;; +1209E;CUNEIFORM SIGN EREN;Lo;0;L;;;;;N;;;;; +1209F;CUNEIFORM SIGN ERIN2;Lo;0;L;;;;;N;;;;; +120A0;CUNEIFORM SIGN ESH2;Lo;0;L;;;;;N;;;;; +120A1;CUNEIFORM SIGN EZEN;Lo;0;L;;;;;N;;;;; +120A2;CUNEIFORM SIGN EZEN TIMES A;Lo;0;L;;;;;N;;;;; +120A3;CUNEIFORM SIGN EZEN TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;; +120A4;CUNEIFORM SIGN EZEN TIMES A PLUS LAL TIMES LAL;Lo;0;L;;;;;N;;;;; +120A5;CUNEIFORM SIGN EZEN TIMES AN;Lo;0;L;;;;;N;;;;; +120A6;CUNEIFORM SIGN EZEN TIMES BAD;Lo;0;L;;;;;N;;;;; +120A7;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;; +120A8;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;; +120A9;CUNEIFORM SIGN EZEN TIMES HA;Lo;0;L;;;;;N;;;;; +120AA;CUNEIFORM SIGN EZEN TIMES HA GUNU;Lo;0;L;;;;;N;;;;; +120AB;CUNEIFORM SIGN EZEN TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +120AC;CUNEIFORM SIGN EZEN TIMES KASKAL;Lo;0;L;;;;;N;;;;; +120AD;CUNEIFORM SIGN EZEN TIMES KASKAL SQUARED;Lo;0;L;;;;;N;;;;; +120AE;CUNEIFORM SIGN EZEN TIMES KU3;Lo;0;L;;;;;N;;;;; +120AF;CUNEIFORM SIGN EZEN TIMES LA;Lo;0;L;;;;;N;;;;; +120B0;CUNEIFORM SIGN EZEN TIMES LAL TIMES LAL;Lo;0;L;;;;;N;;;;; +120B1;CUNEIFORM SIGN EZEN TIMES LI;Lo;0;L;;;;;N;;;;; +120B2;CUNEIFORM SIGN EZEN TIMES LU;Lo;0;L;;;;;N;;;;; +120B3;CUNEIFORM SIGN EZEN TIMES U2;Lo;0;L;;;;;N;;;;; +120B4;CUNEIFORM SIGN EZEN TIMES UD;Lo;0;L;;;;;N;;;;; +120B5;CUNEIFORM SIGN GA;Lo;0;L;;;;;N;;;;; +120B6;CUNEIFORM SIGN GA GUNU;Lo;0;L;;;;;N;;;;; +120B7;CUNEIFORM SIGN GA2;Lo;0;L;;;;;N;;;;; +120B8;CUNEIFORM SIGN GA2 TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;; +120B9;CUNEIFORM SIGN GA2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;; +120BA;CUNEIFORM SIGN GA2 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;; +120BB;CUNEIFORM SIGN GA2 TIMES AB2 TENU PLUS TAB;Lo;0;L;;;;;N;;;;; +120BC;CUNEIFORM SIGN GA2 TIMES AN;Lo;0;L;;;;;N;;;;; +120BD;CUNEIFORM SIGN GA2 TIMES ASH;Lo;0;L;;;;;N;;;;; +120BE;CUNEIFORM SIGN GA2 TIMES ASH2 PLUS GAL;Lo;0;L;;;;;N;;;;; +120BF;CUNEIFORM SIGN GA2 TIMES BAD;Lo;0;L;;;;;N;;;;; +120C0;CUNEIFORM SIGN GA2 TIMES BAR PLUS RA;Lo;0;L;;;;;N;;;;; +120C1;CUNEIFORM SIGN GA2 TIMES BUR;Lo;0;L;;;;;N;;;;; +120C2;CUNEIFORM SIGN GA2 TIMES BUR PLUS RA;Lo;0;L;;;;;N;;;;; +120C3;CUNEIFORM SIGN GA2 TIMES DA;Lo;0;L;;;;;N;;;;; +120C4;CUNEIFORM SIGN GA2 TIMES DI;Lo;0;L;;;;;N;;;;; +120C5;CUNEIFORM SIGN GA2 TIMES DIM TIMES SHE;Lo;0;L;;;;;N;;;;; +120C6;CUNEIFORM SIGN GA2 TIMES DUB;Lo;0;L;;;;;N;;;;; +120C7;CUNEIFORM SIGN GA2 TIMES EL;Lo;0;L;;;;;N;;;;; +120C8;CUNEIFORM SIGN GA2 TIMES EL PLUS LA;Lo;0;L;;;;;N;;;;; +120C9;CUNEIFORM SIGN GA2 TIMES EN;Lo;0;L;;;;;N;;;;; +120CA;CUNEIFORM SIGN GA2 TIMES EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +120CB;CUNEIFORM SIGN GA2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +120CC;CUNEIFORM SIGN GA2 TIMES GAR;Lo;0;L;;;;;N;;;;; +120CD;CUNEIFORM SIGN GA2 TIMES GI;Lo;0;L;;;;;N;;;;; +120CE;CUNEIFORM SIGN GA2 TIMES GI4;Lo;0;L;;;;;N;;;;; +120CF;CUNEIFORM SIGN GA2 TIMES GI4 PLUS A;Lo;0;L;;;;;N;;;;; +120D0;CUNEIFORM SIGN GA2 TIMES GIR2 PLUS SU;Lo;0;L;;;;;N;;;;; +120D1;CUNEIFORM SIGN GA2 TIMES HA PLUS LU PLUS ESH2;Lo;0;L;;;;;N;;;;; +120D2;CUNEIFORM SIGN GA2 TIMES HAL;Lo;0;L;;;;;N;;;;; +120D3;CUNEIFORM SIGN GA2 TIMES HAL PLUS LA;Lo;0;L;;;;;N;;;;; +120D4;CUNEIFORM SIGN GA2 TIMES HI PLUS LI;Lo;0;L;;;;;N;;;;; +120D5;CUNEIFORM SIGN GA2 TIMES HUB2;Lo;0;L;;;;;N;;;;; +120D6;CUNEIFORM SIGN GA2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +120D7;CUNEIFORM SIGN GA2 TIMES ISH PLUS HU PLUS ASH;Lo;0;L;;;;;N;;;;; +120D8;CUNEIFORM SIGN GA2 TIMES KAK;Lo;0;L;;;;;N;;;;; +120D9;CUNEIFORM SIGN GA2 TIMES KASKAL;Lo;0;L;;;;;N;;;;; +120DA;CUNEIFORM SIGN GA2 TIMES KID;Lo;0;L;;;;;N;;;;; +120DB;CUNEIFORM SIGN GA2 TIMES KID PLUS LAL;Lo;0;L;;;;;N;;;;; +120DC;CUNEIFORM SIGN GA2 TIMES KU3 PLUS AN;Lo;0;L;;;;;N;;;;; +120DD;CUNEIFORM SIGN GA2 TIMES LA;Lo;0;L;;;;;N;;;;; +120DE;CUNEIFORM SIGN GA2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; +120DF;CUNEIFORM SIGN GA2 TIMES MI;Lo;0;L;;;;;N;;;;; +120E0;CUNEIFORM SIGN GA2 TIMES NUN;Lo;0;L;;;;;N;;;;; +120E1;CUNEIFORM SIGN GA2 TIMES NUN OVER NUN;Lo;0;L;;;;;N;;;;; +120E2;CUNEIFORM SIGN GA2 TIMES PA;Lo;0;L;;;;;N;;;;; +120E3;CUNEIFORM SIGN GA2 TIMES SAL;Lo;0;L;;;;;N;;;;; +120E4;CUNEIFORM SIGN GA2 TIMES SAR;Lo;0;L;;;;;N;;;;; +120E5;CUNEIFORM SIGN GA2 TIMES SHE;Lo;0;L;;;;;N;;;;; +120E6;CUNEIFORM SIGN GA2 TIMES SHE PLUS TUR;Lo;0;L;;;;;N;;;;; +120E7;CUNEIFORM SIGN GA2 TIMES SHID;Lo;0;L;;;;;N;;;;; +120E8;CUNEIFORM SIGN GA2 TIMES SUM;Lo;0;L;;;;;N;;;;; +120E9;CUNEIFORM SIGN GA2 TIMES TAK4;Lo;0;L;;;;;N;;;;; +120EA;CUNEIFORM SIGN GA2 TIMES U;Lo;0;L;;;;;N;;;;; +120EB;CUNEIFORM SIGN GA2 TIMES UD;Lo;0;L;;;;;N;;;;; +120EC;CUNEIFORM SIGN GA2 TIMES UD PLUS DU;Lo;0;L;;;;;N;;;;; +120ED;CUNEIFORM SIGN GA2 OVER GA2;Lo;0;L;;;;;N;;;;; +120EE;CUNEIFORM SIGN GABA;Lo;0;L;;;;;N;;;;; +120EF;CUNEIFORM SIGN GABA CROSSING GABA;Lo;0;L;;;;;N;;;;; +120F0;CUNEIFORM SIGN GAD;Lo;0;L;;;;;N;;;;; +120F1;CUNEIFORM SIGN GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; +120F2;CUNEIFORM SIGN GAL;Lo;0;L;;;;;N;;;;; +120F3;CUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; +120F4;CUNEIFORM SIGN GALAM;Lo;0;L;;;;;N;;;;; +120F5;CUNEIFORM SIGN GAM;Lo;0;L;;;;;N;;;;; +120F6;CUNEIFORM SIGN GAN;Lo;0;L;;;;;N;;;;; +120F7;CUNEIFORM SIGN GAN2;Lo;0;L;;;;;N;;;;; +120F8;CUNEIFORM SIGN GAN2 TENU;Lo;0;L;;;;;N;;;;; +120F9;CUNEIFORM SIGN GAN2 OVER GAN2;Lo;0;L;;;;;N;;;;; +120FA;CUNEIFORM SIGN GAN2 CROSSING GAN2;Lo;0;L;;;;;N;;;;; +120FB;CUNEIFORM SIGN GAR;Lo;0;L;;;;;N;;;;; +120FC;CUNEIFORM SIGN GAR3;Lo;0;L;;;;;N;;;;; +120FD;CUNEIFORM SIGN GASHAN;Lo;0;L;;;;;N;;;;; +120FE;CUNEIFORM SIGN GESHTIN;Lo;0;L;;;;;N;;;;; +120FF;CUNEIFORM SIGN GESHTIN TIMES KUR;Lo;0;L;;;;;N;;;;; +12100;CUNEIFORM SIGN GI;Lo;0;L;;;;;N;;;;; +12101;CUNEIFORM SIGN GI TIMES E;Lo;0;L;;;;;N;;;;; +12102;CUNEIFORM SIGN GI TIMES U;Lo;0;L;;;;;N;;;;; +12103;CUNEIFORM SIGN GI CROSSING GI;Lo;0;L;;;;;N;;;;; +12104;CUNEIFORM SIGN GI4;Lo;0;L;;;;;N;;;;; +12105;CUNEIFORM SIGN GI4 OVER GI4;Lo;0;L;;;;;N;;;;; +12106;CUNEIFORM SIGN GI4 CROSSING GI4;Lo;0;L;;;;;N;;;;; +12107;CUNEIFORM SIGN GIDIM;Lo;0;L;;;;;N;;;;; +12108;CUNEIFORM SIGN GIR2;Lo;0;L;;;;;N;;;;; +12109;CUNEIFORM SIGN GIR2 GUNU;Lo;0;L;;;;;N;;;;; +1210A;CUNEIFORM SIGN GIR3;Lo;0;L;;;;;N;;;;; +1210B;CUNEIFORM SIGN GIR3 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;; +1210C;CUNEIFORM SIGN GIR3 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1210D;CUNEIFORM SIGN GIR3 TIMES IGI;Lo;0;L;;;;;N;;;;; +1210E;CUNEIFORM SIGN GIR3 TIMES LU PLUS IGI;Lo;0;L;;;;;N;;;;; +1210F;CUNEIFORM SIGN GIR3 TIMES PA;Lo;0;L;;;;;N;;;;; +12110;CUNEIFORM SIGN GISAL;Lo;0;L;;;;;N;;;;; +12111;CUNEIFORM SIGN GISH;Lo;0;L;;;;;N;;;;; +12112;CUNEIFORM SIGN GISH CROSSING GISH;Lo;0;L;;;;;N;;;;; +12113;CUNEIFORM SIGN GISH TIMES BAD;Lo;0;L;;;;;N;;;;; +12114;CUNEIFORM SIGN GISH TIMES TAK4;Lo;0;L;;;;;N;;;;; +12115;CUNEIFORM SIGN GISH TENU;Lo;0;L;;;;;N;;;;; +12116;CUNEIFORM SIGN GU;Lo;0;L;;;;;N;;;;; +12117;CUNEIFORM SIGN GU CROSSING GU;Lo;0;L;;;;;N;;;;; +12118;CUNEIFORM SIGN GU2;Lo;0;L;;;;;N;;;;; +12119;CUNEIFORM SIGN GU2 TIMES KAK;Lo;0;L;;;;;N;;;;; +1211A;CUNEIFORM SIGN GU2 TIMES KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +1211B;CUNEIFORM SIGN GU2 TIMES NUN;Lo;0;L;;;;;N;;;;; +1211C;CUNEIFORM SIGN GU2 TIMES SAL PLUS TUG2;Lo;0;L;;;;;N;;;;; +1211D;CUNEIFORM SIGN GU2 GUNU;Lo;0;L;;;;;N;;;;; +1211E;CUNEIFORM SIGN GUD;Lo;0;L;;;;;N;;;;; +1211F;CUNEIFORM SIGN GUD TIMES A PLUS KUR;Lo;0;L;;;;;N;;;;; +12120;CUNEIFORM SIGN GUD TIMES KUR;Lo;0;L;;;;;N;;;;; +12121;CUNEIFORM SIGN GUD OVER GUD LUGAL;Lo;0;L;;;;;N;;;;; +12122;CUNEIFORM SIGN GUL;Lo;0;L;;;;;N;;;;; +12123;CUNEIFORM SIGN GUM;Lo;0;L;;;;;N;;;;; +12124;CUNEIFORM SIGN GUM TIMES SHE;Lo;0;L;;;;;N;;;;; +12125;CUNEIFORM SIGN GUR;Lo;0;L;;;;;N;;;;; +12126;CUNEIFORM SIGN GUR7;Lo;0;L;;;;;N;;;;; +12127;CUNEIFORM SIGN GURUN;Lo;0;L;;;;;N;;;;; +12128;CUNEIFORM SIGN GURUSH;Lo;0;L;;;;;N;;;;; +12129;CUNEIFORM SIGN HA;Lo;0;L;;;;;N;;;;; +1212A;CUNEIFORM SIGN HA TENU;Lo;0;L;;;;;N;;;;; +1212B;CUNEIFORM SIGN HA GUNU;Lo;0;L;;;;;N;;;;; +1212C;CUNEIFORM SIGN HAL;Lo;0;L;;;;;N;;;;; +1212D;CUNEIFORM SIGN HI;Lo;0;L;;;;;N;;;;; +1212E;CUNEIFORM SIGN HI TIMES ASH;Lo;0;L;;;;;N;;;;; +1212F;CUNEIFORM SIGN HI TIMES ASH2;Lo;0;L;;;;;N;;;;; +12130;CUNEIFORM SIGN HI TIMES BAD;Lo;0;L;;;;;N;;;;; +12131;CUNEIFORM SIGN HI TIMES DISH;Lo;0;L;;;;;N;;;;; +12132;CUNEIFORM SIGN HI TIMES GAD;Lo;0;L;;;;;N;;;;; +12133;CUNEIFORM SIGN HI TIMES KIN;Lo;0;L;;;;;N;;;;; +12134;CUNEIFORM SIGN HI TIMES NUN;Lo;0;L;;;;;N;;;;; +12135;CUNEIFORM SIGN HI TIMES SHE;Lo;0;L;;;;;N;;;;; +12136;CUNEIFORM SIGN HI TIMES U;Lo;0;L;;;;;N;;;;; +12137;CUNEIFORM SIGN HU;Lo;0;L;;;;;N;;;;; +12138;CUNEIFORM SIGN HUB2;Lo;0;L;;;;;N;;;;; +12139;CUNEIFORM SIGN HUB2 TIMES AN;Lo;0;L;;;;;N;;;;; +1213A;CUNEIFORM SIGN HUB2 TIMES HAL;Lo;0;L;;;;;N;;;;; +1213B;CUNEIFORM SIGN HUB2 TIMES KASKAL;Lo;0;L;;;;;N;;;;; +1213C;CUNEIFORM SIGN HUB2 TIMES LISH;Lo;0;L;;;;;N;;;;; +1213D;CUNEIFORM SIGN HUB2 TIMES UD;Lo;0;L;;;;;N;;;;; +1213E;CUNEIFORM SIGN HUL2;Lo;0;L;;;;;N;;;;; +1213F;CUNEIFORM SIGN I;Lo;0;L;;;;;N;;;;; +12140;CUNEIFORM SIGN I A;Lo;0;L;;;;;N;;;;; +12141;CUNEIFORM SIGN IB;Lo;0;L;;;;;N;;;;; +12142;CUNEIFORM SIGN IDIM;Lo;0;L;;;;;N;;;;; +12143;CUNEIFORM SIGN IDIM OVER IDIM BUR;Lo;0;L;;;;;N;;;;; +12144;CUNEIFORM SIGN IDIM OVER IDIM SQUARED;Lo;0;L;;;;;N;;;;; +12145;CUNEIFORM SIGN IG;Lo;0;L;;;;;N;;;;; +12146;CUNEIFORM SIGN IGI;Lo;0;L;;;;;N;;;;; +12147;CUNEIFORM SIGN IGI DIB;Lo;0;L;;;;;N;;;;; +12148;CUNEIFORM SIGN IGI RI;Lo;0;L;;;;;N;;;;; +12149;CUNEIFORM SIGN IGI OVER IGI SHIR OVER SHIR UD OVER UD;Lo;0;L;;;;;N;;;;; +1214A;CUNEIFORM SIGN IGI GUNU;Lo;0;L;;;;;N;;;;; +1214B;CUNEIFORM SIGN IL;Lo;0;L;;;;;N;;;;; +1214C;CUNEIFORM SIGN IL TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1214D;CUNEIFORM SIGN IL2;Lo;0;L;;;;;N;;;;; +1214E;CUNEIFORM SIGN IM;Lo;0;L;;;;;N;;;;; +1214F;CUNEIFORM SIGN IM TIMES TAK4;Lo;0;L;;;;;N;;;;; +12150;CUNEIFORM SIGN IM CROSSING IM;Lo;0;L;;;;;N;;;;; +12151;CUNEIFORM SIGN IM OPPOSING IM;Lo;0;L;;;;;N;;;;; +12152;CUNEIFORM SIGN IM SQUARED;Lo;0;L;;;;;N;;;;; +12153;CUNEIFORM SIGN IMIN;Lo;0;L;;;;;N;;;;; +12154;CUNEIFORM SIGN IN;Lo;0;L;;;;;N;;;;; +12155;CUNEIFORM SIGN IR;Lo;0;L;;;;;N;;;;; +12156;CUNEIFORM SIGN ISH;Lo;0;L;;;;;N;;;;; +12157;CUNEIFORM SIGN KA;Lo;0;L;;;;;N;;;;; +12158;CUNEIFORM SIGN KA TIMES A;Lo;0;L;;;;;N;;;;; +12159;CUNEIFORM SIGN KA TIMES AD;Lo;0;L;;;;;N;;;;; +1215A;CUNEIFORM SIGN KA TIMES AD PLUS KU3;Lo;0;L;;;;;N;;;;; +1215B;CUNEIFORM SIGN KA TIMES ASH2;Lo;0;L;;;;;N;;;;; +1215C;CUNEIFORM SIGN KA TIMES BAD;Lo;0;L;;;;;N;;;;; +1215D;CUNEIFORM SIGN KA TIMES BALAG;Lo;0;L;;;;;N;;;;; +1215E;CUNEIFORM SIGN KA TIMES BAR;Lo;0;L;;;;;N;;;;; +1215F;CUNEIFORM SIGN KA TIMES BI;Lo;0;L;;;;;N;;;;; +12160;CUNEIFORM SIGN KA TIMES ERIN2;Lo;0;L;;;;;N;;;;; +12161;CUNEIFORM SIGN KA TIMES ESH2;Lo;0;L;;;;;N;;;;; +12162;CUNEIFORM SIGN KA TIMES GA;Lo;0;L;;;;;N;;;;; +12163;CUNEIFORM SIGN KA TIMES GAL;Lo;0;L;;;;;N;;;;; +12164;CUNEIFORM SIGN KA TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12165;CUNEIFORM SIGN KA TIMES GAR;Lo;0;L;;;;;N;;;;; +12166;CUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS A;Lo;0;L;;;;;N;;;;; +12167;CUNEIFORM SIGN KA TIMES GI;Lo;0;L;;;;;N;;;;; +12168;CUNEIFORM SIGN KA TIMES GIR2;Lo;0;L;;;;;N;;;;; +12169;CUNEIFORM SIGN KA TIMES GISH PLUS SAR;Lo;0;L;;;;;N;;;;; +1216A;CUNEIFORM SIGN KA TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;; +1216B;CUNEIFORM SIGN KA TIMES GU;Lo;0;L;;;;;N;;;;; +1216C;CUNEIFORM SIGN KA TIMES GUR7;Lo;0;L;;;;;N;;;;; +1216D;CUNEIFORM SIGN KA TIMES IGI;Lo;0;L;;;;;N;;;;; +1216E;CUNEIFORM SIGN KA TIMES IM;Lo;0;L;;;;;N;;;;; +1216F;CUNEIFORM SIGN KA TIMES KAK;Lo;0;L;;;;;N;;;;; +12170;CUNEIFORM SIGN KA TIMES KI;Lo;0;L;;;;;N;;;;; +12171;CUNEIFORM SIGN KA TIMES KID;Lo;0;L;;;;;N;;;;; +12172;CUNEIFORM SIGN KA TIMES LI;Lo;0;L;;;;;N;;;;; +12173;CUNEIFORM SIGN KA TIMES LU;Lo;0;L;;;;;N;;;;; +12174;CUNEIFORM SIGN KA TIMES ME;Lo;0;L;;;;;N;;;;; +12175;CUNEIFORM SIGN KA TIMES ME PLUS DU;Lo;0;L;;;;;N;;;;; +12176;CUNEIFORM SIGN KA TIMES ME PLUS GI;Lo;0;L;;;;;N;;;;; +12177;CUNEIFORM SIGN KA TIMES ME PLUS TE;Lo;0;L;;;;;N;;;;; +12178;CUNEIFORM SIGN KA TIMES MI;Lo;0;L;;;;;N;;;;; +12179;CUNEIFORM SIGN KA TIMES MI PLUS NUNUZ;Lo;0;L;;;;;N;;;;; +1217A;CUNEIFORM SIGN KA TIMES NE;Lo;0;L;;;;;N;;;;; +1217B;CUNEIFORM SIGN KA TIMES NUN;Lo;0;L;;;;;N;;;;; +1217C;CUNEIFORM SIGN KA TIMES PI;Lo;0;L;;;;;N;;;;; +1217D;CUNEIFORM SIGN KA TIMES RU;Lo;0;L;;;;;N;;;;; +1217E;CUNEIFORM SIGN KA TIMES SA;Lo;0;L;;;;;N;;;;; +1217F;CUNEIFORM SIGN KA TIMES SAR;Lo;0;L;;;;;N;;;;; +12180;CUNEIFORM SIGN KA TIMES SHA;Lo;0;L;;;;;N;;;;; +12181;CUNEIFORM SIGN KA TIMES SHE;Lo;0;L;;;;;N;;;;; +12182;CUNEIFORM SIGN KA TIMES SHID;Lo;0;L;;;;;N;;;;; +12183;CUNEIFORM SIGN KA TIMES SHU;Lo;0;L;;;;;N;;;;; +12184;CUNEIFORM SIGN KA TIMES SIG;Lo;0;L;;;;;N;;;;; +12185;CUNEIFORM SIGN KA TIMES SUHUR;Lo;0;L;;;;;N;;;;; +12186;CUNEIFORM SIGN KA TIMES TAR;Lo;0;L;;;;;N;;;;; +12187;CUNEIFORM SIGN KA TIMES U;Lo;0;L;;;;;N;;;;; +12188;CUNEIFORM SIGN KA TIMES U2;Lo;0;L;;;;;N;;;;; +12189;CUNEIFORM SIGN KA TIMES UD;Lo;0;L;;;;;N;;;;; +1218A;CUNEIFORM SIGN KA TIMES UMUM TIMES PA;Lo;0;L;;;;;N;;;;; +1218B;CUNEIFORM SIGN KA TIMES USH;Lo;0;L;;;;;N;;;;; +1218C;CUNEIFORM SIGN KA TIMES ZI;Lo;0;L;;;;;N;;;;; +1218D;CUNEIFORM SIGN KA2;Lo;0;L;;;;;N;;;;; +1218E;CUNEIFORM SIGN KA2 CROSSING KA2;Lo;0;L;;;;;N;;;;; +1218F;CUNEIFORM SIGN KAB;Lo;0;L;;;;;N;;;;; +12190;CUNEIFORM SIGN KAD2;Lo;0;L;;;;;N;;;;; +12191;CUNEIFORM SIGN KAD3;Lo;0;L;;;;;N;;;;; +12192;CUNEIFORM SIGN KAD4;Lo;0;L;;;;;N;;;;; +12193;CUNEIFORM SIGN KAD5;Lo;0;L;;;;;N;;;;; +12194;CUNEIFORM SIGN KAD5 OVER KAD5;Lo;0;L;;;;;N;;;;; +12195;CUNEIFORM SIGN KAK;Lo;0;L;;;;;N;;;;; +12196;CUNEIFORM SIGN KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +12197;CUNEIFORM SIGN KAL;Lo;0;L;;;;;N;;;;; +12198;CUNEIFORM SIGN KAL TIMES BAD;Lo;0;L;;;;;N;;;;; +12199;CUNEIFORM SIGN KAL CROSSING KAL;Lo;0;L;;;;;N;;;;; +1219A;CUNEIFORM SIGN KAM2;Lo;0;L;;;;;N;;;;; +1219B;CUNEIFORM SIGN KAM4;Lo;0;L;;;;;N;;;;; +1219C;CUNEIFORM SIGN KASKAL;Lo;0;L;;;;;N;;;;; +1219D;CUNEIFORM SIGN KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;; +1219E;CUNEIFORM SIGN KASKAL OVER KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;; +1219F;CUNEIFORM SIGN KESH2;Lo;0;L;;;;;N;;;;; +121A0;CUNEIFORM SIGN KI;Lo;0;L;;;;;N;;;;; +121A1;CUNEIFORM SIGN KI TIMES BAD;Lo;0;L;;;;;N;;;;; +121A2;CUNEIFORM SIGN KI TIMES U;Lo;0;L;;;;;N;;;;; +121A3;CUNEIFORM SIGN KI TIMES UD;Lo;0;L;;;;;N;;;;; +121A4;CUNEIFORM SIGN KID;Lo;0;L;;;;;N;;;;; +121A5;CUNEIFORM SIGN KIN;Lo;0;L;;;;;N;;;;; +121A6;CUNEIFORM SIGN KISAL;Lo;0;L;;;;;N;;;;; +121A7;CUNEIFORM SIGN KISH;Lo;0;L;;;;;N;;;;; +121A8;CUNEIFORM SIGN KISIM5;Lo;0;L;;;;;N;;;;; +121A9;CUNEIFORM SIGN KISIM5 OVER KISIM5;Lo;0;L;;;;;N;;;;; +121AA;CUNEIFORM SIGN KU;Lo;0;L;;;;;N;;;;; +121AB;CUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIMES ASH2;Lo;0;L;;;;;N;;;;; +121AC;CUNEIFORM SIGN KU3;Lo;0;L;;;;;N;;;;; +121AD;CUNEIFORM SIGN KU4;Lo;0;L;;;;;N;;;;; +121AE;CUNEIFORM SIGN KU4 VARIANT FORM;Lo;0;L;;;;;N;;;;; +121AF;CUNEIFORM SIGN KU7;Lo;0;L;;;;;N;;;;; +121B0;CUNEIFORM SIGN KUL;Lo;0;L;;;;;N;;;;; +121B1;CUNEIFORM SIGN KUL GUNU;Lo;0;L;;;;;N;;;;; +121B2;CUNEIFORM SIGN KUN;Lo;0;L;;;;;N;;;;; +121B3;CUNEIFORM SIGN KUR;Lo;0;L;;;;;N;;;;; +121B4;CUNEIFORM SIGN KUR OPPOSING KUR;Lo;0;L;;;;;N;;;;; +121B5;CUNEIFORM SIGN KUSHU2;Lo;0;L;;;;;N;;;;; +121B6;CUNEIFORM SIGN KWU318;Lo;0;L;;;;;N;;;;; +121B7;CUNEIFORM SIGN LA;Lo;0;L;;;;;N;;;;; +121B8;CUNEIFORM SIGN LAGAB;Lo;0;L;;;;;N;;;;; +121B9;CUNEIFORM SIGN LAGAB TIMES A;Lo;0;L;;;;;N;;;;; +121BA;CUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;; +121BB;CUNEIFORM SIGN LAGAB TIMES A PLUS GAR;Lo;0;L;;;;;N;;;;; +121BC;CUNEIFORM SIGN LAGAB TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;; +121BD;CUNEIFORM SIGN LAGAB TIMES AL;Lo;0;L;;;;;N;;;;; +121BE;CUNEIFORM SIGN LAGAB TIMES AN;Lo;0;L;;;;;N;;;;; +121BF;CUNEIFORM SIGN LAGAB TIMES ASH ZIDA TENU;Lo;0;L;;;;;N;;;;; +121C0;CUNEIFORM SIGN LAGAB TIMES BAD;Lo;0;L;;;;;N;;;;; +121C1;CUNEIFORM SIGN LAGAB TIMES BI;Lo;0;L;;;;;N;;;;; +121C2;CUNEIFORM SIGN LAGAB TIMES DAR;Lo;0;L;;;;;N;;;;; +121C3;CUNEIFORM SIGN LAGAB TIMES EN;Lo;0;L;;;;;N;;;;; +121C4;CUNEIFORM SIGN LAGAB TIMES GA;Lo;0;L;;;;;N;;;;; +121C5;CUNEIFORM SIGN LAGAB TIMES GAR;Lo;0;L;;;;;N;;;;; +121C6;CUNEIFORM SIGN LAGAB TIMES GUD;Lo;0;L;;;;;N;;;;; +121C7;CUNEIFORM SIGN LAGAB TIMES GUD PLUS GUD;Lo;0;L;;;;;N;;;;; +121C8;CUNEIFORM SIGN LAGAB TIMES HA;Lo;0;L;;;;;N;;;;; +121C9;CUNEIFORM SIGN LAGAB TIMES HAL;Lo;0;L;;;;;N;;;;; +121CA;CUNEIFORM SIGN LAGAB TIMES HI TIMES NUN;Lo;0;L;;;;;N;;;;; +121CB;CUNEIFORM SIGN LAGAB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +121CC;CUNEIFORM SIGN LAGAB TIMES IM;Lo;0;L;;;;;N;;;;; +121CD;CUNEIFORM SIGN LAGAB TIMES IM PLUS HA;Lo;0;L;;;;;N;;;;; +121CE;CUNEIFORM SIGN LAGAB TIMES IM PLUS LU;Lo;0;L;;;;;N;;;;; +121CF;CUNEIFORM SIGN LAGAB TIMES KI;Lo;0;L;;;;;N;;;;; +121D0;CUNEIFORM SIGN LAGAB TIMES KIN;Lo;0;L;;;;;N;;;;; +121D1;CUNEIFORM SIGN LAGAB TIMES KU3;Lo;0;L;;;;;N;;;;; +121D2;CUNEIFORM SIGN LAGAB TIMES KUL;Lo;0;L;;;;;N;;;;; +121D3;CUNEIFORM SIGN LAGAB TIMES KUL PLUS HI PLUS A;Lo;0;L;;;;;N;;;;; +121D4;CUNEIFORM SIGN LAGAB TIMES LAGAB;Lo;0;L;;;;;N;;;;; +121D5;CUNEIFORM SIGN LAGAB TIMES LISH;Lo;0;L;;;;;N;;;;; +121D6;CUNEIFORM SIGN LAGAB TIMES LU;Lo;0;L;;;;;N;;;;; +121D7;CUNEIFORM SIGN LAGAB TIMES LUL;Lo;0;L;;;;;N;;;;; +121D8;CUNEIFORM SIGN LAGAB TIMES ME;Lo;0;L;;;;;N;;;;; +121D9;CUNEIFORM SIGN LAGAB TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; +121DA;CUNEIFORM SIGN LAGAB TIMES MUSH;Lo;0;L;;;;;N;;;;; +121DB;CUNEIFORM SIGN LAGAB TIMES NE;Lo;0;L;;;;;N;;;;; +121DC;CUNEIFORM SIGN LAGAB TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;; +121DD;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2;Lo;0;L;;;;;N;;;;; +121DE;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH TENU;Lo;0;L;;;;;N;;;;; +121DF;CUNEIFORM SIGN LAGAB TIMES SHU2;Lo;0;L;;;;;N;;;;; +121E0;CUNEIFORM SIGN LAGAB TIMES SHU2 PLUS SHU2;Lo;0;L;;;;;N;;;;; +121E1;CUNEIFORM SIGN LAGAB TIMES SUM;Lo;0;L;;;;;N;;;;; +121E2;CUNEIFORM SIGN LAGAB TIMES TAG;Lo;0;L;;;;;N;;;;; +121E3;CUNEIFORM SIGN LAGAB TIMES TAK4;Lo;0;L;;;;;N;;;;; +121E4;CUNEIFORM SIGN LAGAB TIMES TE PLUS A PLUS SU PLUS NA;Lo;0;L;;;;;N;;;;; +121E5;CUNEIFORM SIGN LAGAB TIMES U;Lo;0;L;;;;;N;;;;; +121E6;CUNEIFORM SIGN LAGAB TIMES U PLUS A;Lo;0;L;;;;;N;;;;; +121E7;CUNEIFORM SIGN LAGAB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;; +121E8;CUNEIFORM SIGN LAGAB TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;; +121E9;CUNEIFORM SIGN LAGAB TIMES UD;Lo;0;L;;;;;N;;;;; +121EA;CUNEIFORM SIGN LAGAB TIMES USH;Lo;0;L;;;;;N;;;;; +121EB;CUNEIFORM SIGN LAGAB SQUARED;Lo;0;L;;;;;N;;;;; +121EC;CUNEIFORM SIGN LAGAR;Lo;0;L;;;;;N;;;;; +121ED;CUNEIFORM SIGN LAGAR TIMES SHE;Lo;0;L;;;;;N;;;;; +121EE;CUNEIFORM SIGN LAGAR TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;; +121EF;CUNEIFORM SIGN LAGAR GUNU;Lo;0;L;;;;;N;;;;; +121F0;CUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHE;Lo;0;L;;;;;N;;;;; +121F1;CUNEIFORM SIGN LAHSHU;Lo;0;L;;;;;N;;;;; +121F2;CUNEIFORM SIGN LAL;Lo;0;L;;;;;N;;;;; +121F3;CUNEIFORM SIGN LAL TIMES LAL;Lo;0;L;;;;;N;;;;; +121F4;CUNEIFORM SIGN LAM;Lo;0;L;;;;;N;;;;; +121F5;CUNEIFORM SIGN LAM TIMES KUR;Lo;0;L;;;;;N;;;;; +121F6;CUNEIFORM SIGN LAM TIMES KUR PLUS RU;Lo;0;L;;;;;N;;;;; +121F7;CUNEIFORM SIGN LI;Lo;0;L;;;;;N;;;;; +121F8;CUNEIFORM SIGN LIL;Lo;0;L;;;;;N;;;;; +121F9;CUNEIFORM SIGN LIMMU2;Lo;0;L;;;;;N;;;;; +121FA;CUNEIFORM SIGN LISH;Lo;0;L;;;;;N;;;;; +121FB;CUNEIFORM SIGN LU;Lo;0;L;;;;;N;;;;; +121FC;CUNEIFORM SIGN LU TIMES BAD;Lo;0;L;;;;;N;;;;; +121FD;CUNEIFORM SIGN LU2;Lo;0;L;;;;;N;;;;; +121FE;CUNEIFORM SIGN LU2 TIMES AL;Lo;0;L;;;;;N;;;;; +121FF;CUNEIFORM SIGN LU2 TIMES BAD;Lo;0;L;;;;;N;;;;; +12200;CUNEIFORM SIGN LU2 TIMES ESH2;Lo;0;L;;;;;N;;;;; +12201;CUNEIFORM SIGN LU2 TIMES ESH2 TENU;Lo;0;L;;;;;N;;;;; +12202;CUNEIFORM SIGN LU2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12203;CUNEIFORM SIGN LU2 TIMES HI TIMES BAD;Lo;0;L;;;;;N;;;;; +12204;CUNEIFORM SIGN LU2 TIMES IM;Lo;0;L;;;;;N;;;;; +12205;CUNEIFORM SIGN LU2 TIMES KAD2;Lo;0;L;;;;;N;;;;; +12206;CUNEIFORM SIGN LU2 TIMES KAD3;Lo;0;L;;;;;N;;;;; +12207;CUNEIFORM SIGN LU2 TIMES KAD3 PLUS ASH;Lo;0;L;;;;;N;;;;; +12208;CUNEIFORM SIGN LU2 TIMES KI;Lo;0;L;;;;;N;;;;; +12209;CUNEIFORM SIGN LU2 TIMES LA PLUS ASH;Lo;0;L;;;;;N;;;;; +1220A;CUNEIFORM SIGN LU2 TIMES LAGAB;Lo;0;L;;;;;N;;;;; +1220B;CUNEIFORM SIGN LU2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; +1220C;CUNEIFORM SIGN LU2 TIMES NE;Lo;0;L;;;;;N;;;;; +1220D;CUNEIFORM SIGN LU2 TIMES NU;Lo;0;L;;;;;N;;;;; +1220E;CUNEIFORM SIGN LU2 TIMES SI PLUS ASH;Lo;0;L;;;;;N;;;;; +1220F;CUNEIFORM SIGN LU2 TIMES SIK2 PLUS BU;Lo;0;L;;;;;N;;;;; +12210;CUNEIFORM SIGN LU2 TIMES TUG2;Lo;0;L;;;;;N;;;;; +12211;CUNEIFORM SIGN LU2 TENU;Lo;0;L;;;;;N;;;;; +12212;CUNEIFORM SIGN LU2 CROSSING LU2;Lo;0;L;;;;;N;;;;; +12213;CUNEIFORM SIGN LU2 OPPOSING LU2;Lo;0;L;;;;;N;;;;; +12214;CUNEIFORM SIGN LU2 SQUARED;Lo;0;L;;;;;N;;;;; +12215;CUNEIFORM SIGN LU2 SHESHIG;Lo;0;L;;;;;N;;;;; +12216;CUNEIFORM SIGN LU3;Lo;0;L;;;;;N;;;;; +12217;CUNEIFORM SIGN LUGAL;Lo;0;L;;;;;N;;;;; +12218;CUNEIFORM SIGN LUGAL OVER LUGAL;Lo;0;L;;;;;N;;;;; +12219;CUNEIFORM SIGN LUGAL OPPOSING LUGAL;Lo;0;L;;;;;N;;;;; +1221A;CUNEIFORM SIGN LUGAL SHESHIG;Lo;0;L;;;;;N;;;;; +1221B;CUNEIFORM SIGN LUH;Lo;0;L;;;;;N;;;;; +1221C;CUNEIFORM SIGN LUL;Lo;0;L;;;;;N;;;;; +1221D;CUNEIFORM SIGN LUM;Lo;0;L;;;;;N;;;;; +1221E;CUNEIFORM SIGN LUM OVER LUM;Lo;0;L;;;;;N;;;;; +1221F;CUNEIFORM SIGN LUM OVER LUM GAR OVER GAR;Lo;0;L;;;;;N;;;;; +12220;CUNEIFORM SIGN MA;Lo;0;L;;;;;N;;;;; +12221;CUNEIFORM SIGN MA TIMES TAK4;Lo;0;L;;;;;N;;;;; +12222;CUNEIFORM SIGN MA GUNU;Lo;0;L;;;;;N;;;;; +12223;CUNEIFORM SIGN MA2;Lo;0;L;;;;;N;;;;; +12224;CUNEIFORM SIGN MAH;Lo;0;L;;;;;N;;;;; +12225;CUNEIFORM SIGN MAR;Lo;0;L;;;;;N;;;;; +12226;CUNEIFORM SIGN MASH;Lo;0;L;;;;;N;;;;; +12227;CUNEIFORM SIGN MASH2;Lo;0;L;;;;;N;;;;; +12228;CUNEIFORM SIGN ME;Lo;0;L;;;;;N;;;;; +12229;CUNEIFORM SIGN MES;Lo;0;L;;;;;N;;;;; +1222A;CUNEIFORM SIGN MI;Lo;0;L;;;;;N;;;;; +1222B;CUNEIFORM SIGN MIN;Lo;0;L;;;;;N;;;;; +1222C;CUNEIFORM SIGN MU;Lo;0;L;;;;;N;;;;; +1222D;CUNEIFORM SIGN MU OVER MU;Lo;0;L;;;;;N;;;;; +1222E;CUNEIFORM SIGN MUG;Lo;0;L;;;;;N;;;;; +1222F;CUNEIFORM SIGN MUG GUNU;Lo;0;L;;;;;N;;;;; +12230;CUNEIFORM SIGN MUNSUB;Lo;0;L;;;;;N;;;;; +12231;CUNEIFORM SIGN MURGU2;Lo;0;L;;;;;N;;;;; +12232;CUNEIFORM SIGN MUSH;Lo;0;L;;;;;N;;;;; +12233;CUNEIFORM SIGN MUSH TIMES A;Lo;0;L;;;;;N;;;;; +12234;CUNEIFORM SIGN MUSH TIMES KUR;Lo;0;L;;;;;N;;;;; +12235;CUNEIFORM SIGN MUSH TIMES ZA;Lo;0;L;;;;;N;;;;; +12236;CUNEIFORM SIGN MUSH OVER MUSH;Lo;0;L;;;;;N;;;;; +12237;CUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS NA;Lo;0;L;;;;;N;;;;; +12238;CUNEIFORM SIGN MUSH CROSSING MUSH;Lo;0;L;;;;;N;;;;; +12239;CUNEIFORM SIGN MUSH3;Lo;0;L;;;;;N;;;;; +1223A;CUNEIFORM SIGN MUSH3 TIMES A;Lo;0;L;;;;;N;;;;; +1223B;CUNEIFORM SIGN MUSH3 TIMES A PLUS DI;Lo;0;L;;;;;N;;;;; +1223C;CUNEIFORM SIGN MUSH3 TIMES DI;Lo;0;L;;;;;N;;;;; +1223D;CUNEIFORM SIGN MUSH3 GUNU;Lo;0;L;;;;;N;;;;; +1223E;CUNEIFORM SIGN NA;Lo;0;L;;;;;N;;;;; +1223F;CUNEIFORM SIGN NA2;Lo;0;L;;;;;N;;;;; +12240;CUNEIFORM SIGN NAGA;Lo;0;L;;;;;N;;;;; +12241;CUNEIFORM SIGN NAGA INVERTED;Lo;0;L;;;;;N;;;;; +12242;CUNEIFORM SIGN NAGA TIMES SHU TENU;Lo;0;L;;;;;N;;;;; +12243;CUNEIFORM SIGN NAGA OPPOSING NAGA;Lo;0;L;;;;;N;;;;; +12244;CUNEIFORM SIGN NAGAR;Lo;0;L;;;;;N;;;;; +12245;CUNEIFORM SIGN NAM NUTILLU;Lo;0;L;;;;;N;;;;; +12246;CUNEIFORM SIGN NAM;Lo;0;L;;;;;N;;;;; +12247;CUNEIFORM SIGN NAM2;Lo;0;L;;;;;N;;;;; +12248;CUNEIFORM SIGN NE;Lo;0;L;;;;;N;;;;; +12249;CUNEIFORM SIGN NE TIMES A;Lo;0;L;;;;;N;;;;; +1224A;CUNEIFORM SIGN NE TIMES UD;Lo;0;L;;;;;N;;;;; +1224B;CUNEIFORM SIGN NE SHESHIG;Lo;0;L;;;;;N;;;;; +1224C;CUNEIFORM SIGN NI;Lo;0;L;;;;;N;;;;; +1224D;CUNEIFORM SIGN NI TIMES E;Lo;0;L;;;;;N;;;;; +1224E;CUNEIFORM SIGN NI2;Lo;0;L;;;;;N;;;;; +1224F;CUNEIFORM SIGN NIM;Lo;0;L;;;;;N;;;;; +12250;CUNEIFORM SIGN NIM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12251;CUNEIFORM SIGN NIM TIMES GAR PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;; +12252;CUNEIFORM SIGN NINDA2;Lo;0;L;;;;;N;;;;; +12253;CUNEIFORM SIGN NINDA2 TIMES AN;Lo;0;L;;;;;N;;;;; +12254;CUNEIFORM SIGN NINDA2 TIMES ASH;Lo;0;L;;;;;N;;;;; +12255;CUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASH;Lo;0;L;;;;;N;;;;; +12256;CUNEIFORM SIGN NINDA2 TIMES GUD;Lo;0;L;;;;;N;;;;; +12257;CUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;; +12258;CUNEIFORM SIGN NINDA2 TIMES NE;Lo;0;L;;;;;N;;;;; +12259;CUNEIFORM SIGN NINDA2 TIMES NUN;Lo;0;L;;;;;N;;;;; +1225A;CUNEIFORM SIGN NINDA2 TIMES SHE;Lo;0;L;;;;;N;;;;; +1225B;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS A AN;Lo;0;L;;;;;N;;;;; +1225C;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH;Lo;0;L;;;;;N;;;;; +1225D;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASH;Lo;0;L;;;;;N;;;;; +1225E;CUNEIFORM SIGN NINDA2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;; +1225F;CUNEIFORM SIGN NINDA2 TIMES USH;Lo;0;L;;;;;N;;;;; +12260;CUNEIFORM SIGN NISAG;Lo;0;L;;;;;N;;;;; +12261;CUNEIFORM SIGN NU;Lo;0;L;;;;;N;;;;; +12262;CUNEIFORM SIGN NU11;Lo;0;L;;;;;N;;;;; +12263;CUNEIFORM SIGN NUN;Lo;0;L;;;;;N;;;;; +12264;CUNEIFORM SIGN NUN LAGAR TIMES GAR;Lo;0;L;;;;;N;;;;; +12265;CUNEIFORM SIGN NUN LAGAR TIMES MASH;Lo;0;L;;;;;N;;;;; +12266;CUNEIFORM SIGN NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;; +12267;CUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;; +12268;CUNEIFORM SIGN NUN LAGAR TIMES USH;Lo;0;L;;;;;N;;;;; +12269;CUNEIFORM SIGN NUN TENU;Lo;0;L;;;;;N;;;;; +1226A;CUNEIFORM SIGN NUN OVER NUN;Lo;0;L;;;;;N;;;;; +1226B;CUNEIFORM SIGN NUN CROSSING NUN;Lo;0;L;;;;;N;;;;; +1226C;CUNEIFORM SIGN NUN CROSSING NUN LAGAR OVER LAGAR;Lo;0;L;;;;;N;;;;; +1226D;CUNEIFORM SIGN NUNUZ;Lo;0;L;;;;;N;;;;; +1226E;CUNEIFORM SIGN NUNUZ AB2 TIMES ASHGAB;Lo;0;L;;;;;N;;;;; +1226F;CUNEIFORM SIGN NUNUZ AB2 TIMES BI;Lo;0;L;;;;;N;;;;; +12270;CUNEIFORM SIGN NUNUZ AB2 TIMES DUG;Lo;0;L;;;;;N;;;;; +12271;CUNEIFORM SIGN NUNUZ AB2 TIMES GUD;Lo;0;L;;;;;N;;;;; +12272;CUNEIFORM SIGN NUNUZ AB2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +12273;CUNEIFORM SIGN NUNUZ AB2 TIMES KAD3;Lo;0;L;;;;;N;;;;; +12274;CUNEIFORM SIGN NUNUZ AB2 TIMES LA;Lo;0;L;;;;;N;;;;; +12275;CUNEIFORM SIGN NUNUZ AB2 TIMES NE;Lo;0;L;;;;;N;;;;; +12276;CUNEIFORM SIGN NUNUZ AB2 TIMES SILA3;Lo;0;L;;;;;N;;;;; +12277;CUNEIFORM SIGN NUNUZ AB2 TIMES U2;Lo;0;L;;;;;N;;;;; +12278;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;; +12279;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI U;Lo;0;L;;;;;N;;;;; +1227A;CUNEIFORM SIGN PA;Lo;0;L;;;;;N;;;;; +1227B;CUNEIFORM SIGN PAD;Lo;0;L;;;;;N;;;;; +1227C;CUNEIFORM SIGN PAN;Lo;0;L;;;;;N;;;;; +1227D;CUNEIFORM SIGN PAP;Lo;0;L;;;;;N;;;;; +1227E;CUNEIFORM SIGN PESH2;Lo;0;L;;;;;N;;;;; +1227F;CUNEIFORM SIGN PI;Lo;0;L;;;;;N;;;;; +12280;CUNEIFORM SIGN PI TIMES A;Lo;0;L;;;;;N;;;;; +12281;CUNEIFORM SIGN PI TIMES AB;Lo;0;L;;;;;N;;;;; +12282;CUNEIFORM SIGN PI TIMES BI;Lo;0;L;;;;;N;;;;; +12283;CUNEIFORM SIGN PI TIMES BU;Lo;0;L;;;;;N;;;;; +12284;CUNEIFORM SIGN PI TIMES E;Lo;0;L;;;;;N;;;;; +12285;CUNEIFORM SIGN PI TIMES I;Lo;0;L;;;;;N;;;;; +12286;CUNEIFORM SIGN PI TIMES IB;Lo;0;L;;;;;N;;;;; +12287;CUNEIFORM SIGN PI TIMES U;Lo;0;L;;;;;N;;;;; +12288;CUNEIFORM SIGN PI TIMES U2;Lo;0;L;;;;;N;;;;; +12289;CUNEIFORM SIGN PI CROSSING PI;Lo;0;L;;;;;N;;;;; +1228A;CUNEIFORM SIGN PIRIG;Lo;0;L;;;;;N;;;;; +1228B;CUNEIFORM SIGN PIRIG TIMES KAL;Lo;0;L;;;;;N;;;;; +1228C;CUNEIFORM SIGN PIRIG TIMES UD;Lo;0;L;;;;;N;;;;; +1228D;CUNEIFORM SIGN PIRIG TIMES ZA;Lo;0;L;;;;;N;;;;; +1228E;CUNEIFORM SIGN PIRIG OPPOSING PIRIG;Lo;0;L;;;;;N;;;;; +1228F;CUNEIFORM SIGN RA;Lo;0;L;;;;;N;;;;; +12290;CUNEIFORM SIGN RAB;Lo;0;L;;;;;N;;;;; +12291;CUNEIFORM SIGN RI;Lo;0;L;;;;;N;;;;; +12292;CUNEIFORM SIGN RU;Lo;0;L;;;;;N;;;;; +12293;CUNEIFORM SIGN SA;Lo;0;L;;;;;N;;;;; +12294;CUNEIFORM SIGN SAG NUTILLU;Lo;0;L;;;;;N;;;;; +12295;CUNEIFORM SIGN SAG;Lo;0;L;;;;;N;;;;; +12296;CUNEIFORM SIGN SAG TIMES A;Lo;0;L;;;;;N;;;;; +12297;CUNEIFORM SIGN SAG TIMES DU;Lo;0;L;;;;;N;;;;; +12298;CUNEIFORM SIGN SAG TIMES DUB;Lo;0;L;;;;;N;;;;; +12299;CUNEIFORM SIGN SAG TIMES HA;Lo;0;L;;;;;N;;;;; +1229A;CUNEIFORM SIGN SAG TIMES KAK;Lo;0;L;;;;;N;;;;; +1229B;CUNEIFORM SIGN SAG TIMES KUR;Lo;0;L;;;;;N;;;;; +1229C;CUNEIFORM SIGN SAG TIMES LUM;Lo;0;L;;;;;N;;;;; +1229D;CUNEIFORM SIGN SAG TIMES MI;Lo;0;L;;;;;N;;;;; +1229E;CUNEIFORM SIGN SAG TIMES NUN;Lo;0;L;;;;;N;;;;; +1229F;CUNEIFORM SIGN SAG TIMES SAL;Lo;0;L;;;;;N;;;;; +122A0;CUNEIFORM SIGN SAG TIMES SHID;Lo;0;L;;;;;N;;;;; +122A1;CUNEIFORM SIGN SAG TIMES TAB;Lo;0;L;;;;;N;;;;; +122A2;CUNEIFORM SIGN SAG TIMES U2;Lo;0;L;;;;;N;;;;; +122A3;CUNEIFORM SIGN SAG TIMES UB;Lo;0;L;;;;;N;;;;; +122A4;CUNEIFORM SIGN SAG TIMES UM;Lo;0;L;;;;;N;;;;; +122A5;CUNEIFORM SIGN SAG TIMES UR;Lo;0;L;;;;;N;;;;; +122A6;CUNEIFORM SIGN SAG TIMES USH;Lo;0;L;;;;;N;;;;; +122A7;CUNEIFORM SIGN SAG OVER SAG;Lo;0;L;;;;;N;;;;; +122A8;CUNEIFORM SIGN SAG GUNU;Lo;0;L;;;;;N;;;;; +122A9;CUNEIFORM SIGN SAL;Lo;0;L;;;;;N;;;;; +122AA;CUNEIFORM SIGN SAL LAGAB TIMES ASH2;Lo;0;L;;;;;N;;;;; +122AB;CUNEIFORM SIGN SANGA2;Lo;0;L;;;;;N;;;;; +122AC;CUNEIFORM SIGN SAR;Lo;0;L;;;;;N;;;;; +122AD;CUNEIFORM SIGN SHA;Lo;0;L;;;;;N;;;;; +122AE;CUNEIFORM SIGN SHA3;Lo;0;L;;;;;N;;;;; +122AF;CUNEIFORM SIGN SHA3 TIMES A;Lo;0;L;;;;;N;;;;; +122B0;CUNEIFORM SIGN SHA3 TIMES BAD;Lo;0;L;;;;;N;;;;; +122B1;CUNEIFORM SIGN SHA3 TIMES GISH;Lo;0;L;;;;;N;;;;; +122B2;CUNEIFORM SIGN SHA3 TIMES NE;Lo;0;L;;;;;N;;;;; +122B3;CUNEIFORM SIGN SHA3 TIMES SHU2;Lo;0;L;;;;;N;;;;; +122B4;CUNEIFORM SIGN SHA3 TIMES TUR;Lo;0;L;;;;;N;;;;; +122B5;CUNEIFORM SIGN SHA3 TIMES U;Lo;0;L;;;;;N;;;;; +122B6;CUNEIFORM SIGN SHA3 TIMES U PLUS A;Lo;0;L;;;;;N;;;;; +122B7;CUNEIFORM SIGN SHA6;Lo;0;L;;;;;N;;;;; +122B8;CUNEIFORM SIGN SHAB6;Lo;0;L;;;;;N;;;;; +122B9;CUNEIFORM SIGN SHAR2;Lo;0;L;;;;;N;;;;; +122BA;CUNEIFORM SIGN SHE;Lo;0;L;;;;;N;;;;; +122BB;CUNEIFORM SIGN SHE HU;Lo;0;L;;;;;N;;;;; +122BC;CUNEIFORM SIGN SHE OVER SHE GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; +122BD;CUNEIFORM SIGN SHE OVER SHE TAB OVER TAB GAR OVER GAR;Lo;0;L;;;;;N;;;;; +122BE;CUNEIFORM SIGN SHEG9;Lo;0;L;;;;;N;;;;; +122BF;CUNEIFORM SIGN SHEN;Lo;0;L;;;;;N;;;;; +122C0;CUNEIFORM SIGN SHESH;Lo;0;L;;;;;N;;;;; +122C1;CUNEIFORM SIGN SHESH2;Lo;0;L;;;;;N;;;;; +122C2;CUNEIFORM SIGN SHESHLAM;Lo;0;L;;;;;N;;;;; +122C3;CUNEIFORM SIGN SHID;Lo;0;L;;;;;N;;;;; +122C4;CUNEIFORM SIGN SHID TIMES A;Lo;0;L;;;;;N;;;;; +122C5;CUNEIFORM SIGN SHID TIMES IM;Lo;0;L;;;;;N;;;;; +122C6;CUNEIFORM SIGN SHIM;Lo;0;L;;;;;N;;;;; +122C7;CUNEIFORM SIGN SHIM TIMES A;Lo;0;L;;;;;N;;;;; +122C8;CUNEIFORM SIGN SHIM TIMES BAL;Lo;0;L;;;;;N;;;;; +122C9;CUNEIFORM SIGN SHIM TIMES BULUG;Lo;0;L;;;;;N;;;;; +122CA;CUNEIFORM SIGN SHIM TIMES DIN;Lo;0;L;;;;;N;;;;; +122CB;CUNEIFORM SIGN SHIM TIMES GAR;Lo;0;L;;;;;N;;;;; +122CC;CUNEIFORM SIGN SHIM TIMES IGI;Lo;0;L;;;;;N;;;;; +122CD;CUNEIFORM SIGN SHIM TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +122CE;CUNEIFORM SIGN SHIM TIMES KUSHU2;Lo;0;L;;;;;N;;;;; +122CF;CUNEIFORM SIGN SHIM TIMES LUL;Lo;0;L;;;;;N;;;;; +122D0;CUNEIFORM SIGN SHIM TIMES MUG;Lo;0;L;;;;;N;;;;; +122D1;CUNEIFORM SIGN SHIM TIMES SAL;Lo;0;L;;;;;N;;;;; +122D2;CUNEIFORM SIGN SHINIG;Lo;0;L;;;;;N;;;;; +122D3;CUNEIFORM SIGN SHIR;Lo;0;L;;;;;N;;;;; +122D4;CUNEIFORM SIGN SHIR TENU;Lo;0;L;;;;;N;;;;; +122D5;CUNEIFORM SIGN SHIR OVER SHIR BUR OVER BUR;Lo;0;L;;;;;N;;;;; +122D6;CUNEIFORM SIGN SHITA;Lo;0;L;;;;;N;;;;; +122D7;CUNEIFORM SIGN SHU;Lo;0;L;;;;;N;;;;; +122D8;CUNEIFORM SIGN SHU OVER INVERTED SHU;Lo;0;L;;;;;N;;;;; +122D9;CUNEIFORM SIGN SHU2;Lo;0;L;;;;;N;;;;; +122DA;CUNEIFORM SIGN SHUBUR;Lo;0;L;;;;;N;;;;; +122DB;CUNEIFORM SIGN SI;Lo;0;L;;;;;N;;;;; +122DC;CUNEIFORM SIGN SI GUNU;Lo;0;L;;;;;N;;;;; +122DD;CUNEIFORM SIGN SIG;Lo;0;L;;;;;N;;;;; +122DE;CUNEIFORM SIGN SIG4;Lo;0;L;;;;;N;;;;; +122DF;CUNEIFORM SIGN SIG4 OVER SIG4 SHU2;Lo;0;L;;;;;N;;;;; +122E0;CUNEIFORM SIGN SIK2;Lo;0;L;;;;;N;;;;; +122E1;CUNEIFORM SIGN SILA3;Lo;0;L;;;;;N;;;;; +122E2;CUNEIFORM SIGN SU;Lo;0;L;;;;;N;;;;; +122E3;CUNEIFORM SIGN SU OVER SU;Lo;0;L;;;;;N;;;;; +122E4;CUNEIFORM SIGN SUD;Lo;0;L;;;;;N;;;;; +122E5;CUNEIFORM SIGN SUD2;Lo;0;L;;;;;N;;;;; +122E6;CUNEIFORM SIGN SUHUR;Lo;0;L;;;;;N;;;;; +122E7;CUNEIFORM SIGN SUM;Lo;0;L;;;;;N;;;;; +122E8;CUNEIFORM SIGN SUMASH;Lo;0;L;;;;;N;;;;; +122E9;CUNEIFORM SIGN SUR;Lo;0;L;;;;;N;;;;; +122EA;CUNEIFORM SIGN SUR9;Lo;0;L;;;;;N;;;;; +122EB;CUNEIFORM SIGN TA;Lo;0;L;;;;;N;;;;; +122EC;CUNEIFORM SIGN TA ASTERISK;Lo;0;L;;;;;N;;;;; +122ED;CUNEIFORM SIGN TA TIMES HI;Lo;0;L;;;;;N;;;;; +122EE;CUNEIFORM SIGN TA TIMES MI;Lo;0;L;;;;;N;;;;; +122EF;CUNEIFORM SIGN TA GUNU;Lo;0;L;;;;;N;;;;; +122F0;CUNEIFORM SIGN TAB;Lo;0;L;;;;;N;;;;; +122F1;CUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISH;Lo;0;L;;;;;N;;;;; +122F2;CUNEIFORM SIGN TAB SQUARED;Lo;0;L;;;;;N;;;;; +122F3;CUNEIFORM SIGN TAG;Lo;0;L;;;;;N;;;;; +122F4;CUNEIFORM SIGN TAG TIMES BI;Lo;0;L;;;;;N;;;;; +122F5;CUNEIFORM SIGN TAG TIMES GUD;Lo;0;L;;;;;N;;;;; +122F6;CUNEIFORM SIGN TAG TIMES SHE;Lo;0;L;;;;;N;;;;; +122F7;CUNEIFORM SIGN TAG TIMES SHU;Lo;0;L;;;;;N;;;;; +122F8;CUNEIFORM SIGN TAG TIMES TUG2;Lo;0;L;;;;;N;;;;; +122F9;CUNEIFORM SIGN TAG TIMES UD;Lo;0;L;;;;;N;;;;; +122FA;CUNEIFORM SIGN TAK4;Lo;0;L;;;;;N;;;;; +122FB;CUNEIFORM SIGN TAR;Lo;0;L;;;;;N;;;;; +122FC;CUNEIFORM SIGN TE;Lo;0;L;;;;;N;;;;; +122FD;CUNEIFORM SIGN TE GUNU;Lo;0;L;;;;;N;;;;; +122FE;CUNEIFORM SIGN TI;Lo;0;L;;;;;N;;;;; +122FF;CUNEIFORM SIGN TI TENU;Lo;0;L;;;;;N;;;;; +12300;CUNEIFORM SIGN TIL;Lo;0;L;;;;;N;;;;; +12301;CUNEIFORM SIGN TIR;Lo;0;L;;;;;N;;;;; +12302;CUNEIFORM SIGN TIR TIMES TAK4;Lo;0;L;;;;;N;;;;; +12303;CUNEIFORM SIGN TIR OVER TIR;Lo;0;L;;;;;N;;;;; +12304;CUNEIFORM SIGN TIR OVER TIR GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; +12305;CUNEIFORM SIGN TU;Lo;0;L;;;;;N;;;;; +12306;CUNEIFORM SIGN TUG2;Lo;0;L;;;;;N;;;;; +12307;CUNEIFORM SIGN TUK;Lo;0;L;;;;;N;;;;; +12308;CUNEIFORM SIGN TUM;Lo;0;L;;;;;N;;;;; +12309;CUNEIFORM SIGN TUR;Lo;0;L;;;;;N;;;;; +1230A;CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA;Lo;0;L;;;;;N;;;;; +1230B;CUNEIFORM SIGN U;Lo;0;L;;;;;N;;;;; +1230C;CUNEIFORM SIGN U GUD;Lo;0;L;;;;;N;;;;; +1230D;CUNEIFORM SIGN U U U;Lo;0;L;;;;;N;;;;; +1230E;CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR;Lo;0;L;;;;;N;;;;; +1230F;CUNEIFORM SIGN U OVER U SUR OVER SUR;Lo;0;L;;;;;N;;;;; +12310;CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED;Lo;0;L;;;;;N;;;;; +12311;CUNEIFORM SIGN U2;Lo;0;L;;;;;N;;;;; +12312;CUNEIFORM SIGN UB;Lo;0;L;;;;;N;;;;; +12313;CUNEIFORM SIGN UD;Lo;0;L;;;;;N;;;;; +12314;CUNEIFORM SIGN UD KUSHU2;Lo;0;L;;;;;N;;;;; +12315;CUNEIFORM SIGN UD TIMES BAD;Lo;0;L;;;;;N;;;;; +12316;CUNEIFORM SIGN UD TIMES MI;Lo;0;L;;;;;N;;;;; +12317;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;; +12318;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNU;Lo;0;L;;;;;N;;;;; +12319;CUNEIFORM SIGN UD GUNU;Lo;0;L;;;;;N;;;;; +1231A;CUNEIFORM SIGN UD SHESHIG;Lo;0;L;;;;;N;;;;; +1231B;CUNEIFORM SIGN UD SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;; +1231C;CUNEIFORM SIGN UDUG;Lo;0;L;;;;;N;;;;; +1231D;CUNEIFORM SIGN UM;Lo;0;L;;;;;N;;;;; +1231E;CUNEIFORM SIGN UM TIMES LAGAB;Lo;0;L;;;;;N;;;;; +1231F;CUNEIFORM SIGN UM TIMES ME PLUS DA;Lo;0;L;;;;;N;;;;; +12320;CUNEIFORM SIGN UM TIMES SHA3;Lo;0;L;;;;;N;;;;; +12321;CUNEIFORM SIGN UM TIMES U;Lo;0;L;;;;;N;;;;; +12322;CUNEIFORM SIGN UMBIN;Lo;0;L;;;;;N;;;;; +12323;CUNEIFORM SIGN UMUM;Lo;0;L;;;;;N;;;;; +12324;CUNEIFORM SIGN UMUM TIMES KASKAL;Lo;0;L;;;;;N;;;;; +12325;CUNEIFORM SIGN UMUM TIMES PA;Lo;0;L;;;;;N;;;;; +12326;CUNEIFORM SIGN UN;Lo;0;L;;;;;N;;;;; +12327;CUNEIFORM SIGN UN GUNU;Lo;0;L;;;;;N;;;;; +12328;CUNEIFORM SIGN UR;Lo;0;L;;;;;N;;;;; +12329;CUNEIFORM SIGN UR CROSSING UR;Lo;0;L;;;;;N;;;;; +1232A;CUNEIFORM SIGN UR SHESHIG;Lo;0;L;;;;;N;;;;; +1232B;CUNEIFORM SIGN UR2;Lo;0;L;;;;;N;;;;; +1232C;CUNEIFORM SIGN UR2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;; +1232D;CUNEIFORM SIGN UR2 TIMES A PLUS NA;Lo;0;L;;;;;N;;;;; +1232E;CUNEIFORM SIGN UR2 TIMES AL;Lo;0;L;;;;;N;;;;; +1232F;CUNEIFORM SIGN UR2 TIMES HA;Lo;0;L;;;;;N;;;;; +12330;CUNEIFORM SIGN UR2 TIMES NUN;Lo;0;L;;;;;N;;;;; +12331;CUNEIFORM SIGN UR2 TIMES U2;Lo;0;L;;;;;N;;;;; +12332;CUNEIFORM SIGN UR2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;; +12333;CUNEIFORM SIGN UR2 TIMES U2 PLUS BI;Lo;0;L;;;;;N;;;;; +12334;CUNEIFORM SIGN UR4;Lo;0;L;;;;;N;;;;; +12335;CUNEIFORM SIGN URI;Lo;0;L;;;;;N;;;;; +12336;CUNEIFORM SIGN URI3;Lo;0;L;;;;;N;;;;; +12337;CUNEIFORM SIGN URU;Lo;0;L;;;;;N;;;;; +12338;CUNEIFORM SIGN URU TIMES A;Lo;0;L;;;;;N;;;;; +12339;CUNEIFORM SIGN URU TIMES ASHGAB;Lo;0;L;;;;;N;;;;; +1233A;CUNEIFORM SIGN URU TIMES BAR;Lo;0;L;;;;;N;;;;; +1233B;CUNEIFORM SIGN URU TIMES DUN;Lo;0;L;;;;;N;;;;; +1233C;CUNEIFORM SIGN URU TIMES GA;Lo;0;L;;;;;N;;;;; +1233D;CUNEIFORM SIGN URU TIMES GAL;Lo;0;L;;;;;N;;;;; +1233E;CUNEIFORM SIGN URU TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1233F;CUNEIFORM SIGN URU TIMES GAR;Lo;0;L;;;;;N;;;;; +12340;CUNEIFORM SIGN URU TIMES GU;Lo;0;L;;;;;N;;;;; +12341;CUNEIFORM SIGN URU TIMES HA;Lo;0;L;;;;;N;;;;; +12342;CUNEIFORM SIGN URU TIMES IGI;Lo;0;L;;;;;N;;;;; +12343;CUNEIFORM SIGN URU TIMES IM;Lo;0;L;;;;;N;;;;; +12344;CUNEIFORM SIGN URU TIMES ISH;Lo;0;L;;;;;N;;;;; +12345;CUNEIFORM SIGN URU TIMES KI;Lo;0;L;;;;;N;;;;; +12346;CUNEIFORM SIGN URU TIMES LUM;Lo;0;L;;;;;N;;;;; +12347;CUNEIFORM SIGN URU TIMES MIN;Lo;0;L;;;;;N;;;;; +12348;CUNEIFORM SIGN URU TIMES PA;Lo;0;L;;;;;N;;;;; +12349;CUNEIFORM SIGN URU TIMES SHE;Lo;0;L;;;;;N;;;;; +1234A;CUNEIFORM SIGN URU TIMES SIG4;Lo;0;L;;;;;N;;;;; +1234B;CUNEIFORM SIGN URU TIMES TU;Lo;0;L;;;;;N;;;;; +1234C;CUNEIFORM SIGN URU TIMES U PLUS GUD;Lo;0;L;;;;;N;;;;; +1234D;CUNEIFORM SIGN URU TIMES UD;Lo;0;L;;;;;N;;;;; +1234E;CUNEIFORM SIGN URU TIMES URUDA;Lo;0;L;;;;;N;;;;; +1234F;CUNEIFORM SIGN URUDA;Lo;0;L;;;;;N;;;;; +12350;CUNEIFORM SIGN URUDA TIMES U;Lo;0;L;;;;;N;;;;; +12351;CUNEIFORM SIGN USH;Lo;0;L;;;;;N;;;;; +12352;CUNEIFORM SIGN USH TIMES A;Lo;0;L;;;;;N;;;;; +12353;CUNEIFORM SIGN USH TIMES KU;Lo;0;L;;;;;N;;;;; +12354;CUNEIFORM SIGN USH TIMES KUR;Lo;0;L;;;;;N;;;;; +12355;CUNEIFORM SIGN USH TIMES TAK4;Lo;0;L;;;;;N;;;;; +12356;CUNEIFORM SIGN USHX;Lo;0;L;;;;;N;;;;; +12357;CUNEIFORM SIGN USH2;Lo;0;L;;;;;N;;;;; +12358;CUNEIFORM SIGN USHUMX;Lo;0;L;;;;;N;;;;; +12359;CUNEIFORM SIGN UTUKI;Lo;0;L;;;;;N;;;;; +1235A;CUNEIFORM SIGN UZ3;Lo;0;L;;;;;N;;;;; +1235B;CUNEIFORM SIGN UZ3 TIMES KASKAL;Lo;0;L;;;;;N;;;;; +1235C;CUNEIFORM SIGN UZU;Lo;0;L;;;;;N;;;;; +1235D;CUNEIFORM SIGN ZA;Lo;0;L;;;;;N;;;;; +1235E;CUNEIFORM SIGN ZA TENU;Lo;0;L;;;;;N;;;;; +1235F;CUNEIFORM SIGN ZA SQUARED TIMES KUR;Lo;0;L;;;;;N;;;;; +12360;CUNEIFORM SIGN ZAG;Lo;0;L;;;;;N;;;;; +12361;CUNEIFORM SIGN ZAMX;Lo;0;L;;;;;N;;;;; +12362;CUNEIFORM SIGN ZE2;Lo;0;L;;;;;N;;;;; +12363;CUNEIFORM SIGN ZI;Lo;0;L;;;;;N;;;;; +12364;CUNEIFORM SIGN ZI OVER ZI;Lo;0;L;;;;;N;;;;; +12365;CUNEIFORM SIGN ZI3;Lo;0;L;;;;;N;;;;; +12366;CUNEIFORM SIGN ZIB;Lo;0;L;;;;;N;;;;; +12367;CUNEIFORM SIGN ZIB KABA TENU;Lo;0;L;;;;;N;;;;; +12368;CUNEIFORM SIGN ZIG;Lo;0;L;;;;;N;;;;; +12369;CUNEIFORM SIGN ZIZ2;Lo;0;L;;;;;N;;;;; +1236A;CUNEIFORM SIGN ZU;Lo;0;L;;;;;N;;;;; +1236B;CUNEIFORM SIGN ZU5;Lo;0;L;;;;;N;;;;; +1236C;CUNEIFORM SIGN ZU5 TIMES A;Lo;0;L;;;;;N;;;;; +1236D;CUNEIFORM SIGN ZUBUR;Lo;0;L;;;;;N;;;;; +1236E;CUNEIFORM SIGN ZUM;Lo;0;L;;;;;N;;;;; +12400;CUNEIFORM NUMERIC SIGN TWO ASH;Nl;0;L;;;;2;N;;;;; +12401;CUNEIFORM NUMERIC SIGN THREE ASH;Nl;0;L;;;;3;N;;;;; +12402;CUNEIFORM NUMERIC SIGN FOUR ASH;Nl;0;L;;;;4;N;;;;; +12403;CUNEIFORM NUMERIC SIGN FIVE ASH;Nl;0;L;;;;5;N;;;;; +12404;CUNEIFORM NUMERIC SIGN SIX ASH;Nl;0;L;;;;6;N;;;;; +12405;CUNEIFORM NUMERIC SIGN SEVEN ASH;Nl;0;L;;;;7;N;;;;; +12406;CUNEIFORM NUMERIC SIGN EIGHT ASH;Nl;0;L;;;;8;N;;;;; +12407;CUNEIFORM NUMERIC SIGN NINE ASH;Nl;0;L;;;;9;N;;;;; +12408;CUNEIFORM NUMERIC SIGN THREE DISH;Nl;0;L;;;;3;N;;;;; +12409;CUNEIFORM NUMERIC SIGN FOUR DISH;Nl;0;L;;;;4;N;;;;; +1240A;CUNEIFORM NUMERIC SIGN FIVE DISH;Nl;0;L;;;;5;N;;;;; +1240B;CUNEIFORM NUMERIC SIGN SIX DISH;Nl;0;L;;;;6;N;;;;; +1240C;CUNEIFORM NUMERIC SIGN SEVEN DISH;Nl;0;L;;;;7;N;;;;; +1240D;CUNEIFORM NUMERIC SIGN EIGHT DISH;Nl;0;L;;;;8;N;;;;; +1240E;CUNEIFORM NUMERIC SIGN NINE DISH;Nl;0;L;;;;9;N;;;;; +1240F;CUNEIFORM NUMERIC SIGN FOUR U;Nl;0;L;;;;4;N;;;;; +12410;CUNEIFORM NUMERIC SIGN FIVE U;Nl;0;L;;;;5;N;;;;; +12411;CUNEIFORM NUMERIC SIGN SIX U;Nl;0;L;;;;6;N;;;;; +12412;CUNEIFORM NUMERIC SIGN SEVEN U;Nl;0;L;;;;7;N;;;;; +12413;CUNEIFORM NUMERIC SIGN EIGHT U;Nl;0;L;;;;8;N;;;;; +12414;CUNEIFORM NUMERIC SIGN NINE U;Nl;0;L;;;;9;N;;;;; +12415;CUNEIFORM NUMERIC SIGN ONE GESH2;Nl;0;L;;;;1;N;;;;; +12416;CUNEIFORM NUMERIC SIGN TWO GESH2;Nl;0;L;;;;2;N;;;;; +12417;CUNEIFORM NUMERIC SIGN THREE GESH2;Nl;0;L;;;;3;N;;;;; +12418;CUNEIFORM NUMERIC SIGN FOUR GESH2;Nl;0;L;;;;4;N;;;;; +12419;CUNEIFORM NUMERIC SIGN FIVE GESH2;Nl;0;L;;;;5;N;;;;; +1241A;CUNEIFORM NUMERIC SIGN SIX GESH2;Nl;0;L;;;;6;N;;;;; +1241B;CUNEIFORM NUMERIC SIGN SEVEN GESH2;Nl;0;L;;;;7;N;;;;; +1241C;CUNEIFORM NUMERIC SIGN EIGHT GESH2;Nl;0;L;;;;8;N;;;;; +1241D;CUNEIFORM NUMERIC SIGN NINE GESH2;Nl;0;L;;;;9;N;;;;; +1241E;CUNEIFORM NUMERIC SIGN ONE GESHU;Nl;0;L;;;;1;N;;;;; +1241F;CUNEIFORM NUMERIC SIGN TWO GESHU;Nl;0;L;;;;2;N;;;;; +12420;CUNEIFORM NUMERIC SIGN THREE GESHU;Nl;0;L;;;;3;N;;;;; +12421;CUNEIFORM NUMERIC SIGN FOUR GESHU;Nl;0;L;;;;4;N;;;;; +12422;CUNEIFORM NUMERIC SIGN FIVE GESHU;Nl;0;L;;;;5;N;;;;; +12423;CUNEIFORM NUMERIC SIGN TWO SHAR2;Nl;0;L;;;;2;N;;;;; +12424;CUNEIFORM NUMERIC SIGN THREE SHAR2;Nl;0;L;;;;3;N;;;;; +12425;CUNEIFORM NUMERIC SIGN THREE SHAR2 VARIANT FORM;Nl;0;L;;;;3;N;;;;; +12426;CUNEIFORM NUMERIC SIGN FOUR SHAR2;Nl;0;L;;;;4;N;;;;; +12427;CUNEIFORM NUMERIC SIGN FIVE SHAR2;Nl;0;L;;;;5;N;;;;; +12428;CUNEIFORM NUMERIC SIGN SIX SHAR2;Nl;0;L;;;;6;N;;;;; +12429;CUNEIFORM NUMERIC SIGN SEVEN SHAR2;Nl;0;L;;;;7;N;;;;; +1242A;CUNEIFORM NUMERIC SIGN EIGHT SHAR2;Nl;0;L;;;;8;N;;;;; +1242B;CUNEIFORM NUMERIC SIGN NINE SHAR2;Nl;0;L;;;;9;N;;;;; +1242C;CUNEIFORM NUMERIC SIGN ONE SHARU;Nl;0;L;;;;1;N;;;;; +1242D;CUNEIFORM NUMERIC SIGN TWO SHARU;Nl;0;L;;;;2;N;;;;; +1242E;CUNEIFORM NUMERIC SIGN THREE SHARU;Nl;0;L;;;;3;N;;;;; +1242F;CUNEIFORM NUMERIC SIGN THREE SHARU VARIANT FORM;Nl;0;L;;;;3;N;;;;; +12430;CUNEIFORM NUMERIC SIGN FOUR SHARU;Nl;0;L;;;;4;N;;;;; +12431;CUNEIFORM NUMERIC SIGN FIVE SHARU;Nl;0;L;;;;5;N;;;;; +12432;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH;Nl;0;L;;;;;N;;;;; +12433;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN;Nl;0;L;;;;;N;;;;; +12434;CUNEIFORM NUMERIC SIGN ONE BURU;Nl;0;L;;;;1;N;;;;; +12435;CUNEIFORM NUMERIC SIGN TWO BURU;Nl;0;L;;;;2;N;;;;; +12436;CUNEIFORM NUMERIC SIGN THREE BURU;Nl;0;L;;;;3;N;;;;; +12437;CUNEIFORM NUMERIC SIGN THREE BURU VARIANT FORM;Nl;0;L;;;;3;N;;;;; +12438;CUNEIFORM NUMERIC SIGN FOUR BURU;Nl;0;L;;;;4;N;;;;; +12439;CUNEIFORM NUMERIC SIGN FIVE BURU;Nl;0;L;;;;5;N;;;;; +1243A;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH16;Nl;0;L;;;;3;N;;;;; +1243B;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21;Nl;0;L;;;;3;N;;;;; +1243C;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU;Nl;0;L;;;;4;N;;;;; +1243D;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU4;Nl;0;L;;;;4;N;;;;; +1243E;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU A;Nl;0;L;;;;4;N;;;;; +1243F;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU B;Nl;0;L;;;;4;N;;;;; +12440;CUNEIFORM NUMERIC SIGN SIX VARIANT FORM ASH9;Nl;0;L;;;;6;N;;;;; +12441;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3;Nl;0;L;;;;7;N;;;;; +12442;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN A;Nl;0;L;;;;7;N;;;;; +12443;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN B;Nl;0;L;;;;7;N;;;;; +12444;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU;Nl;0;L;;;;8;N;;;;; +12445;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU3;Nl;0;L;;;;8;N;;;;; +12446;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU;Nl;0;L;;;;9;N;;;;; +12447;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU3;Nl;0;L;;;;9;N;;;;; +12448;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU4;Nl;0;L;;;;9;N;;;;; +12449;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU A;Nl;0;L;;;;9;N;;;;; +1244A;CUNEIFORM NUMERIC SIGN TWO ASH TENU;Nl;0;L;;;;2;N;;;;; +1244B;CUNEIFORM NUMERIC SIGN THREE ASH TENU;Nl;0;L;;;;3;N;;;;; +1244C;CUNEIFORM NUMERIC SIGN FOUR ASH TENU;Nl;0;L;;;;4;N;;;;; +1244D;CUNEIFORM NUMERIC SIGN FIVE ASH TENU;Nl;0;L;;;;5;N;;;;; +1244E;CUNEIFORM NUMERIC SIGN SIX ASH TENU;Nl;0;L;;;;6;N;;;;; +1244F;CUNEIFORM NUMERIC SIGN ONE BAN2;Nl;0;L;;;;1;N;;;;; +12450;CUNEIFORM NUMERIC SIGN TWO BAN2;Nl;0;L;;;;2;N;;;;; +12451;CUNEIFORM NUMERIC SIGN THREE BAN2;Nl;0;L;;;;3;N;;;;; +12452;CUNEIFORM NUMERIC SIGN FOUR BAN2;Nl;0;L;;;;4;N;;;;; +12453;CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORM;Nl;0;L;;;;4;N;;;;; +12454;CUNEIFORM NUMERIC SIGN FIVE BAN2;Nl;0;L;;;;5;N;;;;; +12455;CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM;Nl;0;L;;;;5;N;;;;; +12456;CUNEIFORM NUMERIC SIGN NIGIDAMIN;Nl;0;L;;;;;N;;;;; +12457;CUNEIFORM NUMERIC SIGN NIGIDAESH;Nl;0;L;;;;;N;;;;; +12458;CUNEIFORM NUMERIC SIGN ONE ESHE3;Nl;0;L;;;;1;N;;;;; +12459;CUNEIFORM NUMERIC SIGN TWO ESHE3;Nl;0;L;;;;2;N;;;;; +1245A;CUNEIFORM NUMERIC SIGN ONE THIRD DISH;Nl;0;L;;;;1/3;N;;;;; +1245B;CUNEIFORM NUMERIC SIGN TWO THIRDS DISH;Nl;0;L;;;;2/3;N;;;;; +1245C;CUNEIFORM NUMERIC SIGN FIVE SIXTHS DISH;Nl;0;L;;;;5/6;N;;;;; +1245D;CUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM A;Nl;0;L;;;;1/3;N;;;;; +1245E;CUNEIFORM NUMERIC SIGN TWO THIRDS VARIANT FORM A;Nl;0;L;;;;2/3;N;;;;; +1245F;CUNEIFORM NUMERIC SIGN ONE EIGHTH ASH;Nl;0;L;;;;1/8;N;;;;; +12460;CUNEIFORM NUMERIC SIGN ONE QUARTER ASH;Nl;0;L;;;;1/4;N;;;;; +12461;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE SIXTH;Nl;0;L;;;;1/6;N;;;;; +12462;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER;Nl;0;L;;;;1/4;N;;;;; +12470;CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER;Po;0;L;;;;;N;;;;; +12471;CUNEIFORM PUNCTUATION SIGN VERTICAL COLON;Po;0;L;;;;;N;;;;; +12472;CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON;Po;0;L;;;;;N;;;;; +12473;CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON;Po;0;L;;;;;N;;;;; 1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; 1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;; 1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;; @@ -12954,6 +16953,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; 1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;; 1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;; +1D129;MUSICAL SYMBOL MULTIPLE MEASURE REST;So;0;L;;;;;N;;;;; 1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;; 1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;; 1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;; @@ -13134,12 +17134,82 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;; 1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;; 1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;; -1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;; -1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;; -1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;; -1D303;DIGRAM FOR EARTHLY HEAVEN;So;0;ON;;;;;N;;;;; -1D304;DIGRAM FOR EARTHLY HUMAN;So;0;ON;;;;;N;;;;; -1D305;DIGRAM FOR EARTH;So;0;ON;;;;;N;;;;; +1D200;GREEK VOCAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;; +1D201;GREEK VOCAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;; +1D202;GREEK VOCAL NOTATION SYMBOL-3;So;0;ON;;;;;N;;;;; +1D203;GREEK VOCAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;; +1D204;GREEK VOCAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;; +1D205;GREEK VOCAL NOTATION SYMBOL-6;So;0;ON;;;;;N;;;;; +1D206;GREEK VOCAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;; +1D207;GREEK VOCAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;; +1D208;GREEK VOCAL NOTATION SYMBOL-9;So;0;ON;;;;;N;;;;; +1D209;GREEK VOCAL NOTATION SYMBOL-10;So;0;ON;;;;;N;;;;; +1D20A;GREEK VOCAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;; +1D20B;GREEK VOCAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;; +1D20C;GREEK VOCAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;; +1D20D;GREEK VOCAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;; +1D20E;GREEK VOCAL NOTATION SYMBOL-15;So;0;ON;;;;;N;;;;; +1D20F;GREEK VOCAL NOTATION SYMBOL-16;So;0;ON;;;;;N;;;;; +1D210;GREEK VOCAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;; +1D211;GREEK VOCAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;; +1D212;GREEK VOCAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;; +1D213;GREEK VOCAL NOTATION SYMBOL-20;So;0;ON;;;;;N;;;;; +1D214;GREEK VOCAL NOTATION SYMBOL-21;So;0;ON;;;;;N;;;;; +1D215;GREEK VOCAL NOTATION SYMBOL-22;So;0;ON;;;;;N;;;;; +1D216;GREEK VOCAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;; +1D217;GREEK VOCAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;; +1D218;GREEK VOCAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;; +1D219;GREEK VOCAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;; +1D21A;GREEK VOCAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;; +1D21B;GREEK VOCAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;; +1D21C;GREEK VOCAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;; +1D21D;GREEK INSTRUMENTAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;; +1D21E;GREEK INSTRUMENTAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;; +1D21F;GREEK INSTRUMENTAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;; +1D220;GREEK INSTRUMENTAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;; +1D221;GREEK INSTRUMENTAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;; +1D222;GREEK INSTRUMENTAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;; +1D223;GREEK INSTRUMENTAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;; +1D224;GREEK INSTRUMENTAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;; +1D225;GREEK INSTRUMENTAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;; +1D226;GREEK INSTRUMENTAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;; +1D227;GREEK INSTRUMENTAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;; +1D228;GREEK INSTRUMENTAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;; +1D229;GREEK INSTRUMENTAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;; +1D22A;GREEK INSTRUMENTAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;; +1D22B;GREEK INSTRUMENTAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;; +1D22C;GREEK INSTRUMENTAL NOTATION SYMBOL-25;So;0;ON;;;;;N;;;;; +1D22D;GREEK INSTRUMENTAL NOTATION SYMBOL-26;So;0;ON;;;;;N;;;;; +1D22E;GREEK INSTRUMENTAL NOTATION SYMBOL-27;So;0;ON;;;;;N;;;;; +1D22F;GREEK INSTRUMENTAL NOTATION SYMBOL-29;So;0;ON;;;;;N;;;;; +1D230;GREEK INSTRUMENTAL NOTATION SYMBOL-30;So;0;ON;;;;;N;;;;; +1D231;GREEK INSTRUMENTAL NOTATION SYMBOL-32;So;0;ON;;;;;N;;;;; +1D232;GREEK INSTRUMENTAL NOTATION SYMBOL-36;So;0;ON;;;;;N;;;;; +1D233;GREEK INSTRUMENTAL NOTATION SYMBOL-37;So;0;ON;;;;;N;;;;; +1D234;GREEK INSTRUMENTAL NOTATION SYMBOL-38;So;0;ON;;;;;N;;;;; +1D235;GREEK INSTRUMENTAL NOTATION SYMBOL-39;So;0;ON;;;;;N;;;;; +1D236;GREEK INSTRUMENTAL NOTATION SYMBOL-40;So;0;ON;;;;;N;;;;; +1D237;GREEK INSTRUMENTAL NOTATION SYMBOL-42;So;0;ON;;;;;N;;;;; +1D238;GREEK INSTRUMENTAL NOTATION SYMBOL-43;So;0;ON;;;;;N;;;;; +1D239;GREEK INSTRUMENTAL NOTATION SYMBOL-45;So;0;ON;;;;;N;;;;; +1D23A;GREEK INSTRUMENTAL NOTATION SYMBOL-47;So;0;ON;;;;;N;;;;; +1D23B;GREEK INSTRUMENTAL NOTATION SYMBOL-48;So;0;ON;;;;;N;;;;; +1D23C;GREEK INSTRUMENTAL NOTATION SYMBOL-49;So;0;ON;;;;;N;;;;; +1D23D;GREEK INSTRUMENTAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;; +1D23E;GREEK INSTRUMENTAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;; +1D23F;GREEK INSTRUMENTAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;; +1D240;GREEK INSTRUMENTAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;; +1D241;GREEK INSTRUMENTAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;; +1D242;COMBINING GREEK MUSICAL TRISEME;Mn;230;NSM;;;;;N;;;;; +1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;; +1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;; +1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;; +1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;ren *;;; +1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;tian ren *;;; +1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;di ren *;;; +1D303;DIGRAM FOR EARTHLY HEAVEN;So;0;ON;;;;;N;;ren tian *;;; +1D304;DIGRAM FOR EARTHLY HUMAN;So;0;ON;;;;;N;;ren di *;;; +1D305;DIGRAM FOR EARTH;So;0;ON;;;;;N;;ren ren *;;; 1D306;TETRAGRAM FOR CENTRE;So;0;ON;;;;;N;;;;; 1D307;TETRAGRAM FOR FULL CIRCLE;So;0;ON;;;;;N;;;;; 1D308;TETRAGRAM FOR MIRED;So;0;ON;;;;;N;;;;; @@ -13221,6 +17291,24 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D354;TETRAGRAM FOR DIFFICULTIES;So;0;ON;;;;;N;;;;; 1D355;TETRAGRAM FOR LABOURING;So;0;ON;;;;;N;;;;; 1D356;TETRAGRAM FOR FOSTERING;So;0;ON;;;;;N;;;;; +1D360;COUNTING ROD UNIT DIGIT ONE;No;0;L;;;;1;N;;;;; +1D361;COUNTING ROD UNIT DIGIT TWO;No;0;L;;;;2;N;;;;; +1D362;COUNTING ROD UNIT DIGIT THREE;No;0;L;;;;3;N;;;;; +1D363;COUNTING ROD UNIT DIGIT FOUR;No;0;L;;;;4;N;;;;; +1D364;COUNTING ROD UNIT DIGIT FIVE;No;0;L;;;;5;N;;;;; +1D365;COUNTING ROD UNIT DIGIT SIX;No;0;L;;;;6;N;;;;; +1D366;COUNTING ROD UNIT DIGIT SEVEN;No;0;L;;;;7;N;;;;; +1D367;COUNTING ROD UNIT DIGIT EIGHT;No;0;L;;;;8;N;;;;; +1D368;COUNTING ROD UNIT DIGIT NINE;No;0;L;;;;9;N;;;;; +1D369;COUNTING ROD TENS DIGIT ONE;No;0;L;;;;10;N;;;;; +1D36A;COUNTING ROD TENS DIGIT TWO;No;0;L;;;;20;N;;;;; +1D36B;COUNTING ROD TENS DIGIT THREE;No;0;L;;;;30;N;;;;; +1D36C;COUNTING ROD TENS DIGIT FOUR;No;0;L;;;;40;N;;;;; +1D36D;COUNTING ROD TENS DIGIT FIVE;No;0;L;;;;50;N;;;;; +1D36E;COUNTING ROD TENS DIGIT SIX;No;0;L;;;;60;N;;;;; +1D36F;COUNTING ROD TENS DIGIT SEVEN;No;0;L;;;;70;N;;;;; +1D370;COUNTING ROD TENS DIGIT EIGHT;No;0;L;;;;80;N;;;;; +1D371;COUNTING ROD TENS DIGIT NINE;No;0;L;;;;90;N;;;;; 1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; 1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; 1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; @@ -13873,6 +17961,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; 1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; 1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D6A4;MATHEMATICAL ITALIC SMALL DOTLESS I;Ll;0;L;<font> 0131;;;;N;;;;; +1D6A5;MATHEMATICAL ITALIC SMALL DOTLESS J;Ll;0;L;<font> 0237;;;;N;;;;; 1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; 1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; 1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; @@ -13924,7 +18014,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; 1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; 1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;Y;;;;; 1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; 1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; 1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; @@ -13982,7 +18072,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; 1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; 1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;Y;;;;; 1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; 1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; 1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; @@ -14040,7 +18130,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; 1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; 1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;Y;;;;; 1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; 1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; 1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; @@ -14098,7 +18188,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; 1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; 1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;Y;;;;; 1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; 1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; 1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; @@ -14156,13 +18246,15 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; 1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; 1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;Y;;;;; 1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; 1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; 1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; 1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; 1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; 1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; +1D7CA;MATHEMATICAL BOLD CAPITAL DIGAMMA;Lu;0;L;<font> 03DC;;;;N;;;;; +1D7CB;MATHEMATICAL BOLD SMALL DIGAMMA;Ll;0;L;<font> 03DD;;;;N;;;;; 1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; 1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; 1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; @@ -14213,6 +18305,150 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; 1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; 1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; +1F000;MAHJONG TILE EAST WIND;So;0;ON;;;;;N;;;;; +1F001;MAHJONG TILE SOUTH WIND;So;0;ON;;;;;N;;;;; +1F002;MAHJONG TILE WEST WIND;So;0;ON;;;;;N;;;;; +1F003;MAHJONG TILE NORTH WIND;So;0;ON;;;;;N;;;;; +1F004;MAHJONG TILE RED DRAGON;So;0;ON;;;;;N;;;;; +1F005;MAHJONG TILE GREEN DRAGON;So;0;ON;;;;;N;;;;; +1F006;MAHJONG TILE WHITE DRAGON;So;0;ON;;;;;N;;;;; +1F007;MAHJONG TILE ONE OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F008;MAHJONG TILE TWO OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F009;MAHJONG TILE THREE OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00A;MAHJONG TILE FOUR OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00B;MAHJONG TILE FIVE OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00C;MAHJONG TILE SIX OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00D;MAHJONG TILE SEVEN OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00E;MAHJONG TILE EIGHT OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00F;MAHJONG TILE NINE OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F010;MAHJONG TILE ONE OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F011;MAHJONG TILE TWO OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F012;MAHJONG TILE THREE OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F013;MAHJONG TILE FOUR OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F014;MAHJONG TILE FIVE OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F015;MAHJONG TILE SIX OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F016;MAHJONG TILE SEVEN OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F017;MAHJONG TILE EIGHT OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F018;MAHJONG TILE NINE OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F019;MAHJONG TILE ONE OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01A;MAHJONG TILE TWO OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01B;MAHJONG TILE THREE OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01C;MAHJONG TILE FOUR OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01D;MAHJONG TILE FIVE OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01E;MAHJONG TILE SIX OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01F;MAHJONG TILE SEVEN OF CIRCLES;So;0;ON;;;;;N;;;;; +1F020;MAHJONG TILE EIGHT OF CIRCLES;So;0;ON;;;;;N;;;;; +1F021;MAHJONG TILE NINE OF CIRCLES;So;0;ON;;;;;N;;;;; +1F022;MAHJONG TILE PLUM;So;0;ON;;;;;N;;;;; +1F023;MAHJONG TILE ORCHID;So;0;ON;;;;;N;;;;; +1F024;MAHJONG TILE BAMBOO;So;0;ON;;;;;N;;;;; +1F025;MAHJONG TILE CHRYSANTHEMUM;So;0;ON;;;;;N;;;;; +1F026;MAHJONG TILE SPRING;So;0;ON;;;;;N;;;;; +1F027;MAHJONG TILE SUMMER;So;0;ON;;;;;N;;;;; +1F028;MAHJONG TILE AUTUMN;So;0;ON;;;;;N;;;;; +1F029;MAHJONG TILE WINTER;So;0;ON;;;;;N;;;;; +1F02A;MAHJONG TILE JOKER;So;0;ON;;;;;N;;;;; +1F02B;MAHJONG TILE BACK;So;0;ON;;;;;N;;;;; +1F030;DOMINO TILE HORIZONTAL BACK;So;0;ON;;;;;N;;;;; +1F031;DOMINO TILE HORIZONTAL-00-00;So;0;ON;;;;;N;;;;; +1F032;DOMINO TILE HORIZONTAL-00-01;So;0;ON;;;;;N;;;;; +1F033;DOMINO TILE HORIZONTAL-00-02;So;0;ON;;;;;N;;;;; +1F034;DOMINO TILE HORIZONTAL-00-03;So;0;ON;;;;;N;;;;; +1F035;DOMINO TILE HORIZONTAL-00-04;So;0;ON;;;;;N;;;;; +1F036;DOMINO TILE HORIZONTAL-00-05;So;0;ON;;;;;N;;;;; +1F037;DOMINO TILE HORIZONTAL-00-06;So;0;ON;;;;;N;;;;; +1F038;DOMINO TILE HORIZONTAL-01-00;So;0;ON;;;;;N;;;;; +1F039;DOMINO TILE HORIZONTAL-01-01;So;0;ON;;;;;N;;;;; +1F03A;DOMINO TILE HORIZONTAL-01-02;So;0;ON;;;;;N;;;;; +1F03B;DOMINO TILE HORIZONTAL-01-03;So;0;ON;;;;;N;;;;; +1F03C;DOMINO TILE HORIZONTAL-01-04;So;0;ON;;;;;N;;;;; +1F03D;DOMINO TILE HORIZONTAL-01-05;So;0;ON;;;;;N;;;;; +1F03E;DOMINO TILE HORIZONTAL-01-06;So;0;ON;;;;;N;;;;; +1F03F;DOMINO TILE HORIZONTAL-02-00;So;0;ON;;;;;N;;;;; +1F040;DOMINO TILE HORIZONTAL-02-01;So;0;ON;;;;;N;;;;; +1F041;DOMINO TILE HORIZONTAL-02-02;So;0;ON;;;;;N;;;;; +1F042;DOMINO TILE HORIZONTAL-02-03;So;0;ON;;;;;N;;;;; +1F043;DOMINO TILE HORIZONTAL-02-04;So;0;ON;;;;;N;;;;; +1F044;DOMINO TILE HORIZONTAL-02-05;So;0;ON;;;;;N;;;;; +1F045;DOMINO TILE HORIZONTAL-02-06;So;0;ON;;;;;N;;;;; +1F046;DOMINO TILE HORIZONTAL-03-00;So;0;ON;;;;;N;;;;; +1F047;DOMINO TILE HORIZONTAL-03-01;So;0;ON;;;;;N;;;;; +1F048;DOMINO TILE HORIZONTAL-03-02;So;0;ON;;;;;N;;;;; +1F049;DOMINO TILE HORIZONTAL-03-03;So;0;ON;;;;;N;;;;; +1F04A;DOMINO TILE HORIZONTAL-03-04;So;0;ON;;;;;N;;;;; +1F04B;DOMINO TILE HORIZONTAL-03-05;So;0;ON;;;;;N;;;;; +1F04C;DOMINO TILE HORIZONTAL-03-06;So;0;ON;;;;;N;;;;; +1F04D;DOMINO TILE HORIZONTAL-04-00;So;0;ON;;;;;N;;;;; +1F04E;DOMINO TILE HORIZONTAL-04-01;So;0;ON;;;;;N;;;;; +1F04F;DOMINO TILE HORIZONTAL-04-02;So;0;ON;;;;;N;;;;; +1F050;DOMINO TILE HORIZONTAL-04-03;So;0;ON;;;;;N;;;;; +1F051;DOMINO TILE HORIZONTAL-04-04;So;0;ON;;;;;N;;;;; +1F052;DOMINO TILE HORIZONTAL-04-05;So;0;ON;;;;;N;;;;; +1F053;DOMINO TILE HORIZONTAL-04-06;So;0;ON;;;;;N;;;;; +1F054;DOMINO TILE HORIZONTAL-05-00;So;0;ON;;;;;N;;;;; +1F055;DOMINO TILE HORIZONTAL-05-01;So;0;ON;;;;;N;;;;; +1F056;DOMINO TILE HORIZONTAL-05-02;So;0;ON;;;;;N;;;;; +1F057;DOMINO TILE HORIZONTAL-05-03;So;0;ON;;;;;N;;;;; +1F058;DOMINO TILE HORIZONTAL-05-04;So;0;ON;;;;;N;;;;; +1F059;DOMINO TILE HORIZONTAL-05-05;So;0;ON;;;;;N;;;;; +1F05A;DOMINO TILE HORIZONTAL-05-06;So;0;ON;;;;;N;;;;; +1F05B;DOMINO TILE HORIZONTAL-06-00;So;0;ON;;;;;N;;;;; +1F05C;DOMINO TILE HORIZONTAL-06-01;So;0;ON;;;;;N;;;;; +1F05D;DOMINO TILE HORIZONTAL-06-02;So;0;ON;;;;;N;;;;; +1F05E;DOMINO TILE HORIZONTAL-06-03;So;0;ON;;;;;N;;;;; +1F05F;DOMINO TILE HORIZONTAL-06-04;So;0;ON;;;;;N;;;;; +1F060;DOMINO TILE HORIZONTAL-06-05;So;0;ON;;;;;N;;;;; +1F061;DOMINO TILE HORIZONTAL-06-06;So;0;ON;;;;;N;;;;; +1F062;DOMINO TILE VERTICAL BACK;So;0;ON;;;;;N;;;;; +1F063;DOMINO TILE VERTICAL-00-00;So;0;ON;;;;;N;;;;; +1F064;DOMINO TILE VERTICAL-00-01;So;0;ON;;;;;N;;;;; +1F065;DOMINO TILE VERTICAL-00-02;So;0;ON;;;;;N;;;;; +1F066;DOMINO TILE VERTICAL-00-03;So;0;ON;;;;;N;;;;; +1F067;DOMINO TILE VERTICAL-00-04;So;0;ON;;;;;N;;;;; +1F068;DOMINO TILE VERTICAL-00-05;So;0;ON;;;;;N;;;;; +1F069;DOMINO TILE VERTICAL-00-06;So;0;ON;;;;;N;;;;; +1F06A;DOMINO TILE VERTICAL-01-00;So;0;ON;;;;;N;;;;; +1F06B;DOMINO TILE VERTICAL-01-01;So;0;ON;;;;;N;;;;; +1F06C;DOMINO TILE VERTICAL-01-02;So;0;ON;;;;;N;;;;; +1F06D;DOMINO TILE VERTICAL-01-03;So;0;ON;;;;;N;;;;; +1F06E;DOMINO TILE VERTICAL-01-04;So;0;ON;;;;;N;;;;; +1F06F;DOMINO TILE VERTICAL-01-05;So;0;ON;;;;;N;;;;; +1F070;DOMINO TILE VERTICAL-01-06;So;0;ON;;;;;N;;;;; +1F071;DOMINO TILE VERTICAL-02-00;So;0;ON;;;;;N;;;;; +1F072;DOMINO TILE VERTICAL-02-01;So;0;ON;;;;;N;;;;; +1F073;DOMINO TILE VERTICAL-02-02;So;0;ON;;;;;N;;;;; +1F074;DOMINO TILE VERTICAL-02-03;So;0;ON;;;;;N;;;;; +1F075;DOMINO TILE VERTICAL-02-04;So;0;ON;;;;;N;;;;; +1F076;DOMINO TILE VERTICAL-02-05;So;0;ON;;;;;N;;;;; +1F077;DOMINO TILE VERTICAL-02-06;So;0;ON;;;;;N;;;;; +1F078;DOMINO TILE VERTICAL-03-00;So;0;ON;;;;;N;;;;; +1F079;DOMINO TILE VERTICAL-03-01;So;0;ON;;;;;N;;;;; +1F07A;DOMINO TILE VERTICAL-03-02;So;0;ON;;;;;N;;;;; +1F07B;DOMINO TILE VERTICAL-03-03;So;0;ON;;;;;N;;;;; +1F07C;DOMINO TILE VERTICAL-03-04;So;0;ON;;;;;N;;;;; +1F07D;DOMINO TILE VERTICAL-03-05;So;0;ON;;;;;N;;;;; +1F07E;DOMINO TILE VERTICAL-03-06;So;0;ON;;;;;N;;;;; +1F07F;DOMINO TILE VERTICAL-04-00;So;0;ON;;;;;N;;;;; +1F080;DOMINO TILE VERTICAL-04-01;So;0;ON;;;;;N;;;;; +1F081;DOMINO TILE VERTICAL-04-02;So;0;ON;;;;;N;;;;; +1F082;DOMINO TILE VERTICAL-04-03;So;0;ON;;;;;N;;;;; +1F083;DOMINO TILE VERTICAL-04-04;So;0;ON;;;;;N;;;;; +1F084;DOMINO TILE VERTICAL-04-05;So;0;ON;;;;;N;;;;; +1F085;DOMINO TILE VERTICAL-04-06;So;0;ON;;;;;N;;;;; +1F086;DOMINO TILE VERTICAL-05-00;So;0;ON;;;;;N;;;;; +1F087;DOMINO TILE VERTICAL-05-01;So;0;ON;;;;;N;;;;; +1F088;DOMINO TILE VERTICAL-05-02;So;0;ON;;;;;N;;;;; +1F089;DOMINO TILE VERTICAL-05-03;So;0;ON;;;;;N;;;;; +1F08A;DOMINO TILE VERTICAL-05-04;So;0;ON;;;;;N;;;;; +1F08B;DOMINO TILE VERTICAL-05-05;So;0;ON;;;;;N;;;;; +1F08C;DOMINO TILE VERTICAL-05-06;So;0;ON;;;;;N;;;;; +1F08D;DOMINO TILE VERTICAL-06-00;So;0;ON;;;;;N;;;;; +1F08E;DOMINO TILE VERTICAL-06-01;So;0;ON;;;;;N;;;;; +1F08F;DOMINO TILE VERTICAL-06-02;So;0;ON;;;;;N;;;;; +1F090;DOMINO TILE VERTICAL-06-03;So;0;ON;;;;;N;;;;; +1F091;DOMINO TILE VERTICAL-06-04;So;0;ON;;;;;N;;;;; +1F092;DOMINO TILE VERTICAL-06-05;So;0;ON;;;;;N;;;;; +1F093;DOMINO TILE VERTICAL-06-06;So;0;ON;;;;;N;;;;; 20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;; 2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;; 2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;; @@ -14359,7 +18595,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;; 2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;; 2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;; -2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;;N;;;;; +2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;9;N;;;;; 2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;; 2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;; 2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;; diff --git a/jdk/make/tools/UnicodeData/VERSION b/jdk/make/tools/UnicodeData/VERSION new file mode 100644 index 00000000000..831446cbd27 --- /dev/null +++ b/jdk/make/tools/UnicodeData/VERSION @@ -0,0 +1 @@ +5.1.0 diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java index 08da84856b7..9660d82603a 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java @@ -153,7 +153,7 @@ public class GIFImageMetadata extends GIFMetadata { node.setAttribute("imageWidth", Integer.toString(imageWidth)); node.setAttribute("imageHeight", Integer.toString(imageHeight)); node.setAttribute("interlaceFlag", - interlaceFlag ? "true" : "false"); + interlaceFlag ? "TRUE" : "FALSE"); root.appendChild(node); // Local color table @@ -185,9 +185,9 @@ public class GIFImageMetadata extends GIFMetadata { node.setAttribute("disposalMethod", disposalMethodNames[disposalMethod]); node.setAttribute("userInputFlag", - userInputFlag ? "true" : "false"); + userInputFlag ? "TRUE" : "FALSE"); node.setAttribute("transparentColorFlag", - transparentColorFlag ? "true" : "false"); + transparentColorFlag ? "TRUE" : "FALSE"); node.setAttribute("delayTime", Integer.toString(delayTime)); node.setAttribute("transparentColorIndex", diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java index 4c7903bfe84..89f735d8793 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java @@ -55,6 +55,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.sun.imageio.plugins.common.LZWCompressor; import com.sun.imageio.plugins.common.PaletteBuilder; +import sun.awt.image.ByteComponentRaster; public class GIFImageWriter extends ImageWriter { private static final boolean DEBUG = false; // XXX false for release! @@ -905,10 +906,18 @@ public class GIFImageWriter extends ImageWriter { LZWCompressor compressor = new LZWCompressor(stream, initCodeSize, false); + /* At this moment we know that input image is indexed image. + * We can directly copy data iff: + * - no subsampling required (periodX = 1, periodY = 0) + * - we can access data directly (image is non-tiled, + * i.e. image data are in single block) + * - we can calculate offset in data buffer (next 3 lines) + */ boolean isOptimizedCase = periodX == 1 && periodY == 1 && - sampleModel instanceof ComponentSampleModel && image.getNumXTiles() == 1 && image.getNumYTiles() == 1 && + sampleModel instanceof ComponentSampleModel && + image.getTile(0, 0) instanceof ByteComponentRaster && image.getTile(0, 0).getDataBuffer() instanceof DataBufferByte; int numRowsWritten = 0; @@ -921,11 +930,14 @@ public class GIFImageWriter extends ImageWriter { if (DEBUG) System.out.println("Writing interlaced"); if (isOptimizedCase) { - Raster tile = image.getTile(0, 0); + ByteComponentRaster tile = + (ByteComponentRaster)image.getTile(0, 0); byte[] data = ((DataBufferByte)tile.getDataBuffer()).getData(); ComponentSampleModel csm = (ComponentSampleModel)tile.getSampleModel(); int offset = csm.getOffset(sourceXOffset, sourceYOffset, 0); + // take into account the raster data offset + offset += tile.getDataOffset(0); int lineStride = csm.getScanlineStride(); writeRowsOpt(data, offset, lineStride, compressor, diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java index 42dfbd0bed9..8acdaa2db49 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java @@ -158,13 +158,10 @@ abstract class GIFMetadata extends IIOMetadata { } } String value = attr.getNodeValue(); - // XXX Should be able to use equals() here instead of - // equalsIgnoreCase() but some boolean attributes are incorrectly - // set to "true" or "false" by the J2SE core metadata classes - // getAsTree() method (which are duplicated above). See bug 5082756. - if (value.equalsIgnoreCase("TRUE")) { + // Allow lower case booleans for backward compatibility, #5082756 + if (value.equals("TRUE") || value.equals("true")) { return true; - } else if (value.equalsIgnoreCase("FALSE")) { + } else if (value.equals("FALSE") || value.equals("false")) { return false; } else { fatal(node, "Attribute " + name + " must be 'TRUE' or 'FALSE'!"); diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java index 0979bf3d849..bc0a784b272 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java @@ -202,7 +202,7 @@ public class GIFStreamMetadata extends GIFMetadata { compression_node.appendChild(node); node = new IIOMetadataNode("Lossless"); - node.setAttribute("value", "true"); + node.setAttribute("value", "TRUE"); compression_node.appendChild(node); // NumProgressiveScans not in stream diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java index 883bd1a7447..d59a8885c9b 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java @@ -1003,7 +1003,7 @@ class JFIFMarkerSegment extends MarkerSegment { 3, new int [] {0, 1, 2}, null); - ColorModel cm = new ComponentColorModel(JPEG.sRGB, + ColorModel cm = new ComponentColorModel(JPEG.JCS.sRGB, false, false, ColorModel.OPAQUE, diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java index b16669bc089..3ed5c5083c3 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java @@ -208,15 +208,24 @@ public class JPEG { public static final int [] bOffsRGB = { 2, 1, 0 }; - protected static final ColorSpace sRGB = - ColorSpace.getInstance(ColorSpace.CS_sRGB); - protected static ColorSpace YCC = null; // Can't be final + /* These are kept in the inner class to avoid static initialization + * of the CMM class until someone actually needs it. + * (e.g. do not init CMM on the request for jpeg mime types) + */ + public static class JCS { + public static final ColorSpace sRGB = + ColorSpace.getInstance(ColorSpace.CS_sRGB); + public static final ColorSpace YCC; - static { - try { - YCC = ColorSpace.getInstance(ColorSpace.CS_PYCC); - } catch (IllegalArgumentException e) { - // PYCC.pf may not always be installed + static { + ColorSpace cs = null; + try { + cs = ColorSpace.getInstance(ColorSpace.CS_PYCC); + } catch (IllegalArgumentException e) { + // PYCC.pf may not always be installed + } finally { + YCC = cs; + } } } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index 48afd2f354c..faf8261544c 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -228,31 +228,31 @@ public class JPEGImageReader extends ImageReader { (BufferedImage.TYPE_BYTE_GRAY); defaultTypes[JPEG.JCS_RGB] = ImageTypeSpecifier.createInterleaved - (JPEG.sRGB, + (JPEG.JCS.sRGB, JPEG.bOffsRGB, DataBuffer.TYPE_BYTE, false, false); defaultTypes[JPEG.JCS_RGBA] = ImageTypeSpecifier.createPacked - (JPEG.sRGB, + (JPEG.JCS.sRGB, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, DataBuffer.TYPE_INT, false); - if (JPEG.YCC != null) { + if (JPEG.JCS.YCC != null) { defaultTypes[JPEG.JCS_YCC] = ImageTypeSpecifier.createInterleaved - (JPEG.YCC, + (JPEG.JCS.YCC, JPEG.bandOffsets[2], DataBuffer.TYPE_BYTE, false, false); defaultTypes[JPEG.JCS_YCCA] = ImageTypeSpecifier.createInterleaved - (JPEG.YCC, + (JPEG.JCS.YCC, JPEG.bandOffsets[3], DataBuffer.TYPE_BYTE, true, @@ -774,7 +774,7 @@ public class JPEGImageReader extends ImageReader { case JPEG.JCS_RGB: list.add(raw); list.add(getImageType(JPEG.JCS_GRAYSCALE)); - if (JPEG.YCC != null) { + if (JPEG.JCS.YCC != null) { list.add(getImageType(JPEG.JCS_YCC)); } break; @@ -811,7 +811,7 @@ public class JPEGImageReader extends ImageReader { } list.add(getImageType(JPEG.JCS_GRAYSCALE)); - if (JPEG.YCC != null) { // Might be null if PYCC.pf not installed + if (JPEG.JCS.YCC != null) { // Might be null if PYCC.pf not installed list.add(getImageType(JPEG.JCS_YCC)); } break; @@ -893,7 +893,7 @@ public class JPEGImageReader extends ImageReader { (!cs.isCS_sRGB()) && (cm.getNumComponents() == numComponents)) { // Target isn't sRGB, so convert from sRGB to the target - convert = new ColorConvertOp(JPEG.sRGB, cs, null); + convert = new ColorConvertOp(JPEG.JCS.sRGB, cs, null); } else if (csType != ColorSpace.TYPE_RGB) { throw new IIOException("Incompatible color conversion"); } @@ -906,18 +906,18 @@ public class JPEGImageReader extends ImageReader { } break; case JPEG.JCS_YCC: - if (JPEG.YCC == null) { // We can't do YCC at all + if (JPEG.JCS.YCC == null) { // We can't do YCC at all throw new IIOException("Incompatible color conversion"); } - if ((cs != JPEG.YCC) && + if ((cs != JPEG.JCS.YCC) && (cm.getNumComponents() == numComponents)) { - convert = new ColorConvertOp(JPEG.YCC, cs, null); + convert = new ColorConvertOp(JPEG.JCS.YCC, cs, null); } break; case JPEG.JCS_YCCA: // No conversions available; image must be YCCA - if ((JPEG.YCC == null) || // We can't do YCC at all - (cs != JPEG.YCC) || + if ((JPEG.JCS.YCC == null) || // We can't do YCC at all + (cs != JPEG.JCS.YCC) || (cm.getNumComponents() != numComponents)) { throw new IIOException("Incompatible color conversion"); } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java index 5bed06158af..13327e3ea9c 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java @@ -39,8 +39,6 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { private static String [] writerSpiNames = {"com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi"}; - private boolean registered = false; - public JPEGImageReaderSpi() { super(JPEG.vendor, JPEG.version, @@ -61,26 +59,6 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { ); } - public void onRegistration(ServiceRegistry registry, - Class<?> category) { - if (registered) { - return; - } - try { - java.security.AccessController.doPrivileged( - new sun.security.action.LoadLibraryAction("jpeg")); - // Stuff it all into one lib for first pass - //java.security.AccessController.doPrivileged( - //new sun.security.action.LoadLibraryAction("imageioIJG")); - } catch (Throwable e) { // Fail on any Throwable - // if it can't be loaded, deregister and return - registry.deregisterServiceProvider(this); - return; - } - - registered = true; - } - public String getDescription(Locale locale) { return "Standard JPEG Image Reader"; } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java index 0fbe8f33945..9c585047faa 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java @@ -812,13 +812,13 @@ public class JPEGImageWriter extends ImageWriter { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { if (!alpha) { if (jfif != null) { convertTosRGB = true; convertOp = new ColorConvertOp(cs, - JPEG.sRGB, + JPEG.JCS.sRGB, null); outCsType = JPEG.JCS_YCbCr; } else if (adobe != null) { @@ -1494,7 +1494,7 @@ public class JPEGImageWriter extends ImageWriter { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { if (alpha) { retval = JPEG.JCS_YCCA; } else { @@ -1533,7 +1533,7 @@ public class JPEGImageWriter extends ImageWriter { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { if (alpha) { retval = JPEG.JCS_YCCA; } else { @@ -1579,7 +1579,7 @@ public class JPEGImageWriter extends ImageWriter { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { if (alpha) { retval = JPEG.JCS_YCCA; } else { diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java index 936c65c544f..717b4360794 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java @@ -42,8 +42,6 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { private static String [] readerSpiNames = {"com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi"}; - private boolean registered = false; - public JPEGImageWriterSpi() { super(JPEG.vendor, JPEG.version, @@ -68,23 +66,6 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { return "Standard JPEG Image Writer"; } - public void onRegistration(ServiceRegistry registry, - Class<?> category) { - if (registered) { - return; - } - try { - java.security.AccessController.doPrivileged( - new sun.security.action.LoadLibraryAction("jpeg")); - } catch (Throwable e) { // Fail on any Throwable - // if it can't be loaded, deregister and return - registry.deregisterServiceProvider(this); - return; - } - - registered = true; - } - public boolean isFormatLossless() { return false; } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index 7f753341c93..044f7d632f6 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -490,7 +490,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { wantJFIF = false; componentIDs[0] = (byte) 'Y'; componentIDs[1] = (byte) 'C'; @@ -955,7 +955,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Lossless - false IIOMetadataNode lossless = new IIOMetadataNode("Lossless"); - lossless.setAttribute("value", "false"); + lossless.setAttribute("value", "FALSE"); compression.appendChild(lossless); // NumProgressiveScans - count sos segments diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java index 84a593264be..f35165420e9 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java @@ -37,6 +37,7 @@ import java.awt.image.WritableRaster; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.DataInputStream; +import java.io.EOFException; import java.io.InputStream; import java.io.IOException; import java.io.SequenceInputStream; @@ -59,7 +60,7 @@ import com.sun.imageio.plugins.common.SubImageInputStream; import java.io.ByteArrayOutputStream; import sun.awt.image.ByteInterleavedRaster; -class PNGImageDataEnumeration implements Enumeration { +class PNGImageDataEnumeration implements Enumeration<InputStream> { boolean firstTime = true; ImageInputStream stream; @@ -72,7 +73,7 @@ class PNGImageDataEnumeration implements Enumeration { int type = stream.readInt(); // skip chunk type } - public Object nextElement() { + public InputStream nextElement() { try { firstTime = false; ImageInputStream iis = new SubImageInputStream(stream, length); @@ -207,25 +208,17 @@ public class PNGImageReader extends ImageReader { resetStreamSettings(); } - private String readNullTerminatedString(String charset) throws IOException { + private String readNullTerminatedString(String charset, int maxLen) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int b; - while ((b = stream.read()) != 0) { + int count = 0; + while ((maxLen > count++) && ((b = stream.read()) != 0)) { + if (b == -1) throw new EOFException(); baos.write(b); } return new String(baos.toByteArray(), charset); } - private String readNullTerminatedString() throws IOException { - StringBuilder b = new StringBuilder(); - int c; - - while ((c = stream.read()) != 0) { - b.append((char)c); - } - return b.toString(); - } - private void readHeader() throws IIOException { if (gotHeader) { return; @@ -434,7 +427,7 @@ public class PNGImageReader extends ImageReader { } private void parse_iCCP_chunk(int chunkLength) throws IOException { - String keyword = readNullTerminatedString(); + String keyword = readNullTerminatedString("ISO-8859-1", 80); metadata.iCCP_profileName = keyword; metadata.iCCP_compressionMethod = stream.readUnsignedByte(); @@ -450,7 +443,7 @@ public class PNGImageReader extends ImageReader { private void parse_iTXt_chunk(int chunkLength) throws IOException { long chunkStart = stream.getStreamPosition(); - String keyword = readNullTerminatedString(); + String keyword = readNullTerminatedString("ISO-8859-1", 80); metadata.iTXt_keyword.add(keyword); int compressionFlag = stream.readUnsignedByte(); @@ -459,15 +452,17 @@ public class PNGImageReader extends ImageReader { int compressionMethod = stream.readUnsignedByte(); metadata.iTXt_compressionMethod.add(Integer.valueOf(compressionMethod)); - String languageTag = readNullTerminatedString("UTF8"); + String languageTag = readNullTerminatedString("UTF8", 80); metadata.iTXt_languageTag.add(languageTag); + long pos = stream.getStreamPosition(); + int maxLen = (int)(chunkStart + chunkLength - pos); String translatedKeyword = - readNullTerminatedString("UTF8"); + readNullTerminatedString("UTF8", maxLen); metadata.iTXt_translatedKeyword.add(translatedKeyword); String text; - long pos = stream.getStreamPosition(); + pos = stream.getStreamPosition(); byte[] b = new byte[(int)(chunkStart + chunkLength - pos)]; stream.readFully(b); @@ -511,7 +506,7 @@ public class PNGImageReader extends ImageReader { private void parse_sPLT_chunk(int chunkLength) throws IOException, IIOException { - metadata.sPLT_paletteName = readNullTerminatedString(); + metadata.sPLT_paletteName = readNullTerminatedString("ISO-8859-1", 80); chunkLength -= metadata.sPLT_paletteName.length() + 1; int sampleDepth = stream.readUnsignedByte(); @@ -554,12 +549,12 @@ public class PNGImageReader extends ImageReader { } private void parse_tEXt_chunk(int chunkLength) throws IOException { - String keyword = readNullTerminatedString(); + String keyword = readNullTerminatedString("ISO-8859-1", 80); metadata.tEXt_keyword.add(keyword); byte[] b = new byte[chunkLength - keyword.length() - 1]; stream.readFully(b); - metadata.tEXt_text.add(new String(b)); + metadata.tEXt_text.add(new String(b, "ISO-8859-1")); } private void parse_tIME_chunk() throws IOException { @@ -640,7 +635,7 @@ public class PNGImageReader extends ImageReader { } private void parse_zTXt_chunk(int chunkLength) throws IOException { - String keyword = readNullTerminatedString(); + String keyword = readNullTerminatedString("ISO-8859-1", 80); metadata.zTXt_keyword.add(keyword); int method = stream.readUnsignedByte(); @@ -648,7 +643,7 @@ public class PNGImageReader extends ImageReader { byte[] b = new byte[chunkLength - keyword.length() - 2]; stream.readFully(b); - metadata.zTXt_text.add(new String(inflate(b))); + metadata.zTXt_text.add(new String(inflate(b), "ISO-8859-1")); } private void readMetadata() throws IIOException { @@ -1263,7 +1258,7 @@ public class PNGImageReader extends ImageReader { try { stream.seek(imageStartPosition); - Enumeration e = new PNGImageDataEnumeration(stream); + Enumeration<InputStream> e = new PNGImageDataEnumeration(stream); InputStream is = new SequenceInputStream(e); /* InflaterInputStream uses an Inflater instance which consumes diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java index ea4233a68ea..0f9cc785f92 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java @@ -674,13 +674,8 @@ public class PNGImageWriter extends ImageWriter { private byte[] deflate(byte[] b) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DeflaterOutputStream dos = new DeflaterOutputStream(baos); - - int len = b.length; - for (int i = 0; i < len; i++) { - dos.write((int)(0xff & b[i])); - } + dos.write(b); dos.close(); - return baos.toByteArray(); } @@ -736,7 +731,7 @@ public class PNGImageWriter extends ImageWriter { cs.writeByte(compressionMethod); String text = (String)textIter.next(); - cs.write(deflate(text.getBytes())); + cs.write(deflate(text.getBytes("ISO-8859-1"))); cs.finish(); } } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java index 5475fc79651..9da72298884 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java @@ -211,8 +211,8 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { public int sRGB_renderingIntent; // tEXt chunk - public ArrayList tEXt_keyword = new ArrayList(); // 1-79 char Strings - public ArrayList tEXt_text = new ArrayList(); // Strings + public ArrayList<String> tEXt_keyword = new ArrayList<String>(); // 1-79 characters + public ArrayList<String> tEXt_text = new ArrayList<String>(); // tIME chunk public boolean tIME_present; @@ -235,13 +235,13 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { public int tRNS_blue; // zTXt chunk - public ArrayList zTXt_keyword = new ArrayList(); // Strings - public ArrayList zTXt_compressionMethod = new ArrayList(); // Integers - public ArrayList zTXt_text = new ArrayList(); // Strings + public ArrayList<String> zTXt_keyword = new ArrayList<String>(); + public ArrayList<Integer> zTXt_compressionMethod = new ArrayList<Integer>(); + public ArrayList<String> zTXt_text = new ArrayList<String>(); // Unknown chunks - public ArrayList unknownChunkType = new ArrayList(); // Strings - public ArrayList unknownChunkData = new ArrayList(); // byte arrays + public ArrayList<String> unknownChunkType = new ArrayList<String>(); + public ArrayList<byte[]> unknownChunkData = new ArrayList<byte[]>(); public PNGMetadata() { super(true, @@ -426,21 +426,14 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return false; } - private ArrayList cloneBytesArrayList(ArrayList in) { + private ArrayList<byte[]> cloneBytesArrayList(ArrayList<byte[]> in) { if (in == null) { return null; } else { - ArrayList list = new ArrayList(in.size()); - Iterator iter = in.iterator(); - while (iter.hasNext()) { - Object o = iter.next(); - if (o == null) { - list.add(null); - } else { - list.add(((byte[])o).clone()); - } + ArrayList<byte[]> list = new ArrayList<byte[]>(in.size()); + for (byte[] b: in) { + list.add((b == null) ? null : (byte[])b.clone()); } - return list; } } @@ -600,7 +593,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { IIOMetadataNode iTXt_node = new IIOMetadataNode("iTXtEntry"); iTXt_node.setAttribute("keyword", iTXt_keyword.get(i)); iTXt_node.setAttribute("compressionFlag", - iTXt_compressionFlag.get(i) ? "1" : "0"); + iTXt_compressionFlag.get(i) ? "TRUE" : "FALSE"); iTXt_node.setAttribute("compressionMethod", iTXt_compressionMethod.get(i).toString()); iTXt_node.setAttribute("languageTag", @@ -832,7 +825,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } node = new IIOMetadataNode("BlackIsZero"); - node.setAttribute("value", "true"); + node.setAttribute("value", "TRUE"); chroma_node.appendChild(node); if (PLTE_present) { @@ -894,7 +887,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { compression_node.appendChild(node); node = new IIOMetadataNode("Lossless"); - node.setAttribute("value", "true"); + node.setAttribute("value", "TRUE"); compression_node.appendChild(node); node = new IIOMetadataNode("NumProgressiveScans"); @@ -1040,7 +1033,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { node.setAttribute("language", iTXt_languageTag.get(i)); if (iTXt_compressionFlag.get(i)) { - node.setAttribute("compression", "deflate"); + node.setAttribute("compression", "zip"); } else { node.setAttribute("compression", "none"); } @@ -1052,7 +1045,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { node = new IIOMetadataNode("TextEntry"); node.setAttribute("keyword", (String)zTXt_keyword.get(i)); node.setAttribute("value", (String)zTXt_text.get(i)); - node.setAttribute("compression", "deflate"); + node.setAttribute("compression", "zip"); text_node.appendChild(node); } @@ -1162,12 +1155,13 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } } String value = attr.getNodeValue(); - if (value.equals("true")) { + // Allow lower case booleans for backward compatibility, #5082756 + if (value.equals("TRUE") || value.equals("true")) { return true; - } else if (value.equals("false")) { + } else if (value.equals("FALSE") || value.equals("false")) { return false; } else { - fatal(node, "Attribute " + name + " must be 'true' or 'false'!"); + fatal(node, "Attribute " + name + " must be 'TRUE' or 'FALSE'!"); return false; } } @@ -1421,26 +1415,30 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } String keyword = getAttribute(iTXt_node, "keyword"); - iTXt_keyword.add(keyword); + if (isValidKeyword(keyword)) { + iTXt_keyword.add(keyword); - boolean compressionFlag = - getBooleanAttribute(iTXt_node, "compressionFlag"); - iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag)); + boolean compressionFlag = + getBooleanAttribute(iTXt_node, "compressionFlag"); + iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag)); - String compressionMethod = - getAttribute(iTXt_node, "compressionMethod"); - iTXt_compressionMethod.add(Integer.valueOf(compressionMethod)); + String compressionMethod = + getAttribute(iTXt_node, "compressionMethod"); + iTXt_compressionMethod.add(Integer.valueOf(compressionMethod)); - String languageTag = - getAttribute(iTXt_node, "languageTag"); - iTXt_languageTag.add(languageTag); + String languageTag = + getAttribute(iTXt_node, "languageTag"); + iTXt_languageTag.add(languageTag); - String translatedKeyword = - getAttribute(iTXt_node, "translatedKeyword"); - iTXt_translatedKeyword.add(translatedKeyword); + String translatedKeyword = + getAttribute(iTXt_node, "translatedKeyword"); + iTXt_translatedKeyword.add(translatedKeyword); - String text = getAttribute(iTXt_node, "text"); - iTXt_text.add(text); + String text = getAttribute(iTXt_node, "text"); + iTXt_text.add(text); + + } + // silently skip invalid text entry iTXt_node = iTXt_node.getNextSibling(); } @@ -1692,11 +1690,45 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } } - private boolean isISOLatin(String s) { + /* + * Accrding to PNG spec, keywords are restricted to 1 to 79 bytes + * in length. Keywords shall contain only printable Latin-1 characters + * and spaces; To reduce the chances for human misreading of a keyword, + * leading spaces, trailing spaces, and consecutive spaces are not + * permitted in keywords. + * + * See: http://www.w3.org/TR/PNG/#11keywords + */ + private boolean isValidKeyword(String s) { + int len = s.length(); + if (len < 1 || len >= 80) { + return false; + } + if (s.startsWith(" ") || s.endsWith(" ") || s.contains(" ")) { + return false; + } + return isISOLatin(s, false); + } + + /* + * According to PNG spec, keyword shall contain only printable + * Latin-1 [ISO-8859-1] characters and spaces; that is, only + * character codes 32-126 and 161-255 decimal are allowed. + * For Latin-1 value fields the 0x10 (linefeed) control + * character is aloowed too. + * + * See: http://www.w3.org/TR/PNG/#11keywords + */ + private boolean isISOLatin(String s, boolean isLineFeedAllowed) { int len = s.length(); for (int i = 0; i < len; i++) { - if (s.charAt(i) > 255) { - return false; + char c = s.charAt(i); + if (c < 32 || c > 255 || (c > 126 && c < 161)) { + // not printable. Check whether this is an allowed + // control char + if (!isLineFeedAllowed || c != 0x10) { + return false; + } } } return true; @@ -1929,19 +1961,22 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { while (child != null) { String childName = child.getNodeName(); if (childName.equals("TextEntry")) { - String keyword = getAttribute(child, "keyword"); + String keyword = + getAttribute(child, "keyword", "", false); String value = getAttribute(child, "value"); - String encoding = getAttribute(child, "encoding"); - String language = getAttribute(child, "language"); + String language = + getAttribute(child, "language", "", false); String compression = - getAttribute(child, "compression"); + getAttribute(child, "compression", "none", false); - if (isISOLatin(value)) { + if (!isValidKeyword(keyword)) { + // Just ignore this node, PNG requires keywords + } else if (isISOLatin(value, true)) { if (compression.equals("zip")) { // Use a zTXt node zTXt_keyword.add(keyword); zTXt_text.add(value); - zTXt_compressionMethod.add(new Integer(0)); + zTXt_compressionMethod.add(Integer.valueOf(0)); } else { // Use a tEXt node tEXt_keyword.add(keyword); @@ -1998,14 +2033,14 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { sBIT_present = false; sPLT_present = false; sRGB_present = false; - tEXt_keyword = new ArrayList(); - tEXt_text = new ArrayList(); + tEXt_keyword = new ArrayList<String>(); + tEXt_text = new ArrayList<String>(); tIME_present = false; tRNS_present = false; - zTXt_keyword = new ArrayList(); - zTXt_compressionMethod = new ArrayList(); - zTXt_text = new ArrayList(); - unknownChunkType = new ArrayList(); - unknownChunkData = new ArrayList(); + zTXt_keyword = new ArrayList<String>(); + zTXt_compressionMethod = new ArrayList<Integer>(); + zTXt_text = new ArrayList<String>(); + unknownChunkType = new ArrayList<String>(); + unknownChunkData = new ArrayList<byte[]>(); } } diff --git a/jdk/src/share/classes/com/sun/imageio/stream/StreamCloser.java b/jdk/src/share/classes/com/sun/imageio/stream/StreamCloser.java index f39b98eb05d..03c6ce32364 100644 --- a/jdk/src/share/classes/com/sun/imageio/stream/StreamCloser.java +++ b/jdk/src/share/classes/com/sun/imageio/stream/StreamCloser.java @@ -94,6 +94,10 @@ public class StreamCloser { tgn != null; tg = tgn, tgn = tg.getParent()); streamCloser = new Thread(tg, streamCloserRunnable); + /* Set context class loader to null in order to avoid + * keeping a strong reference to an application classloader. + */ + streamCloser.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(streamCloser); return null; } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java index 850aa154b83..23df1928fd4 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java @@ -279,20 +279,22 @@ class GTKIconFactory { public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) { - JToolBar toolbar = (JToolBar)context.getComponent(); - Orientation orientation = - (toolbar.getOrientation() == JToolBar.HORIZONTAL ? - Orientation.HORIZONTAL : Orientation.VERTICAL); + if (context != null) { + JToolBar toolbar = (JToolBar)context.getComponent(); + Orientation orientation = + (toolbar.getOrientation() == JToolBar.HORIZONTAL ? + Orientation.HORIZONTAL : Orientation.VERTICAL); - if (style == null) { - style = SynthLookAndFeel.getStyleFactory().getStyle( - context.getComponent(), GTKRegion.HANDLE_BOX); + if (style == null) { + style = SynthLookAndFeel.getStyleFactory().getStyle( + context.getComponent(), GTKRegion.HANDLE_BOX); + } + context = new SynthContext(toolbar, GTKRegion.HANDLE_BOX, + style, SynthConstants.ENABLED); + + GTKPainter.INSTANCE.paintIcon(context, g, + getMethod(), x, y, w, h, orientation); } - context = new SynthContext(toolbar, GTKRegion.HANDLE_BOX, - style, SynthConstants.ENABLED); - - GTKPainter.INSTANCE.paintIcon(context, g, - getMethod(), x, y, w, h, orientation); } public int getIconWidth(SynthContext context) { @@ -336,12 +338,14 @@ class GTKIconFactory { public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) { - ArrowType arrowDir = ArrowType.RIGHT; - if (!context.getComponent().getComponentOrientation().isLeftToRight()) { - arrowDir = ArrowType.LEFT; + if (context != null) { + ArrowType arrowDir = ArrowType.RIGHT; + if (!context.getComponent().getComponentOrientation().isLeftToRight()) { + arrowDir = ArrowType.LEFT; + } + GTKPainter.INSTANCE.paintIcon(context, g, + getMethod(), x, y, w, h, arrowDir); } - GTKPainter.INSTANCE.paintIcon(context, g, - getMethod(), x, y, w, h, arrowDir); } } } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java index 57af97958dd..79d06782e8b 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java @@ -39,6 +39,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.*; +import java.security.AccessController; +import java.security.PrivilegedAction; import sun.awt.shell.ShellFolder; import sun.awt.OSInfo; @@ -1143,7 +1145,11 @@ public class WindowsFileChooserUI extends BasicFileChooserUI { File[] baseFolders; if (useShellFolder) { - baseFolders = (File[])ShellFolder.get("fileChooserComboBoxFolders"); + baseFolders = AccessController.doPrivileged(new PrivilegedAction<File[]>() { + public File[] run() { + return (File[]) ShellFolder.get("fileChooserComboBoxFolders"); + } + }); } else { baseFolders = fsv.getRoots(); } diff --git a/jdk/src/share/classes/com/sun/nio/file/ExtendedCopyOption.java b/jdk/src/share/classes/com/sun/nio/file/ExtendedCopyOption.java new file mode 100644 index 00000000000..b612c0e8d59 --- /dev/null +++ b/jdk/src/share/classes/com/sun/nio/file/ExtendedCopyOption.java @@ -0,0 +1,43 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.nio.file; + +import java.nio.file.CopyOption; + +/** + * Defines <em>extended</em> copy options supported on some platforms + * by Sun's provider implementation. + * + * @since 1.7 + */ + +public enum ExtendedCopyOption implements CopyOption { + /** + * The copy may be interrupted by the {@link Thread#interrupt interrupt} + * method. + */ + INTERRUPTIBLE, +} diff --git a/jdk/src/share/classes/com/sun/nio/file/ExtendedOpenOption.java b/jdk/src/share/classes/com/sun/nio/file/ExtendedOpenOption.java new file mode 100644 index 00000000000..25208d81257 --- /dev/null +++ b/jdk/src/share/classes/com/sun/nio/file/ExtendedOpenOption.java @@ -0,0 +1,50 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.nio.file; + +import java.nio.file.OpenOption; + +/** + * Defines <em>extended</em> open options supported on some platforms + * by Sun's provider implementation. + * + * @since 1.7 + */ + +public enum ExtendedOpenOption implements OpenOption { + /** + * Prevent operations on the file that request read access. + */ + NOSHARE_READ, + /** + * Prevent operations on the file that request write access. + */ + NOSHARE_WRITE, + /** + * Prevent operations on the file that request delete access. + */ + NOSHARE_DELETE; +} diff --git a/jdk/src/share/classes/com/sun/nio/file/ExtendedWatchEventModifier.java b/jdk/src/share/classes/com/sun/nio/file/ExtendedWatchEventModifier.java new file mode 100644 index 00000000000..0f6ddc3276a --- /dev/null +++ b/jdk/src/share/classes/com/sun/nio/file/ExtendedWatchEventModifier.java @@ -0,0 +1,43 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.nio.file; + +import java.nio.file.WatchEvent.Modifier; + +/** + * Defines <em>extended</em> watch event modifiers supported on some platforms + * by Sun's provider implementation. + * + * @since 1.7 + */ + +public enum ExtendedWatchEventModifier implements Modifier { + + /** + * Register a file tree instead of a single directory. + */ + FILE_TREE, +} diff --git a/jdk/src/share/classes/com/sun/nio/file/SensitivityWatchEventModifier.java b/jdk/src/share/classes/com/sun/nio/file/SensitivityWatchEventModifier.java new file mode 100644 index 00000000000..57ab111b00b --- /dev/null +++ b/jdk/src/share/classes/com/sun/nio/file/SensitivityWatchEventModifier.java @@ -0,0 +1,62 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.nio.file; + +import java.nio.file.WatchEvent.Modifier; + +/** + * Defines the <em>sensitivity levels</em> when registering objects with a + * watch service implementation that polls the file system. + * + * @since 1.7 + */ + +public enum SensitivityWatchEventModifier implements Modifier { + /** + * High sensitivity. + */ + HIGH(2), + /** + * Medium sensitivity. + */ + MEDIUM(10), + /** + * Low sensitivity. + */ + LOW(30); + + /** + * Returns the sensitivity in seconds. + */ + public int sensitivityValueInSeconds() { + return sensitivity; + } + + private final int sensitivity; + private SensitivityWatchEventModifier(int sensitivity) { + this.sensitivity = sensitivity; + } +} diff --git a/jdk/src/share/classes/com/sun/servicetag/resources/register.html b/jdk/src/share/classes/com/sun/servicetag/resources/register.html index 23e9d717ab7..29a275b35be 100644 --- a/jdk/src/share/classes/com/sun/servicetag/resources/register.html +++ b/jdk/src/share/classes/com/sun/servicetag/resources/register.html @@ -68,7 +68,7 @@ a:visited,a:visited code{color:#917E9C} <table width="708" border="0" cellspacing="0" cellpadding="3"> <tr valign="top"> <td width="126" height="35"> - <form name="form1" method="post" action="@@REGISTRATION_URL@@" enctype="text/xml"> + <form name="form1" method="post" action="@@REGISTRATION_URL@@"> <input type="hidden" name="servicetag_payload" value="@@REGISTRATION_PAYLOAD@@"> <input type="submit" name="Submit"border="0" class="buttonblue" onmouseover="this.style.color='#fbe249';" onmouseout="this.style.color='#FFF';" value="Register My JDK"> </form></td> diff --git a/jdk/src/share/classes/com/sun/servicetag/resources/register_ja.html b/jdk/src/share/classes/com/sun/servicetag/resources/register_ja.html index 56ee84f5426..fc7cf0517c2 100644 --- a/jdk/src/share/classes/com/sun/servicetag/resources/register_ja.html +++ b/jdk/src/share/classes/com/sun/servicetag/resources/register_ja.html @@ -62,7 +62,7 @@ a:visited,a:visited code{color:#917E9C} <p class="style1">å¿…è¦ã«ãªã‚‹ã®ã¯ã€Sun 開発者å‘ã‘ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¾ãŸã¯ãã®ä»–ã® Sun オンラインアカウントã ã‘ã§ã™ã€‚ ã¾ã ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒãªã„å ´åˆã¯ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®ä½œæˆãŒæ±‚ã‚られã¾ã™ã€‚ </p> <table width="708" border="0" cellspacing="0" cellpadding="3"> <tr valign="top"> - <td width="126" height="35"><form name="form1" method="post" action="@@REGISTRATION_URL@@" enctype="text/xml"> + <td width="126" height="35"><form name="form1" method="post" action="@@REGISTRATION_URL@@"> <input type="hidden" name="servicetag_payload" value="@@REGISTRATION_PAYLOAD@@"> <input type="submit" name="Submit"border="0" class="buttonblue" onmouseover="this.style.color='#fbe249';" onmouseout="this.style.color='#FFF';" value="JDK 製å“登録"> </form></td> diff --git a/jdk/src/share/classes/com/sun/servicetag/resources/register_zh_CN.html b/jdk/src/share/classes/com/sun/servicetag/resources/register_zh_CN.html index c47929fb744..92cf04b7f10 100644 --- a/jdk/src/share/classes/com/sun/servicetag/resources/register_zh_CN.html +++ b/jdk/src/share/classes/com/sun/servicetag/resources/register_zh_CN.html @@ -63,7 +63,7 @@ a:visited,a:visited code{color:#917E9C} <p class="style1">您需è¦å…·æœ‰ Sun å¼€å‘者网络或其他 Sun è”机å¸æˆ·ã€‚如果您没有,系统将æ示您创建一个。 </p> <table width="708" border="0" cellspacing="0" cellpadding="3"> <tr valign="top"> - <td width="126" height="35"><form name="form1" method="post" action="@@REGISTRATION_URL@@" enctype="text/xml"> + <td width="126" height="35"><form name="form1" method="post" action="@@REGISTRATION_URL@@"> <input type="hidden" name="servicetag_payload" value="@@REGISTRATION_PAYLOAD@@"> <input type="submit" name="Submit"border="0" class="buttonblue" onmouseover="this.style.color='#fbe249';" onmouseout="this.style.color='#FFF';" value="注册我的 JDK"> </form></td> diff --git a/jdk/src/share/classes/java/awt/GraphicsEnvironment.java b/jdk/src/share/classes/java/awt/GraphicsEnvironment.java index 167db051910..cf1852e2fc0 100644 --- a/jdk/src/share/classes/java/awt/GraphicsEnvironment.java +++ b/jdk/src/share/classes/java/awt/GraphicsEnvironment.java @@ -356,6 +356,9 @@ public abstract class GraphicsEnvironment { * @since 1.5 */ public void preferLocaleFonts() { + if (!(this instanceof SunGraphicsEnvironment)) { + return; + } sun.font.FontManager.preferLocaleFonts(); } @@ -376,6 +379,9 @@ public abstract class GraphicsEnvironment { * @since 1.5 */ public void preferProportionalFonts() { + if (!(this instanceof SunGraphicsEnvironment)) { + return; + } sun.font.FontManager.preferProportionalFonts(); } diff --git a/jdk/src/share/classes/java/awt/color/ICC_Profile.java b/jdk/src/share/classes/java/awt/color/ICC_Profile.java index 3ef8d437bb4..705d2560e1f 100644 --- a/jdk/src/share/classes/java/awt/color/ICC_Profile.java +++ b/jdk/src/share/classes/java/awt/color/ICC_Profile.java @@ -737,7 +737,7 @@ public class ICC_Profile implements Serializable { ICC_Profile(ProfileDeferralInfo pdi) { this.deferralInfo = pdi; this.profileActivator = new ProfileActivator() { - public void activate() { + public void activate() throws ProfileDataException { activateDeferredProfile(); } }; @@ -830,20 +830,16 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_sRGB: synchronized(ICC_Profile.class) { if (sRGBprofile == null) { - try { - /* - * Deferral is only used for standard profiles. - * Enabling the appropriate access privileges is handled - * at a lower level. - */ - sRGBprofile = getDeferredInstance( - new ProfileDeferralInfo("sRGB.pf", - ColorSpace.TYPE_RGB, - 3, CLASS_DISPLAY)); - } catch (IOException e) { - throw new IllegalArgumentException( - "Can't load standard profile: sRGB.pf"); - } + /* + * Deferral is only used for standard profiles. + * Enabling the appropriate access privileges is handled + * at a lower level. + */ + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("sRGB.pf", + ColorSpace.TYPE_RGB, 3, + CLASS_DISPLAY); + sRGBprofile = getDeferredInstance(pInfo); } thisProfile = sRGBprofile; } @@ -853,7 +849,11 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_CIEXYZ: synchronized(ICC_Profile.class) { if (XYZprofile == null) { - XYZprofile = getStandardProfile("CIEXYZ.pf"); + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("CIEXYZ.pf", + ColorSpace.TYPE_XYZ, 3, + CLASS_DISPLAY); + XYZprofile = getDeferredInstance(pInfo); } thisProfile = XYZprofile; } @@ -863,7 +863,11 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_PYCC: synchronized(ICC_Profile.class) { if (PYCCprofile == null) { - PYCCprofile = getStandardProfile("PYCC.pf"); + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("PYCC.pf", + ColorSpace.TYPE_3CLR, 3, + CLASS_DISPLAY); + PYCCprofile = getDeferredInstance(pInfo); } thisProfile = PYCCprofile; } @@ -873,7 +877,11 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_GRAY: synchronized(ICC_Profile.class) { if (GRAYprofile == null) { - GRAYprofile = getStandardProfile("GRAY.pf"); + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("GRAY.pf", + ColorSpace.TYPE_GRAY, 1, + CLASS_DISPLAY); + GRAYprofile = getDeferredInstance(pInfo); } thisProfile = GRAYprofile; } @@ -883,7 +891,11 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_LINEAR_RGB: synchronized(ICC_Profile.class) { if (LINEAR_RGBprofile == null) { - LINEAR_RGBprofile = getStandardProfile("LINEAR_RGB.pf"); + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("LINEAR_RGB.pf", + ColorSpace.TYPE_RGB, 3, + CLASS_DISPLAY); + LINEAR_RGBprofile = getDeferredInstance(pInfo); } thisProfile = LINEAR_RGBprofile; } @@ -1047,9 +1059,7 @@ public class ICC_Profile implements Serializable { * code will take care of access privileges. * @see activateDeferredProfile() */ - static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) - throws IOException { - + static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) { if (!ProfileDeferralMgr.deferring) { return getStandardProfile(pdi.filename); } @@ -1063,33 +1073,37 @@ public class ICC_Profile implements Serializable { } - void activateDeferredProfile() { - byte profileData[]; - FileInputStream fis; - String fileName = deferralInfo.filename; + void activateDeferredProfile() throws ProfileDataException { + byte profileData[]; + FileInputStream fis; + String fileName = deferralInfo.filename; profileActivator = null; deferralInfo = null; if ((fis = openProfile(fileName)) == null) { - throw new IllegalArgumentException("Cannot open file " + fileName); + throw new ProfileDataException("Cannot open file " + fileName); } try { profileData = getProfileDataFromStream(fis); fis.close(); /* close the file */ } catch (IOException e) { - throw new IllegalArgumentException("Invalid ICC Profile Data" + - fileName); + ProfileDataException pde = new + ProfileDataException("Invalid ICC Profile Data" + fileName); + pde.initCause(e); + throw pde; } if (profileData == null) { - throw new IllegalArgumentException("Invalid ICC Profile Data" + + throw new ProfileDataException("Invalid ICC Profile Data" + fileName); } try { ID = CMSManager.getModule().loadProfile(profileData); } catch (CMMException c) { - throw new IllegalArgumentException("Invalid ICC Profile Data" + - fileName); + ProfileDataException pde = new + ProfileDataException("Invalid ICC Profile Data" + fileName); + pde.initCause(c); + throw pde; } } diff --git a/jdk/src/share/classes/java/beans/Beans.java b/jdk/src/share/classes/java/beans/Beans.java index f19b21aead2..8a750a8b15c 100644 --- a/jdk/src/share/classes/java/beans/Beans.java +++ b/jdk/src/share/classes/java/beans/Beans.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,26 +27,41 @@ package java.beans; import com.sun.beans.finder.ClassFinder; -import java.applet.*; +import java.applet.Applet; +import java.applet.AppletContext; +import java.applet.AppletStub; +import java.applet.AudioClip; -import java.awt.*; - -import java.beans.AppletInitializer; +import java.awt.GraphicsEnvironment; +import java.awt.Image; import java.beans.beancontext.BeanContext; -import java.io.*; - -import java.lang.reflect.Constructor; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.io.StreamCorruptedException; import java.net.URL; -import java.lang.reflect.Array; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Vector; + +import sun.awt.AppContext; /** * This class provides some general purpose beans control methods. */ public class Beans { + private static final Object DESIGN_TIME = new Object(); + private static final Object GUI_AVAILABLE = new Object(); /** * <p> @@ -59,12 +74,12 @@ public class Beans { * @param beanName the name of the bean within the class-loader. * For example "sun.beanbox.foobah" * - * @exception java.lang.ClassNotFoundException if the class of a serialized + * @exception ClassNotFoundException if the class of a serialized * object could not be found. - * @exception java.io.IOException if an I/O error occurs. + * @exception IOException if an I/O error occurs. */ - public static Object instantiate(ClassLoader cls, String beanName) throws java.io.IOException, ClassNotFoundException { + public static Object instantiate(ClassLoader cls, String beanName) throws IOException, ClassNotFoundException { return Beans.instantiate(cls, beanName, null, null); } @@ -80,12 +95,12 @@ public class Beans { * For example "sun.beanbox.foobah" * @param beanContext The BeanContext in which to nest the new bean * - * @exception java.lang.ClassNotFoundException if the class of a serialized + * @exception ClassNotFoundException if the class of a serialized * object could not be found. - * @exception java.io.IOException if an I/O error occurs. + * @exception IOException if an I/O error occurs. */ - public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws java.io.IOException, ClassNotFoundException { + public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws IOException, ClassNotFoundException { return Beans.instantiate(cls, beanName, beanContext, null); } @@ -135,19 +150,19 @@ public class Beans { * @param beanContext The BeanContext in which to nest the new bean * @param initializer The AppletInitializer for the new bean * - * @exception java.lang.ClassNotFoundException if the class of a serialized + * @exception ClassNotFoundException if the class of a serialized * object could not be found. - * @exception java.io.IOException if an I/O error occurs. + * @exception IOException if an I/O error occurs. */ public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer) - throws java.io.IOException, ClassNotFoundException { + throws IOException, ClassNotFoundException { - java.io.InputStream ins; - java.io.ObjectInputStream oins = null; + InputStream ins; + ObjectInputStream oins = null; Object result = null; boolean serialized = false; - java.io.IOException serex = null; + IOException serex = null; // If the given classloader is null, we check if an // system classloader is available and (if so) @@ -166,8 +181,8 @@ public class Beans { // Try to find a serialized object with this name final String serName = beanName.replace('.','/').concat(".ser"); final ClassLoader loader = cls; - ins = (InputStream)java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction() { + ins = (InputStream)AccessController.doPrivileged + (new PrivilegedAction() { public Object run() { if (loader == null) return ClassLoader.getSystemResourceAsStream(serName); @@ -185,7 +200,7 @@ public class Beans { result = oins.readObject(); serialized = true; oins.close(); - } catch (java.io.IOException ex) { + } catch (IOException ex) { ins.close(); // Drop through and try opening the class. But remember // the exception in case we can't find the class either. @@ -264,8 +279,8 @@ public class Beans { final ClassLoader cloader = cls; objectUrl = (URL) - java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction() { + AccessController.doPrivileged + (new PrivilegedAction() { public Object run() { if (cloader == null) return ClassLoader.getSystemResource @@ -377,10 +392,11 @@ public class Beans { * @return True if we are running in an application construction * environment. * - * @see java.beans.DesignMode + * @see DesignMode */ public static boolean isDesignTime() { - return designTime; + Object value = AppContext.getAppContext().get(DESIGN_TIME); + return (value instanceof Boolean) && (Boolean) value; } /** @@ -393,11 +409,12 @@ public class Beans { * false in a server environment or if an application is * running as part of a batch job. * - * @see java.beans.Visibility + * @see Visibility * */ public static boolean isGuiAvailable() { - return guiAvailable; + Object value = AppContext.getAppContext().get(GUI_AVAILABLE); + return (value instanceof Boolean) ? (Boolean) value : !GraphicsEnvironment.isHeadless(); } /** @@ -423,7 +440,7 @@ public class Beans { if (sm != null) { sm.checkPropertiesAccess(); } - designTime = isDesignTime; + AppContext.getAppContext().put(DESIGN_TIME, Boolean.valueOf(isDesignTime)); } /** @@ -449,14 +466,7 @@ public class Beans { if (sm != null) { sm.checkPropertiesAccess(); } - guiAvailable = isGuiAvailable; - } - - - private static boolean designTime; - private static boolean guiAvailable; - static { - guiAvailable = !GraphicsEnvironment.isHeadless(); + AppContext.getAppContext().put(GUI_AVAILABLE, Boolean.valueOf(isGuiAvailable)); } } @@ -501,7 +511,7 @@ class ObjectInputStreamWithLoader extends ObjectInputStream class BeansAppletContext implements AppletContext { Applet target; - java.util.Hashtable imageCache = new java.util.Hashtable(); + Hashtable imageCache = new Hashtable(); BeansAppletContext(Applet target) { this.target = target; @@ -546,8 +556,8 @@ class BeansAppletContext implements AppletContext { return null; } - public java.util.Enumeration getApplets() { - java.util.Vector applets = new java.util.Vector(); + public Enumeration getApplets() { + Vector applets = new Vector(); applets.addElement(target); return applets.elements(); } @@ -573,7 +583,7 @@ class BeansAppletContext implements AppletContext { return null; } - public java.util.Iterator getStreamKeys(){ + public Iterator getStreamKeys(){ // We do nothing. return null; } diff --git a/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java b/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java index ea78643e435..951cd871fe5 100644 --- a/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java +++ b/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ package java.beans; * @author Mark Davidson */ public class IndexedPropertyChangeEvent extends PropertyChangeEvent { + private static final long serialVersionUID = -320227448495806870L; private int index; diff --git a/jdk/src/share/classes/java/beans/IntrospectionException.java b/jdk/src/share/classes/java/beans/IntrospectionException.java index cac0b20fc01..2f5a65eda73 100644 --- a/jdk/src/share/classes/java/beans/IntrospectionException.java +++ b/jdk/src/share/classes/java/beans/IntrospectionException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1998 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ package java.beans; public class IntrospectionException extends Exception { + private static final long serialVersionUID = -3728150539969542619L; /** * Constructs an <code>IntrospectionException</code> with a diff --git a/jdk/src/share/classes/java/beans/PropertyChangeEvent.java b/jdk/src/share/classes/java/beans/PropertyChangeEvent.java index 69f523d92e3..3e0c9cef6f9 100644 --- a/jdk/src/share/classes/java/beans/PropertyChangeEvent.java +++ b/jdk/src/share/classes/java/beans/PropertyChangeEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ package java.beans; */ public class PropertyChangeEvent extends java.util.EventObject { + private static final long serialVersionUID = 7042693688939648123L; /** * Constructs a new <code>PropertyChangeEvent</code>. diff --git a/jdk/src/share/classes/java/beans/PropertyVetoException.java b/jdk/src/share/classes/java/beans/PropertyVetoException.java index f736b3bade5..73376496b53 100644 --- a/jdk/src/share/classes/java/beans/PropertyVetoException.java +++ b/jdk/src/share/classes/java/beans/PropertyVetoException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1998 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ package java.beans; public class PropertyVetoException extends Exception { - + private static final long serialVersionUID = 129596057694162164L; /** * Constructs a <code>PropertyVetoException</code> with a diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextEvent.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextEvent.java index 4574605a154..2530869534b 100644 --- a/jdk/src/share/classes/java/beans/beancontext/BeanContextEvent.java +++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ import java.beans.beancontext.BeanContext; */ public abstract class BeanContextEvent extends EventObject { + private static final long serialVersionUID = 7267998073569045052L; /** * Contruct a BeanContextEvent diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java index 7e6c1ae0a69..3752e390341 100644 --- a/jdk/src/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java +++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ import java.util.Iterator; * @see java.beans.beancontext.BeanContextMembershipListener */ public class BeanContextMembershipEvent extends BeanContextEvent { + private static final long serialVersionUID = 3499346510334590959L; /** * Contruct a BeanContextMembershipEvent diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceAvailableEvent.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceAvailableEvent.java index 558c7f9f363..7bb47a66033 100644 --- a/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceAvailableEvent.java +++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceAvailableEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import java.util.Iterator; */ public class BeanContextServiceAvailableEvent extends BeanContextEvent { + private static final long serialVersionUID = -5333985775656400778L; /** * Construct a <code>BeanContextAvailableServiceEvent</code>. diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceRevokedEvent.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceRevokedEvent.java index a508f4ca157..50d888cdf7e 100644 --- a/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceRevokedEvent.java +++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceRevokedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.beans.beancontext.BeanContextServices; * </p> */ public class BeanContextServiceRevokedEvent extends BeanContextEvent { + private static final long serialVersionUID = -1295543154724961754L; /** * Construct a <code>BeanContextServiceEvent</code>. diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextServicesSupport.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextServicesSupport.java index d9552c8a34e..54dfdd7d227 100644 --- a/jdk/src/share/classes/java/beans/beancontext/BeanContextServicesSupport.java +++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextServicesSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,6 +60,7 @@ import java.util.Locale; public class BeanContextServicesSupport extends BeanContextSupport implements BeanContextServices { + private static final long serialVersionUID = -8494482757288719206L; /** * <p> @@ -594,6 +595,7 @@ public class BeanContextServicesSupport extends BeanContextSupport */ protected static class BCSSServiceProvider implements Serializable { + private static final long serialVersionUID = 861278251667444782L; BCSSServiceProvider(Class sc, BeanContextServiceProvider bcsp) { super(); diff --git a/jdk/src/share/classes/java/io/Console.java b/jdk/src/share/classes/java/io/Console.java index 9e009943a95..201b66f71b5 100644 --- a/jdk/src/share/classes/java/io/Console.java +++ b/jdk/src/share/classes/java/io/Console.java @@ -503,6 +503,21 @@ public final class Console implements Flushable // Set up JavaIOAccess in SharedSecrets static { + + // Add a shutdown hook to restore console's echo state should + // it be necessary. + sun.misc.SharedSecrets.getJavaLangAccess() + .registerShutdownHook(0 /* shutdown hook invocation order */, + new Runnable() { + public void run() { + try { + if (echoOff) { + echo(true); + } + } catch (IOException x) { } + } + }); + sun.misc.SharedSecrets.setJavaIOAccess(new sun.misc.JavaIOAccess() { public Console console() { if (istty()) { @@ -513,20 +528,6 @@ public final class Console implements Flushable return null; } - // Add a shutdown hook to restore console's echo state should - // it be necessary. - public Runnable consoleRestoreHook() { - return new Runnable() { - public void run() { - try { - if (echoOff) { - echo(true); - } - } catch (IOException x) {} - } - }; - } - public Charset charset() { // This method is called in sun.security.util.Password, // cons already exists when this method is called diff --git a/jdk/src/share/classes/java/io/DeleteOnExitHook.java b/jdk/src/share/classes/java/io/DeleteOnExitHook.java index bf4d9e7f20f..1dc5c9d85bc 100644 --- a/jdk/src/share/classes/java/io/DeleteOnExitHook.java +++ b/jdk/src/share/classes/java/io/DeleteOnExitHook.java @@ -34,17 +34,18 @@ import java.io.File; */ class DeleteOnExitHook { - private static DeleteOnExitHook instance = null; + static { + sun.misc.SharedSecrets.getJavaLangAccess() + .registerShutdownHook(2 /* Shutdown hook invocation order */, + new Runnable() { + public void run() { + runHooks(); + } + }); + } private static LinkedHashSet<String> files = new LinkedHashSet<String>(); - static DeleteOnExitHook hook() { - if (instance == null) - instance = new DeleteOnExitHook(); - - return instance; - } - private DeleteOnExitHook() {} static synchronized void add(String file) { @@ -54,7 +55,7 @@ class DeleteOnExitHook { files.add(file); } - void run() { + static void runHooks() { LinkedHashSet<String> theFiles; synchronized (DeleteOnExitHook.class) { diff --git a/jdk/src/share/classes/java/io/File.java b/jdk/src/share/classes/java/io/File.java index d573b89f483..6e58efbbd6b 100644 --- a/jdk/src/share/classes/java/io/File.java +++ b/jdk/src/share/classes/java/io/File.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,12 +30,12 @@ import java.net.URI; import java.net.URL; import java.net.MalformedURLException; import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Map; -import java.util.Hashtable; -import java.util.Random; +import java.util.*; +import java.nio.file.*; +import java.nio.file.attribute.*; import java.security.AccessController; -import java.security.AccessControlException; +import java.security.PrivilegedAction; +import java.security.SecureRandom; import sun.security.action.GetPropertyAction; @@ -131,6 +131,18 @@ import sun.security.action.GetPropertyAction; * created, the abstract pathname represented by a <code>File</code> object * will never change. * + * <h4>Interoperability with {@code java.nio.file} package</h4> + * + * <p> The <a href="../../java/nio/file/package-summary.html">{@code java.nio.file}</a> + * package defines interfaces and classes for the Java virtual machine to access + * files, file attributes, and file systems. This API may be used to overcome + * many of the limitations of the {@code java.io.File} class. + * The {@link #toPath toPath} method may be used to obtain a {@link + * Path} that uses the abstract path represented by a {@code File} object to + * locate a file. The resulting {@code Path} provides more efficient and + * extensive access to file attributes, additional file operations, and I/O + * exceptions to help diagnose errors when an operation on a file fails. + * * @author unascribed * @since JDK1.0 */ @@ -573,6 +585,7 @@ public class File * read access to the file * * @since JDK1.1 + * @see Path#toRealPath */ public String getCanonicalPath() throws IOException { return fs.canonicalize(fs.resolve(this)); @@ -597,6 +610,7 @@ public class File * read access to the file * * @since 1.2 + * @see Path#toRealPath */ public File getCanonicalFile() throws IOException { String canonPath = getCanonicalPath(); @@ -663,6 +677,14 @@ public class File * system is converted into an abstract pathname in a virtual machine on a * different operating system. * + * <p> Note that when this abstract pathname represents a UNC pathname then + * all components of the UNC (including the server name component) are encoded + * in the {@code URI} path. The authority component is undefined, meaning + * that it is represented as {@code null}. The {@link Path} class defines the + * {@link Path#toUri toUri} method to encode the server name in the authority + * component of the resulting {@code URI}. The {@link #toPath toPath} method + * may be used to obtain a {@code Path} representing this abstract pathname. + * * @return An absolute, hierarchical URI with a scheme equal to * <tt>"file"</tt>, a path representing this abstract pathname, * and undefined authority, query, and fragment components @@ -764,6 +786,8 @@ public class File * If a security manager exists and its <code>{@link * java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file + * + * @see Attributes#readBasicFileAttributes */ public boolean isDirectory() { SecurityManager security = System.getSecurityManager(); @@ -788,6 +812,8 @@ public class File * If a security manager exists and its <code>{@link * java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file + * + * @see Attributes#readBasicFileAttributes */ public boolean isFile() { SecurityManager security = System.getSecurityManager(); @@ -836,6 +862,8 @@ public class File * If a security manager exists and its <code>{@link * java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file + * + * @see Attributes#readBasicFileAttributes */ public long lastModified() { SecurityManager security = System.getSecurityManager(); @@ -858,6 +886,8 @@ public class File * If a security manager exists and its <code>{@link * java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file + * + * @see Attributes#readBasicFileAttributes */ public long length() { SecurityManager security = System.getSecurityManager(); @@ -907,6 +937,12 @@ public class File * this pathname denotes a directory, then the directory must be empty in * order to be deleted. * + * <p> Note that the {@link Path} class defines the {@link Path#delete + * delete} method to throw an {@link IOException} when a file cannot be + * deleted. This is useful for error reporting and to diagnose why a file + * cannot be deleted. The {@link #toPath toPath} method may be used to + * obtain a {@code Path} representing this abstract pathname. + * * @return <code>true</code> if and only if the file or directory is * successfully deleted; <code>false</code> otherwise * @@ -973,6 +1009,13 @@ public class File * will appear in any specific order; they are not, in particular, * guaranteed to appear in alphabetical order. * + * <p> Note that the {@link Path} class defines the {@link + * Path#newDirectoryStream newDirectoryStream} method to open a directory + * and iterate over the names of the files in the directory. This may use + * less resources when working with very large directories. The {@link + * #toPath toPath} method may be used to obtain a {@code Path} representing + * this abstract pathname. + * * @return An array of strings naming the files and directories in the * directory denoted by this abstract pathname. The array will be * empty if the directory is empty. Returns {@code null} if @@ -1024,13 +1067,13 @@ public class File if ((names == null) || (filter == null)) { return names; } - ArrayList v = new ArrayList(); + List<String> v = new ArrayList<String>(); for (int i = 0 ; i < names.length ; i++) { if (filter.accept(this, names[i])) { v.add(names[i]); } } - return (String[])(v.toArray(new String[v.size()])); + return v.toArray(new String[v.size()]); } /** @@ -1052,6 +1095,13 @@ public class File * will appear in any specific order; they are not, in particular, * guaranteed to appear in alphabetical order. * + * <p> Note that the {@link Path} class defines the {@link + * Path#newDirectoryStream newDirectoryStream} method to open a directory + * and iterate over the names of the files in the directory. This may use + * less resources when working with very large directories. The {@link + * #toPath toPath} method may be used to obtain a {@code Path} representing + * this abstract pathname. + * * @return An array of abstract pathnames denoting the files and * directories in the directory denoted by this abstract pathname. * The array will be empty if the directory is empty. Returns @@ -1157,6 +1207,12 @@ public class File /** * Creates the directory named by this abstract pathname. * + * <p> Note that the {@link Path} class defines the {@link Path#createDirectory + * createDirectory} method to throw an {@link IOException} when a directory + * cannot be created. This is useful for error reporting and to diagnose why + * a directory cannot be created. The {@link #toPath toPath} method may be + * used to obtain a {@code Path} representing this abstract pathname. + * * @return <code>true</code> if and only if the directory was * created; <code>false</code> otherwise * @@ -1222,6 +1278,11 @@ public class File * already exists. The return value should always be checked to make sure * that the rename operation was successful. * + * <p> Note that the {@link Path} class defines the {@link Path#moveTo + * moveTo} method to move or rename a file in a platform independent manner. + * The {@link #toPath toPath} method may be used to obtain a {@code Path} + * representing this abstract pathname. + * * @param dest The new abstract pathname for the named file * * @return <code>true</code> if and only if the renaming succeeded; @@ -1304,10 +1365,14 @@ public class File return fs.setReadOnly(this); } - /** + /** * Sets the owner's or everybody's write permission for this abstract * pathname. * + * <p> The {@link Attributes Attributes} class defines methods that operate + * on file attributes including file permissions. This may be used when + * finer manipulation of file permissions is required. + * * @param writable * If <code>true</code>, sets the access permission to allow write * operations; if <code>false</code> to disallow write operations @@ -1371,6 +1436,10 @@ public class File * Sets the owner's or everybody's read permission for this abstract * pathname. * + * <p> The {@link Attributes Attributes} class defines methods that operate + * on file attributes including file permissions. This may be used when + * finer manipulation of file permissions is required. + * * @param readable * If <code>true</code>, sets the access permission to allow read * operations; if <code>false</code> to disallow read operations @@ -1440,6 +1509,10 @@ public class File * Sets the owner's or everybody's execute permission for this abstract * pathname. * + * <p> The {@link Attributes Attributes} class defines methods that operate + * on file attributes including file permissions. This may be used when + * finer manipulation of file permissions is required. + * * @param executable * If <code>true</code>, sets the access permission to allow execute * operations; if <code>false</code> to disallow execute operations @@ -1678,44 +1751,44 @@ public class File /* -- Temporary files -- */ - private static final Object tmpFileLock = new Object(); + private static class TemporaryDirectory { + private TemporaryDirectory() { } - private static int counter = -1; /* Protected by tmpFileLock */ + static final String valueAsString = fs.normalize( + AccessController.doPrivileged(new GetPropertyAction("java.io.tmpdir"))); + static final File valueAsFile = + new File(valueAsString, fs.prefixLength(valueAsString)); - private static File generateFile(String prefix, String suffix, File dir) - throws IOException - { - if (counter == -1) { - counter = new Random().nextInt() & 0xffff; - } - counter++; - return new File(dir, prefix + Integer.toString(counter) + suffix); - } - - private static String tmpdir; /* Protected by tmpFileLock */ - - private static String getTempDir() { - if (tmpdir == null) - tmpdir = fs.normalize( - AccessController.doPrivileged( - new GetPropertyAction("java.io.tmpdir"))); - return tmpdir; - } - - private static boolean checkAndCreate(String filename, SecurityManager sm) - throws IOException - { - if (sm != null) { - try { - sm.checkWrite(filename); - } catch (AccessControlException x) { - /* Throwing the original AccessControlException could disclose - the location of the default temporary directory, so we - re-throw a more innocuous SecurityException */ - throw new SecurityException("Unable to create temporary file"); + // file name generation + private static final SecureRandom random = new SecureRandom(); + static File generateFile(String prefix, String suffix, File dir) { + long n = random.nextLong(); + if (n == Long.MIN_VALUE) { + n = 0; // corner case + } else { + n = Math.abs(n); } + return new File(dir, prefix + Long.toString(n) + suffix); + } + + // default file permissions + static final FileAttribute<Set<PosixFilePermission>> defaultPosixFilePermissions = + PosixFilePermissions.asFileAttribute(EnumSet + .of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)); + static final boolean isPosix = isPosix(); + static boolean isPosix() { + return AccessController.doPrivileged( + new PrivilegedAction<Boolean>() { + public Boolean run() { + try { + return FileSystems.getDefault().getPath(valueAsString) + .getFileStore().supportsFileAttributeView("posix"); + } catch (IOException e) { + throw new IOError(e); + } + } + }); } - return fs.createFileExclusively(filename); } /** @@ -1791,22 +1864,29 @@ public class File File directory) throws IOException { - if (prefix == null) throw new NullPointerException(); if (prefix.length() < 3) throw new IllegalArgumentException("Prefix string too short"); - String s = (suffix == null) ? ".tmp" : suffix; - synchronized (tmpFileLock) { - if (directory == null) { - String tmpDir = getTempDir(); - directory = new File(tmpDir, fs.prefixLength(tmpDir)); + if (suffix == null) + suffix = ".tmp"; + + File tmpdir = (directory != null) ? + directory : TemporaryDirectory.valueAsFile; + SecurityManager sm = System.getSecurityManager(); + File f; + do { + f = TemporaryDirectory.generateFile(prefix, suffix, tmpdir); + if (sm != null) { + try { + sm.checkWrite(f.getPath()); + } catch (SecurityException se) { + // don't reveal temporary directory location + if (directory == null) + throw new SecurityException("Unable to create temporary file"); + throw se; + } } - SecurityManager sm = System.getSecurityManager(); - File f; - do { - f = generateFile(prefix, s, directory); - } while (!checkAndCreate(f.getPath(), sm)); - return f; - } + } while (!fs.createFileExclusively(f.getPath())); + return f; } /** @@ -1844,6 +1924,122 @@ public class File return createTempFile(prefix, suffix, null); } + /** + * Creates an empty file in the default temporary-file directory, using + * the given prefix and suffix to generate its name. This method is + * equivalent to invoking the {@link #createTempFile(String,String) + * createTempFile(prefix, suffix)} method with the addition that the + * resulting pathname may be requested to be deleted when the Java virtual + * machine terminates, and the initial file attributes to set atomically + * when creating the file may be specified. + * + * <p> When the value of the {@code deleteOnExit} method is {@code true} + * then the resulting file is requested to be deleted when the Java virtual + * machine terminates as if by invoking the {@link #deleteOnExit deleteOnExit} + * method. + * + * <p> The {@code attrs} parameter is an optional array of {@link FileAttribute + * attributes} to set atomically when creating the file. Each attribute is + * identified by its {@link FileAttribute#name name}. If more than one attribute + * of the same name is included in the array then all but the last occurrence + * is ignored. + * + * @param prefix + * The prefix string to be used in generating the file's + * name; must be at least three characters long + * @param suffix + * The suffix string to be used in generating the file's + * name; may be {@code null}, in which case the suffix + * {@code ".tmp"} will be used + * @param deleteOnExit + * {@code true} if the file denoted by resulting pathname be + * deleted when the Java virtual machine terminates + * @param attrs + * An optional list of file attributes to set atomically when creating + * the file + * + * @return An abstract pathname denoting a newly-created empty file + * + * @throws IllegalArgumentException + * If the <code>prefix</code> argument contains fewer than three + * characters + * @throws UnsupportedOperationException + * If the array contains an attribute that cannot be set atomically + * when creating the file + * @throws IOException + * If a file could not be created + * @throws SecurityException + * If a security manager exists and its <code>{@link + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> + * method does not allow a file to be created. When the {@code + * deleteOnExit} parameter has the value {@code true} then the + * security manager's {@link + * java.lang.SecurityManager#checkDelete(java.lang.String)} is + * invoked to check delete access to the file. + * @since 1.7 + */ + public static File createTempFile(String prefix, + String suffix, + boolean deleteOnExit, + FileAttribute<?>... attrs) + throws IOException + { + if (prefix.length() < 3) + throw new IllegalArgumentException("Prefix string too short"); + suffix = (suffix == null) ? ".tmp" : suffix; + + // special case POSIX environments so that 0600 is used as the file mode + if (TemporaryDirectory.isPosix) { + if (attrs.length == 0) { + // no attributes so use default permissions + attrs = new FileAttribute<?>[1]; + attrs[0] = TemporaryDirectory.defaultPosixFilePermissions; + } else { + // check if posix permissions given; if not use default + boolean hasPermissions = false; + for (int i=0; i<attrs.length; i++) { + if (attrs[i].name().equals("posix:permissions")) { + hasPermissions = true; + break; + } + } + if (!hasPermissions) { + FileAttribute<?>[] copy = new FileAttribute<?>[attrs.length+1]; + System.arraycopy(attrs, 0, copy, 0, attrs.length); + attrs = copy; + attrs[attrs.length-1] = + TemporaryDirectory.defaultPosixFilePermissions; + } + } + } + + // use Path#createFile to create file + SecurityManager sm = System.getSecurityManager(); + for (;;) { + File f = TemporaryDirectory + .generateFile(prefix, suffix, TemporaryDirectory.valueAsFile); + if (sm != null && deleteOnExit) + sm.checkDelete(f.getPath()); + try { + f.toPath().createFile(attrs); + if (deleteOnExit) + DeleteOnExitHook.add(f.getPath()); + return f; + } catch (InvalidPathException e) { + // don't reveal temporary directory location + if (sm != null) + throw new IllegalArgumentException("Invalid prefix or suffix"); + throw e; + } catch (SecurityException e) { + // don't reveal temporary directory location + if (sm != null) + throw new SecurityException("Unable to create temporary file"); + throw e; + } catch (FileAlreadyExistsException e) { + // ignore + } + } + } /* -- Basic infrastructure -- */ @@ -1951,17 +2147,46 @@ public class File /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = 301077366599181567L; - // Set up JavaIODeleteOnExitAccess in SharedSecrets - // Added here as DeleteOnExitHook is package-private and SharedSecrets cannot easily access it. - static { - sun.misc.SharedSecrets.setJavaIODeleteOnExitAccess( - new sun.misc.JavaIODeleteOnExitAccess() { - public void run() { - DeleteOnExitHook.hook().run(); + // -- Integration with java.nio.file -- + + private volatile transient Path filePath; + + /** + * Returns a {@link Path java.nio.file.Path} object constructed from the + * this abstract path. The first invocation of this method works as if + * invoking it were equivalent to evaluating the expression: + * <blockquote><pre> + * {@link FileSystems#getDefault FileSystems.getDefault}().{@link FileSystem#getPath getPath}(this.{@link #getPath getPath}()); + * </pre></blockquote> + * Subsequent invocations of this method return the same {@code Path}. + * + * <p> If this abstract pathname is the empty abstract pathname then this + * method returns a {@code Path} that may be used to access to the current + * user directory. + * + * @return A {@code Path} constructed from this abstract path. The resulting + * {@code Path} is associated with the {@link FileSystems#getDefault + * default-filesystem}. + * + * @throws InvalidPathException + * If a {@code Path} object cannot be constructed from the abstract + * path (see {@link java.nio.file.FileSystem#getPath FileSystem.getPath}) + * + * @since 1.7 + */ + public Path toPath() { + if (filePath == null) { + synchronized (this) { + if (filePath == null) { + if (path.length() == 0) { + // assume default file system treats "." as current directory + filePath = Paths.get("."); + } else { + filePath = Paths.get(path); + } } } - ); + } + return filePath; } - - } diff --git a/jdk/src/share/classes/java/io/FilePermission.java b/jdk/src/share/classes/java/io/FilePermission.java index 9758e35de60..88c98fbddf3 100644 --- a/jdk/src/share/classes/java/io/FilePermission.java +++ b/jdk/src/share/classes/java/io/FilePermission.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.security.*; import java.util.Enumeration; import java.util.List; import java.util.ArrayList; -import java.util.StringTokenizer; import java.util.Vector; import java.util.Collections; import java.io.ObjectStreamField; @@ -58,7 +57,8 @@ import sun.security.util.SecurityConstants; * <P> * The actions to be granted are passed to the constructor in a string containing * a list of one or more comma-separated keywords. The possible keywords are - * "read", "write", "execute", and "delete". Their meaning is defined as follows: + * "read", "write", "execute", "delete", and "readlink". Their meaning is + * defined as follows: * <P> * <DL> * <DT> read <DD> read permission @@ -69,6 +69,11 @@ import sun.security.util.SecurityConstants; * <DT> delete * <DD> delete permission. Allows <code>File.delete</code> to * be called. Corresponds to <code>SecurityManager.checkDelete</code>. + * <DT> readlink + * <DD> read link permission. Allows the target of a + * <a href="../nio/file/package-summary.html#links">symbolic link</a> + * to be read by invoking the {@link java.nio.file.Path#readSymbolicLink + * readSymbolicLink } method. * </DL> * <P> * The actions string is converted to lowercase before processing. @@ -114,11 +119,15 @@ public final class FilePermission extends Permission implements Serializable { * Delete action. */ private final static int DELETE = 0x8; + /** + * Read link action. + */ + private final static int READLINK = 0x10; /** - * All actions (read,write,execute,delete) + * All actions (read,write,execute,delete,readlink) */ - private final static int ALL = READ|WRITE|EXECUTE|DELETE; + private final static int ALL = READ|WRITE|EXECUTE|DELETE|READLINK; /** * No actions. */ @@ -235,7 +244,7 @@ public final class FilePermission extends Permission implements Serializable { * <i>path</i> is the pathname of a file or directory, and <i>actions</i> * contains a comma-separated list of the desired actions granted on the * file or directory. Possible actions are - * "read", "write", "execute", and "delete". + * "read", "write", "execute", "delete", and "readlink". * * <p>A pathname that ends in "/*" (where "/" is * the file separator character, <code>File.separatorChar</code>) @@ -425,6 +434,8 @@ public final class FilePermission extends Permission implements Serializable { return EXECUTE; } else if (actions == SecurityConstants.FILE_DELETE_ACTION) { return DELETE; + } else if (actions == SecurityConstants.FILE_READLINK_ACTION) { + return READLINK; } char[] a = actions.toCharArray(); @@ -485,6 +496,18 @@ public final class FilePermission extends Permission implements Serializable { matchlen = 6; mask |= DELETE; + } else if (i >= 7 && (a[i-7] == 'r' || a[i-7] == 'R') && + (a[i-6] == 'e' || a[i-6] == 'E') && + (a[i-5] == 'a' || a[i-5] == 'A') && + (a[i-4] == 'd' || a[i-4] == 'D') && + (a[i-3] == 'l' || a[i-3] == 'L') && + (a[i-2] == 'i' || a[i-2] == 'I') && + (a[i-1] == 'n' || a[i-1] == 'N') && + (a[i] == 'k' || a[i] == 'K')) + { + matchlen = 8; + mask |= READLINK; + } else { // parse error throw new IllegalArgumentException( @@ -529,7 +552,7 @@ public final class FilePermission extends Permission implements Serializable { /** * Return the canonical string representation of the actions. * Always returns present actions in the following order: - * read, write, execute, delete. + * read, write, execute, delete, readlink. * * @return the canonical string representation of the actions. */ @@ -561,14 +584,20 @@ public final class FilePermission extends Permission implements Serializable { sb.append("delete"); } + if ((mask & READLINK) == READLINK) { + if (comma) sb.append(','); + else comma = true; + sb.append("readlink"); + } + return sb.toString(); } /** * Returns the "canonical string representation" of the actions. * That is, this method always returns present actions in the following order: - * read, write, execute, delete. For example, if this FilePermission object - * allows both write and read actions, a call to <code>getActions</code> + * read, write, execute, delete, readlink. For example, if this FilePermission + * object allows both write and read actions, a call to <code>getActions</code> * will return the string "read,write". * * @return the canonical string representation of the actions. @@ -678,7 +707,7 @@ final class FilePermissionCollection extends PermissionCollection implements Serializable { // Not serialized; see serialization section at end of class - private transient List perms; + private transient List<Permission> perms; /** * Create an empty FilePermissions object. @@ -686,7 +715,7 @@ implements Serializable { */ public FilePermissionCollection() { - perms = new ArrayList(); + perms = new ArrayList<Permission>(); } /** @@ -791,7 +820,7 @@ implements Serializable { // Don't call out.defaultWriteObject() // Write out Vector - Vector permissions = new Vector(perms.size()); + Vector<Permission> permissions = new Vector<Permission>(perms.size()); synchronized (this) { permissions.addAll(perms); } @@ -804,6 +833,7 @@ implements Serializable { /* * Reads in a Vector of FilePermissions and saves them in the perms field. */ + @SuppressWarnings("unchecked") private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { // Don't call defaultReadObject() @@ -812,8 +842,8 @@ implements Serializable { ObjectInputStream.GetField gfields = in.readFields(); // Get the one we want - Vector permissions = (Vector)gfields.get("permissions", null); - perms = new ArrayList(permissions.size()); + Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null); + perms = new ArrayList<Permission>(permissions.size()); perms.addAll(permissions); } } diff --git a/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java b/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java index 8eeb0fef8d0..b3341de15a4 100644 --- a/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java +++ b/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java @@ -34,19 +34,19 @@ import java.util.*; * @see java.lang.Runtime#removeShutdownHook */ -class ApplicationShutdownHooks implements Runnable { - private static ApplicationShutdownHooks instance = null; +class ApplicationShutdownHooks { + static { + Shutdown.add(1 /* shutdown hook invocation order */, + new Runnable() { + public void run() { + runHooks(); + } + }); + } /* The set of registered hooks */ private static IdentityHashMap<Thread, Thread> hooks = new IdentityHashMap<Thread, Thread>(); - static synchronized ApplicationShutdownHooks hook() { - if (instance == null) - instance = new ApplicationShutdownHooks(); - - return instance; - } - private ApplicationShutdownHooks() {} /* Add a new shutdown hook. Checks the shutdown state and the hook itself, @@ -82,7 +82,7 @@ class ApplicationShutdownHooks implements Runnable { * to run in. Hooks are run concurrently and this method waits for * them to finish. */ - public void run() { + static void runHooks() { Collection<Thread> threads; synchronized(ApplicationShutdownHooks.class) { threads = hooks.keySet(); diff --git a/jdk/src/share/classes/java/lang/Character.java b/jdk/src/share/classes/java/lang/Character.java index 33b936f9c01..e33052ee170 100644 --- a/jdk/src/share/classes/java/lang/Character.java +++ b/jdk/src/share/classes/java/lang/Character.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -920,9 +920,9 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara */ public static final UnicodeBlock COMBINING_MARKS_FOR_SYMBOLS = new UnicodeBlock("COMBINING_MARKS_FOR_SYMBOLS", new String[] {"Combining Diacritical Marks for Symbols", - "CombiningDiacriticalMarksforSymbols", - "Combining Marks for Symbols", - "CombiningMarksforSymbols" }); + "CombiningDiacriticalMarksforSymbols", + "Combining Marks for Symbols", + "CombiningMarksforSymbols" }); /** * Constant for the "Letterlike Symbols" Unicode character block. @@ -1332,8 +1332,11 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara * @since 1.5 */ public static final UnicodeBlock CYRILLIC_SUPPLEMENTARY = - new UnicodeBlock("CYRILLIC_SUPPLEMENTARY", new String[] {"Cyrillic Supplementary", - "CyrillicSupplementary"}); + new UnicodeBlock("CYRILLIC_SUPPLEMENTARY", + new String[] {"Cyrillic Supplementary", + "CyrillicSupplementary", + "Cyrillic Supplement", + "CyrillicSupplement"}); /** * Constant for the "Tagalog" Unicode character block. @@ -1641,157 +1644,579 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara public static final UnicodeBlock LOW_SURROGATES = new UnicodeBlock("LOW_SURROGATES", new String[] {"Low Surrogates", "LowSurrogates"}); + /** + * Constant for the "Arabic Supplement" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock ARABIC_SUPPLEMENT = + new UnicodeBlock("ARABIC_SUPPLEMENT", + new String[] { "Arabic Supplement", + "ArabicSupplement"}); + + /** + * Constant for the "NKo" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock NKO = new UnicodeBlock("NKO"); + + /** + * Constant for the "Ethiopic Supplement" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock ETHIOPIC_SUPPLEMENT = + new UnicodeBlock("ETHIOPIC_SUPPLEMENT", + new String[] { "Ethiopic Supplement", + "EthiopicSupplement"}); + + /** + * Constant for the "New Tai Lue" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock NEW_TAI_LUE = + new UnicodeBlock("NEW_TAI_LUE", + new String[] { "New Tai Lue", + "NewTaiLue"}); + + /** + * Constant for the "Buginese" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock BUGINESE = + new UnicodeBlock("BUGINESE"); + + /** + * Constant for the "Balinese" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock BALINESE = + new UnicodeBlock("BALINESE"); + + /** + * Constant for the "Sundanese" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock SUNDANESE = + new UnicodeBlock("SUNDANESE"); + + /** + * Constant for the "Lepcha" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock LEPCHA = new UnicodeBlock("LEPCHA"); + + /** + * Constant for the "Ol Chiki" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock OL_CHIKI = + new UnicodeBlock("OL_CHIKI", + new String[] { "Ol Chiki", + "OlChiki"}); + + /** + * Constant for the "Phonetic Extensions Supplement" Unicode character + * block. + * @since 1.7 + */ + public static final UnicodeBlock PHONETIC_EXTENSIONS_SUPPLEMENT = + new UnicodeBlock("PHONETIC_EXTENSIONS_SUPPLEMENT", + new String[] { "Phonetic Extensions Supplement", + "PhoneticExtensionsSupplement"}); + + /** + * Constant for the "Combining Diacritical Marks Supplement" Unicode + * character block. + * @since 1.7 + */ + public static final UnicodeBlock COMBINING_DIACRITICAL_MARKS_SUPPLEMENT = + new UnicodeBlock("COMBINING_DIACRITICAL_MARKS_SUPPLEMENT", + new String[] { "Combining Diacritical Marks Supplement", + "CombiningDiacriticalMarksSupplement"}); + + /** + * Constant for the "Glagolitic" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock GLAGOLITIC = + new UnicodeBlock("GLAGOLITIC"); + + /** + * Constant for the "Latin Extended-C" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock LATIN_EXTENDED_C = + new UnicodeBlock("LATIN_EXTENDED_C", + new String[] { "Latin Extended-C", + "LatinExtended-C"}); + + /** + * Constant for the "Coptic" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock COPTIC = new UnicodeBlock("COPTIC"); + + /** + * Constant for the "Georgian Supplement" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock GEORGIAN_SUPPLEMENT = + new UnicodeBlock("GEORGIAN_SUPPLEMENT", + new String[] { "Georgian Supplement", + "GeorgianSupplement"}); + + /** + * Constant for the "Tifinagh" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock TIFINAGH = + new UnicodeBlock("TIFINAGH"); + + /** + * Constant for the "Ethiopic Extended" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock ETHIOPIC_EXTENDED = + new UnicodeBlock("ETHIOPIC_EXTENDED", + new String[] { "Ethiopic Extended", + "EthiopicExtended"}); + + /** + * Constant for the "Cyrillic Extended-A" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock CYRILLIC_EXTENDED_A = + new UnicodeBlock("CYRILLIC_EXTENDED_A", + new String[] { "Cyrillic Extended-A", + "CyrillicExtended-A"}); + + /** + * Constant for the "Supplemental Punctuation" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock SUPPLEMENTAL_PUNCTUATION = + new UnicodeBlock("SUPPLEMENTAL_PUNCTUATION", + new String[] { "Supplemental Punctuation", + "SupplementalPunctuation"}); + + /** + * Constant for the "CJK Strokes" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock CJK_STROKES = + new UnicodeBlock("CJK_STROKES", + new String[] { "CJK Strokes", + "CJKStrokes"}); + + /** + * Constant for the "Vai" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock VAI = new UnicodeBlock("VAI"); + + /** + * Constant for the "Cyrillic Extended-B" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock CYRILLIC_EXTENDED_B = + new UnicodeBlock("CYRILLIC_EXTENDED_B", + new String[] { "Cyrillic Extended-B", + "CyrillicExtended-B"}); + + /** + * Constant for the "Modifier Tone Letters" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock MODIFIER_TONE_LETTERS = + new UnicodeBlock("MODIFIER_TONE_LETTERS", + new String[] { "Modifier Tone Letters", + "ModifierToneLetters"}); + + /** + * Constant for the "Latin Extended-D" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock LATIN_EXTENDED_D = + new UnicodeBlock("LATIN_EXTENDED_D", + new String[] { "Latin Extended-D", + "LatinExtended-D"}); + + /** + * Constant for the "Syloti Nagri" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock SYLOTI_NAGRI = + new UnicodeBlock("SYLOTI_NAGRI", + new String[] { "Syloti Nagri", + "SylotiNagri"}); + + /** + * Constant for the "Phags-pa" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock PHAGS_PA = + new UnicodeBlock("PHAGS_PA", new String[] { "Phags-pa"}); + + /** + * Constant for the "Saurashtra" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock SAURASHTRA = + new UnicodeBlock("SAURASHTRA"); + + /** + * Constant for the "Kayah Li" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock KAYAH_LI = + new UnicodeBlock("KAYAH_LI", + new String[] { "Kayah Li", + "KayahLi"}); + + /** + * Constant for the "Rejang" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock REJANG = new UnicodeBlock("REJANG"); + + /** + * Constant for the "Cham" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock CHAM = new UnicodeBlock("CHAM"); + + /** + * Constant for the "Vertical Forms" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock VERTICAL_FORMS = + new UnicodeBlock("VERTICAL_FORMS", + new String[] { "Vertical Forms", + "VerticalForms"}); + + /** + * Constant for the "Ancient Greek Numbers" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock ANCIENT_GREEK_NUMBERS = + new UnicodeBlock("ANCIENT_GREEK_NUMBERS", + new String[] { "Ancient Greek Numbers", + "AncientGreekNumbers"}); + + /** + * Constant for the "Ancient Symbols" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock ANCIENT_SYMBOLS = + new UnicodeBlock("ANCIENT_SYMBOLS", + new String[] { "Ancient Symbols", + "AncientSymbols"}); + + /** + * Constant for the "Phaistos Disc" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock PHAISTOS_DISC = + new UnicodeBlock("PHAISTOS_DISC", + new String[] { "Phaistos Disc", + "PhaistosDisc"}); + + /** + * Constant for the "Lycian" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock LYCIAN = new UnicodeBlock("LYCIAN"); + + /** + * Constant for the "Carian" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock CARIAN = new UnicodeBlock("CARIAN"); + + /** + * Constant for the "Old Persian" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock OLD_PERSIAN = + new UnicodeBlock("OLD_PERSIAN", + new String[] { "Old Persian", + "OldPersian"}); + + /** + * Constant for the "Phoenician" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock PHOENICIAN = + new UnicodeBlock("PHOENICIAN"); + + /** + * Constant for the "Lydian" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock LYDIAN = new UnicodeBlock("LYDIAN"); + + /** + * Constant for the "Kharoshthi" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock KHAROSHTHI = + new UnicodeBlock("KHAROSHTHI"); + + /** + * Constant for the "Cuneiform" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock CUNEIFORM = + new UnicodeBlock("CUNEIFORM"); + + /** + * Constant for the "Cuneiform Numbers and Punctuation" Unicode + * character block. + * @since 1.7 + */ + public static final UnicodeBlock CUNEIFORM_NUMBERS_AND_PUNCTUATION = + new UnicodeBlock("CUNEIFORM_NUMBERS_AND_PUNCTUATION", + new String[] { "Cuneiform Numbers and Punctuation", + "CuneiformNumbersandPunctuation"}); + + /** + * Constant for the "Ancient Greek Musical Notation" Unicode character + * block. + * @since 1.7 + */ + public static final UnicodeBlock ANCIENT_GREEK_MUSICAL_NOTATION = + new UnicodeBlock("ANCIENT_GREEK_MUSICAL_NOTATION", + new String[] { "Ancient Greek Musical Notation", + "AncientGreekMusicalNotation"}); + + /** + * Constant for the "Counting Rod Numerals" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock COUNTING_ROD_NUMERALS = + new UnicodeBlock("COUNTING_ROD_NUMERALS", + new String[] { "Counting Rod Numerals", + "CountingRodNumerals"}); + + /** + * Constant for the "Mahjong Tiles" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock MAHJONG_TILES = + new UnicodeBlock("MAHJONG_TILES", + new String[] { "Mahjong Tiles", + "MahjongTiles"}); + + /** + * Constant for the "Domino Tiles" Unicode character block. + * @since 1.7 + */ + public static final UnicodeBlock DOMINO_TILES = + new UnicodeBlock("DOMINO_TILES", + new String[] { "Domino Tiles", + "DominoTiles"}); + private static final int blockStarts[] = { - 0x0000, // Basic Latin - 0x0080, // Latin-1 Supplement - 0x0100, // Latin Extended-A - 0x0180, // Latin Extended-B - 0x0250, // IPA Extensions - 0x02B0, // Spacing Modifier Letters - 0x0300, // Combining Diacritical Marks - 0x0370, // Greek and Coptic - 0x0400, // Cyrillic - 0x0500, // Cyrillic Supplementary - 0x0530, // Armenian - 0x0590, // Hebrew - 0x0600, // Arabic - 0x0700, // Syriac - 0x0750, // unassigned - 0x0780, // Thaana - 0x07C0, // unassigned - 0x0900, // Devanagari - 0x0980, // Bengali - 0x0A00, // Gurmukhi - 0x0A80, // Gujarati - 0x0B00, // Oriya - 0x0B80, // Tamil - 0x0C00, // Telugu - 0x0C80, // Kannada - 0x0D00, // Malayalam - 0x0D80, // Sinhala - 0x0E00, // Thai - 0x0E80, // Lao - 0x0F00, // Tibetan - 0x1000, // Myanmar - 0x10A0, // Georgian - 0x1100, // Hangul Jamo - 0x1200, // Ethiopic - 0x1380, // unassigned - 0x13A0, // Cherokee - 0x1400, // Unified Canadian Aboriginal Syllabics - 0x1680, // Ogham - 0x16A0, // Runic - 0x1700, // Tagalog - 0x1720, // Hanunoo - 0x1740, // Buhid - 0x1760, // Tagbanwa - 0x1780, // Khmer - 0x1800, // Mongolian - 0x18B0, // unassigned - 0x1900, // Limbu - 0x1950, // Tai Le - 0x1980, // unassigned - 0x19E0, // Khmer Symbols - 0x1A00, // unassigned - 0x1D00, // Phonetic Extensions - 0x1D80, // unassigned - 0x1E00, // Latin Extended Additional - 0x1F00, // Greek Extended - 0x2000, // General Punctuation - 0x2070, // Superscripts and Subscripts - 0x20A0, // Currency Symbols - 0x20D0, // Combining Diacritical Marks for Symbols - 0x2100, // Letterlike Symbols - 0x2150, // Number Forms - 0x2190, // Arrows - 0x2200, // Mathematical Operators - 0x2300, // Miscellaneous Technical - 0x2400, // Control Pictures - 0x2440, // Optical Character Recognition - 0x2460, // Enclosed Alphanumerics - 0x2500, // Box Drawing - 0x2580, // Block Elements - 0x25A0, // Geometric Shapes - 0x2600, // Miscellaneous Symbols - 0x2700, // Dingbats - 0x27C0, // Miscellaneous Mathematical Symbols-A - 0x27F0, // Supplemental Arrows-A - 0x2800, // Braille Patterns - 0x2900, // Supplemental Arrows-B - 0x2980, // Miscellaneous Mathematical Symbols-B - 0x2A00, // Supplemental Mathematical Operators - 0x2B00, // Miscellaneous Symbols and Arrows - 0x2C00, // unassigned - 0x2E80, // CJK Radicals Supplement - 0x2F00, // Kangxi Radicals - 0x2FE0, // unassigned - 0x2FF0, // Ideographic Description Characters - 0x3000, // CJK Symbols and Punctuation - 0x3040, // Hiragana - 0x30A0, // Katakana - 0x3100, // Bopomofo - 0x3130, // Hangul Compatibility Jamo - 0x3190, // Kanbun - 0x31A0, // Bopomofo Extended - 0x31C0, // unassigned - 0x31F0, // Katakana Phonetic Extensions - 0x3200, // Enclosed CJK Letters and Months - 0x3300, // CJK Compatibility - 0x3400, // CJK Unified Ideographs Extension A - 0x4DC0, // Yijing Hexagram Symbols - 0x4E00, // CJK Unified Ideographs - 0xA000, // Yi Syllables - 0xA490, // Yi Radicals - 0xA4D0, // unassigned - 0xAC00, // Hangul Syllables - 0xD7B0, // unassigned - 0xD800, // High Surrogates - 0xDB80, // High Private Use Surrogates - 0xDC00, // Low Surrogates - 0xE000, // Private Use - 0xF900, // CJK Compatibility Ideographs - 0xFB00, // Alphabetic Presentation Forms - 0xFB50, // Arabic Presentation Forms-A - 0xFE00, // Variation Selectors - 0xFE10, // unassigned - 0xFE20, // Combining Half Marks - 0xFE30, // CJK Compatibility Forms - 0xFE50, // Small Form Variants - 0xFE70, // Arabic Presentation Forms-B - 0xFF00, // Halfwidth and Fullwidth Forms - 0xFFF0, // Specials - 0x10000, // Linear B Syllabary - 0x10080, // Linear B Ideograms - 0x10100, // Aegean Numbers - 0x10140, // unassigned - 0x10300, // Old Italic - 0x10330, // Gothic - 0x10350, // unassigned - 0x10380, // Ugaritic - 0x103A0, // unassigned - 0x10400, // Deseret - 0x10450, // Shavian - 0x10480, // Osmanya - 0x104B0, // unassigned - 0x10800, // Cypriot Syllabary - 0x10840, // unassigned - 0x1D000, // Byzantine Musical Symbols - 0x1D100, // Musical Symbols - 0x1D200, // unassigned - 0x1D300, // Tai Xuan Jing Symbols - 0x1D360, // unassigned - 0x1D400, // Mathematical Alphanumeric Symbols - 0x1D800, // unassigned - 0x20000, // CJK Unified Ideographs Extension B - 0x2A6E0, // unassigned - 0x2F800, // CJK Compatibility Ideographs Supplement - 0x2FA20, // unassigned - 0xE0000, // Tags - 0xE0080, // unassigned - 0xE0100, // Variation Selectors Supplement - 0xE01F0, // unassigned - 0xF0000, // Supplementary Private Use Area-A - 0x100000, // Supplementary Private Use Area-B + 0x0000, // 0000..007F; Basic Latin + 0x0080, // 0080..00FF; Latin-1 Supplement + 0x0100, // 0100..017F; Latin Extended-A + 0x0180, // 0180..024F; Latin Extended-B + 0x0250, // 0250..02AF; IPA Extensions + 0x02B0, // 02B0..02FF; Spacing Modifier Letters + 0x0300, // 0300..036F; Combining Diacritical Marks + 0x0370, // 0370..03FF; Greek and Coptic + 0x0400, // 0400..04FF; Cyrillic + 0x0500, // 0500..052F; Cyrillic Supplement + 0x0530, // 0530..058F; Armenian + 0x0590, // 0590..05FF; Hebrew + 0x0600, // 0600..06FF; Arabic + 0x0700, // 0700..074F; Syria + 0x0750, // 0750..077F; Arabic Supplement + 0x0780, // 0780..07BF; Thaana + 0x07C0, // 07C0..07FF; NKo + 0x0800, // unassigned + 0x0900, // 0900..097F; Devanagari + 0x0980, // 0980..09FF; Bengali + 0x0A00, // 0A00..0A7F; Gurmukhi + 0x0A80, // 0A80..0AFF; Gujarati + 0x0B00, // 0B00..0B7F; Oriya + 0x0B80, // 0B80..0BFF; Tamil + 0x0C00, // 0C00..0C7F; Telugu + 0x0C80, // 0C80..0CFF; Kannada + 0x0D00, // 0D00..0D7F; Malayalam + 0x0D80, // 0D80..0DFF; Sinhala + 0x0E00, // 0E00..0E7F; Thai + 0x0E80, // 0E80..0EFF; Lao + 0x0F00, // 0F00..0FFF; Tibetan + 0x1000, // 1000..109F; Myanmar + 0x10A0, // 10A0..10FF; Georgian + 0x1100, // 1100..11FF; Hangul Jamo + 0x1200, // 1200..137F; Ethiopic + 0x1380, // 1380..139F; Ethiopic Supplement + 0x13A0, // 13A0..13FF; Cherokee + 0x1400, // 1400..167F; Unified Canadian Aboriginal Syllabics + 0x1680, // 1680..169F; Ogham + 0x16A0, // 16A0..16FF; Runic + 0x1700, // 1700..171F; Tagalog + 0x1720, // 1720..173F; Hanunoo + 0x1740, // 1740..175F; Buhid + 0x1760, // 1760..177F; Tagbanwa + 0x1780, // 1780..17FF; Khmer + 0x1800, // 1800..18AF; Mongolian + 0x18B0, // unassigned + 0x1900, // 1900..194F; Limbu + 0x1950, // 1950..197F; Tai Le + 0x1980, // 1980..19DF; New Tai Lue + 0x19E0, // 19E0..19FF; Khmer Symbols + 0x1A00, // 1A00..1A1F; Buginese + 0x1A20, // unassigned + 0x1B00, // 1B00..1B7F; Balinese + 0x1B80, // 1B80..1BBF; Sundanese + 0x1BC0, // unassigned + 0x1C00, // 1C00..1C4F; Lepcha + 0x1C50, // 1C50..1C7F; Ol Chiki + 0x1C80, // unassigned + 0x1D00, // 1D00..1D7F; Phonetic Extensions + 0x1D80, // 1D80..1DBF; Phonetic Extensions Supplement + 0x1DC0, // 1DC0..1DFF; Combining Diacritical Marks Supplement + 0x1E00, // 1E00..1EFF; Latin Extended Additional + 0x1F00, // 1F00..1FFF; Greek Extended + 0x2000, // 2000..206F; General Punctuation + 0x2070, // 2070..209F; Superscripts and Subscripts + 0x20A0, // 20A0..20CF; Currency Symbols + 0x20D0, // 20D0..20FF; Combining Diacritical Marks for Symbols + 0x2100, // 2100..214F; Letterlike Symbols + 0x2150, // 2150..218F; Number Forms + 0x2190, // 2190..21FF; Arrows + 0x2200, // 2200..22FF; Mathematical Operators + 0x2300, // 2300..23FF; Miscellaneous Technical + 0x2400, // 2400..243F; Control Pictures + 0x2440, // 2440..245F; Optical Character Recognition + 0x2460, // 2460..24FF; Enclosed Alphanumerics + 0x2500, // 2500..257F; Box Drawing + 0x2580, // 2580..259F; Block Elements + 0x25A0, // 25A0..25FF; Geometric Shapes + 0x2600, // 2600..26FF; Miscellaneous Symbols + 0x2700, // 2700..27BF; Dingbats + 0x27C0, // 27C0..27EF; Miscellaneous Mathematical Symbols-A + 0x27F0, // 27F0..27FF; Supplemental Arrows-A + 0x2800, // 2800..28FF; Braille Patterns + 0x2900, // 2900..297F; Supplemental Arrows-B + 0x2980, // 2980..29FF; Miscellaneous Mathematical Symbols-B + 0x2A00, // 2A00..2AFF; Supplemental Mathematical Operators + 0x2B00, // 2B00..2BFF; Miscellaneous Symbols and Arrows + 0x2C00, // 2C00..2C5F; Glagolitic + 0x2C60, // 2C60..2C7F; Latin Extended-C + 0x2C80, // 2C80..2CFF; Coptic + 0x2D00, // 2D00..2D2F; Georgian Supplement + 0x2D30, // 2D30..2D7F; Tifinagh + 0x2D80, // 2D80..2DDF; Ethiopic Extended + 0x2DE0, // 2DE0..2DFF; Cyrillic Extended-A + 0x2E00, // 2E00..2E7F; Supplemental Punctuation + 0x2E80, // 2E80..2EFF; CJK Radicals Supplement + 0x2F00, // 2F00..2FDF; Kangxi Radicals + 0x2FE0, // unassigned + 0x2FF0, // 2FF0..2FFF; Ideographic Description Characters + 0x3000, // 3000..303F; CJK Symbols and Punctuation + 0x3040, // 3040..309F; Hiragana + 0x30A0, // 30A0..30FF; Katakana + 0x3100, // 3100..312F; Bopomofo + 0x3130, // 3130..318F; Hangul Compatibility Jamo + 0x3190, // 3190..319F; Kanbun + 0x31A0, // 31A0..31BF; Bopomofo Extended + 0x31C0, // 31C0..31EF; CJK Strokes + 0x31F0, // 31F0..31FF; Katakana Phonetic Extensions + 0x3200, // 3200..32FF; Enclosed CJK Letters and Months + 0x3300, // 3300..33FF; CJK Compatibility + 0x3400, // 3400..4DBF; CJK Unified Ideographs Extension A + 0x4DC0, // 4DC0..4DFF; Yijing Hexagram Symbols + 0x4E00, // 4E00..9FFF; CJK Unified Ideograph + 0xA000, // A000..A48F; Yi Syllables + 0xA490, // A490..A4CF; Yi Radicals + 0xA4D0, // unassigned + 0xA500, // A500..A63F; Vai + 0xA640, // A640..A69F; Cyrillic Extended-B + 0xA6A0, // unassigned + 0xA700, // A700..A71F; Modifier Tone Letters + 0xA720, // A720..A7FF; Latin Extended-D + 0xA800, // A800..A82F; Syloti Nagri + 0xA830, // unassigned + 0xA840, // A840..A87F; Phags-pa + 0xA880, // A880..A8DF; Saurashtra + 0xA8E0, // unassigned + 0xA900, // A900..A92F; Kayah Li + 0xA930, // A930..A95F; Rejang + 0xA960, // unassigned + 0xAA00, // AA00..AA5F; Cham + 0xAA60, // unassigned + 0xAC00, // AC00..D7AF; Hangul Syllables + 0xD7B0, // unassigned + 0xD800, // D800..DB7F; High Surrogates + 0xDB80, // DB80..DBFF; High Private Use Surrogates + 0xDC00, // DC00..DFFF; Low Surrogates + 0xE000, // E000..F8FF; Private Use Area + 0xF900, // F900..FAFF; CJK Compatibility Ideographs + 0xFB00, // FB00..FB4F; Alphabetic Presentation Forms + 0xFB50, // FB50..FDFF; Arabic Presentation Forms-A + 0xFE00, // FE00..FE0F; Variation Selectors + 0xFE10, // FE10..FE1F; Vertical Forms + 0xFE20, // FE20..FE2F; Combining Half Marks + 0xFE30, // FE30..FE4F; CJK Compatibility Forms + 0xFE50, // FE50..FE6F; Small Form Variants + 0xFE70, // FE70..FEFF; Arabic Presentation Forms-B + 0xFF00, // FF00..FFEF; Halfwidth and Fullwidth Forms + 0xFFF0, // FFF0..FFFF; Specials + 0x10000, // 10000..1007F; Linear B Syllabary + 0x10080, // 10080..100FF; Linear B Ideograms + 0x10100, // 10100..1013F; Aegean Numbers + 0x10140, // 10140..1018F; Ancient Greek Numbers + 0x10190, // 10190..101CF; Ancient Symbols + 0x101D0, // 101D0..101FF; Phaistos Disc + 0x10200, // unassigned + 0x10280, // 10280..1029F; Lycian + 0x102A0, // 102A0..102DF; Carian + 0x102E0, // unassigned + 0x10300, // 10300..1032F; Old Italic + 0x10330, // 10330..1034F; Gothic + 0x10350, // unassigned + 0x10380, // 10380..1039F; Ugaritic + 0x103A0, // 103A0..103DF; Old Persian + 0x103E0, // unassigned + 0x10400, // 10400..1044F; Desere + 0x10450, // 10450..1047F; Shavian + 0x10480, // 10480..104AF; Osmanya + 0x104B0, // unassigned + 0x10800, // 10800..1083F; Cypriot Syllabary + 0x10840, // unassigned + 0x10900, // 10900..1091F; Phoenician + 0x10920, // 10920..1093F; Lydian + 0x10940, // unassigned + 0x10A00, // 10A00..10A5F; Kharoshthi + 0x10A60, // unassigned + 0x12000, // 12000..123FF; Cuneiform + 0x12400, // 12400..1247F; Cuneiform Numbers and Punctuation + 0x12480, // unassigned + 0x1D000, // 1D000..1D0FF; Byzantine Musical Symbols + 0x1D100, // 1D100..1D1FF; Musical Symbols + 0x1D200, // 1D200..1D24F; Ancient Greek Musical Notation + 0x1D250, // unassigned + 0x1D300, // 1D300..1D35F; Tai Xuan Jing Symbols + 0x1D360, // 1D360..1D37F; Counting Rod Numerals + 0x1D380, // unassigned + 0x1D400, // 1D400..1D7FF; Mathematical Alphanumeric Symbols + 0x1D800, // unassigned + 0x1F000, // 1F000..1F02F; Mahjong Tiles + 0x1F030, // 1F030..1F09F; Domino Tiles + 0x1F0A0, // unassigned + 0x20000, // 20000..2A6DF; CJK Unified Ideographs Extension B + 0x2A6E0, // unassigned + 0x2F800, // 2F800..2FA1F; CJK Compatibility Ideographs Supplement + 0x2FA20, // unassigned + 0xE0000, // E0000..E007F; Tags + 0xE0080, // unassigned + 0xE0100, // E0100..E01EF; Variation Selectors Supplement + 0xE01F0, // unassigned + 0xF0000, // F0000..FFFFF; Supplementary Private Use Area-A + 0x100000, // 100000..10FFFF; Supplementary Private Use Area-B }; private static final UnicodeBlock[] blocks = { @@ -1809,8 +2234,9 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara HEBREW, ARABIC, SYRIAC, - null, + ARABIC_SUPPLEMENT, THAANA, + NKO, null, DEVANAGARI, BENGALI, @@ -1829,7 +2255,7 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara GEORGIAN, HANGUL_JAMO, ETHIOPIC, - null, + ETHIOPIC_SUPPLEMENT, CHEROKEE, UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS, OGHAM, @@ -1843,11 +2269,19 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara null, LIMBU, TAI_LE, - null, + NEW_TAI_LUE, KHMER_SYMBOLS, + BUGINESE, + null, + BALINESE, + SUNDANESE, + null, + LEPCHA, + OL_CHIKI, null, PHONETIC_EXTENSIONS, - null, + PHONETIC_EXTENSIONS_SUPPLEMENT, + COMBINING_DIACRITICAL_MARKS_SUPPLEMENT, LATIN_EXTENDED_ADDITIONAL, GREEK_EXTENDED, GENERAL_PUNCTUATION, @@ -1874,7 +2308,14 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B, SUPPLEMENTAL_MATHEMATICAL_OPERATORS, MISCELLANEOUS_SYMBOLS_AND_ARROWS, - null, + GLAGOLITIC, + LATIN_EXTENDED_C, + COPTIC, + GEORGIAN_SUPPLEMENT, + TIFINAGH, + ETHIOPIC_EXTENDED, + CYRILLIC_EXTENDED_A, + SUPPLEMENTAL_PUNCTUATION, CJK_RADICALS_SUPPLEMENT, KANGXI_RADICALS, null, @@ -1886,7 +2327,7 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara HANGUL_COMPATIBILITY_JAMO, KANBUN, BOPOMOFO_EXTENDED, - null, + CJK_STROKES, KATAKANA_PHONETIC_EXTENSIONS, ENCLOSED_CJK_LETTERS_AND_MONTHS, CJK_COMPATIBILITY, @@ -1896,6 +2337,21 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara YI_SYLLABLES, YI_RADICALS, null, + VAI, + CYRILLIC_EXTENDED_B, + null, + MODIFIER_TONE_LETTERS, + LATIN_EXTENDED_D, + SYLOTI_NAGRI, + null, + PHAGS_PA, + SAURASHTRA, + null, + KAYAH_LI, + REJANG, + null, + CHAM, + null, HANGUL_SYLLABLES, null, HIGH_SURROGATES, @@ -1906,7 +2362,7 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara ALPHABETIC_PRESENTATION_FORMS, ARABIC_PRESENTATION_FORMS_A, VARIATION_SELECTORS, - null, + VERTICAL_FORMS, COMBINING_HALF_MARKS, CJK_COMPATIBILITY_FORMS, SMALL_FORM_VARIANTS, @@ -1916,11 +2372,18 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara LINEAR_B_SYLLABARY, LINEAR_B_IDEOGRAMS, AEGEAN_NUMBERS, + ANCIENT_GREEK_NUMBERS, + ANCIENT_SYMBOLS, + PHAISTOS_DISC, + null, + LYCIAN, + CARIAN, null, OLD_ITALIC, GOTHIC, null, UGARITIC, + OLD_PERSIAN, null, DESERET, SHAVIAN, @@ -1928,13 +2391,26 @@ class Character extends Object implements java.io.Serializable, Comparable<Chara null, CYPRIOT_SYLLABARY, null, + PHOENICIAN, + LYDIAN, + null, + KHAROSHTHI, + null, + CUNEIFORM, + CUNEIFORM_NUMBERS_AND_PUNCTUATION, + null, BYZANTINE_MUSICAL_SYMBOLS, MUSICAL_SYMBOLS, + ANCIENT_GREEK_MUSICAL_NOTATION, null, TAI_XUAN_JING_SYMBOLS, + COUNTING_ROD_NUMERALS, null, MATHEMATICAL_ALPHANUMERIC_SYMBOLS, null, + MAHJONG_TILES, + DOMINO_TILES, + null, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B, null, CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT, diff --git a/jdk/src/share/classes/java/lang/Class.java b/jdk/src/share/classes/java/lang/Class.java index 77df0d146fd..4ba497c64cf 100644 --- a/jdk/src/share/classes/java/lang/Class.java +++ b/jdk/src/share/classes/java/lang/Class.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2846,14 +2846,14 @@ public final if (loader == null) return desiredAssertionStatus0(this); - synchronized(loader) { - // If the classloader has been initialized with - // the assertion directives, ask it. Otherwise, - // ask the VM. - return (loader.classAssertionStatus == null ? - desiredAssertionStatus0(this) : - loader.desiredAssertionStatus(getName())); + // If the classloader has been initialized with the assertion + // directives, ask it. Otherwise, ask the VM. + synchronized(loader.assertionLock) { + if (loader.classAssertionStatus != null) { + return loader.desiredAssertionStatus(getName()); + } } + return desiredAssertionStatus0(this); } // Retrieves the desired assertion status of this class from the VM @@ -3059,14 +3059,12 @@ public final } - private static Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0]; - /** * @since 1.5 */ public Annotation[] getAnnotations() { initAnnotationsIfNecessary(); - return annotations.values().toArray(EMPTY_ANNOTATIONS_ARRAY); + return AnnotationParser.toArray(annotations); } /** @@ -3074,7 +3072,7 @@ public final */ public Annotation[] getDeclaredAnnotations() { initAnnotationsIfNecessary(); - return declaredAnnotations.values().toArray(EMPTY_ANNOTATIONS_ARRAY); + return AnnotationParser.toArray(declaredAnnotations); } // Annotations cache diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java index c0caa01dcf3..cc0987a5864 100644 --- a/jdk/src/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/share/classes/java/lang/ClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,14 +40,17 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; +import java.util.Collections; import java.util.Enumeration; -import java.util.Hashtable; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.Stack; import java.util.Map; import java.util.Vector; +import java.util.Hashtable; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; import sun.misc.ClassFileTransformer; import sun.misc.CompoundEnumeration; import sun.misc.Resource; @@ -91,6 +94,17 @@ import sun.security.util.SecurityConstants; * called the "bootstrap class loader", does not itself have a parent but may * serve as the parent of a <tt>ClassLoader</tt> instance. * + * <p> Class loaders that support concurrent loading of classes are known as + * <em>parallel capable</em> class loaders and are required to register + * themselves at their class initialization time by invoking the + * {@link + * #registerAsParallelCapable <tt>ClassLoader.registerAsParallelCapable</tt>} + * method. In environments in which the delegation model is not strictly + * hierarchical, class loaders need to be parallel capable, otherise class + * loading can lead to deadlocks because the loader lock is held for the + * duration of the class loading process (see {@link #loadClass + * <tt>loadClass</tt>} methods). + * * <p> Normally, the Java virtual machine loads classes from the local file * system in a platform-dependent manner. For example, on UNIX systems, the * virtual machine loads classes from the directory defined by the @@ -160,31 +174,51 @@ import sun.security.util.SecurityConstants; public abstract class ClassLoader { private static native void registerNatives(); + + // Set of classes which are registered as parallel capable class loaders + private static final Set<Class<? extends ClassLoader>> parallelLoaders + = Collections.newSetFromMap(Collections.synchronizedMap + (new WeakHashMap<Class<? extends ClassLoader>, Boolean>())); + static { registerNatives(); + parallelLoaders.add(ClassLoader.class); } // If initialization succeed this is set to true and security checks will // succeed. Otherwise the object is not initialized and the object is // useless. - private boolean initialized = false; + private final boolean initialized; // The parent class loader for delegation - private ClassLoader parent; + // Note: VM hardcoded the offset of this field, thus all new fields + // must be added *after* it. + private final ClassLoader parent; + + // Maps class name to the corresponding lock object when the current + // class loader is parallel capable. + // Note: VM also uses this field to decide if the current class loader + // is parallel capable and the appropriate lock object for class loading. + private final ConcurrentHashMap<String, Object> parallelLockMap; // Hashtable that maps packages to certs - private Hashtable<String, Certificate[]> package2certs - = new Hashtable<String, Certificate[]>(11); + private final Map <String, Certificate[]> package2certs; // Shared among all packages with unsigned classes - Certificate[] nocerts; + private static final Certificate[] nocerts = new Certificate[0]; - // The classes loaded by this class loader. The only purpose of this table + // The classes loaded by this class loader. The only purpose of this table // is to keep the classes from being GC'ed until the loader is GC'ed. - private Vector<Class<?>> classes = new Vector<Class<?>>(); + private final Vector<Class<?>> classes = new Vector<Class<?>>(); + + // The "default" domain. Set as the default ProtectionDomain on newly + // created classes. + private final ProtectionDomain defaultDomain = + new ProtectionDomain(new CodeSource(null, (Certificate[]) null), + null, this, null); // The initiating protection domains for all classes loaded by this loader - private Set<ProtectionDomain> domains = new HashSet<ProtectionDomain>(); + private final Set<ProtectionDomain> domains; // Invoked by the VM to record every loaded class with this loader. void addClass(Class c) { @@ -193,7 +227,9 @@ public abstract class ClassLoader { // The packages defined in this class loader. Each package name is mapped // to its corresponding Package object. - private HashMap<String, Package> packages = new HashMap<String, Package>(); + // @GuardedBy("itself") + private final HashMap<String, Package> packages = + new HashMap<String, Package>(); /** * Creates a new class loader using the specified parent class loader for @@ -220,6 +256,19 @@ public abstract class ClassLoader { security.checkCreateClassLoader(); } this.parent = parent; + if (parallelLoaders.contains(this.getClass())) { + parallelLockMap = new ConcurrentHashMap<String, Object>(); + package2certs = new ConcurrentHashMap<String, Certificate[]>(); + domains = + Collections.synchronizedSet(new HashSet<ProtectionDomain>()); + assertionLock = new Object(); + } else { + // no finer-grained lock; lock on the classloader instance + parallelLockMap = null; + package2certs = new Hashtable<String, Certificate[]>(); + domains = new HashSet<ProtectionDomain>(); + assertionLock = this; + } initialized = true; } @@ -244,10 +293,22 @@ public abstract class ClassLoader { security.checkCreateClassLoader(); } this.parent = getSystemClassLoader(); + if (parallelLoaders.contains(this.getClass())) { + parallelLockMap = new ConcurrentHashMap<String, Object>(); + package2certs = new ConcurrentHashMap<String, Certificate[]>(); + domains = + Collections.synchronizedSet(new HashSet<ProtectionDomain>()); + assertionLock = new Object(); + } else { + // no finer-grained lock; lock on the classloader instance + parallelLockMap = null; + package2certs = new Hashtable<String, Certificate[]>(); + domains = new HashSet<ProtectionDomain>(); + assertionLock = this; + } initialized = true; } - // -- Class -- /** @@ -296,6 +357,10 @@ public abstract class ClassLoader { * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link * #findClass(String)}, rather than this method. </p> * + * <p> Unless overridden, this method synchronizes on the result of + * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method + * during the entire class loading process. + * * @param name * The <a href="#name">binary name</a> of the class * @@ -307,37 +372,80 @@ public abstract class ClassLoader { * @throws ClassNotFoundException * If the class could not be found */ - protected synchronized Class<?> loadClass(String name, boolean resolve) + protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { - // First, check if the class has already been loaded - Class c = findLoadedClass(name); - if (c == null) { - try { - if (parent != null) { - c = parent.loadClass(name, false); - } else { - c = findBootstrapClass0(name); + synchronized (getClassLoadingLock(name)) { + // First, check if the class has already been loaded + Class c = findLoadedClass(name); + if (c == null) { + try { + if (parent != null) { + c = parent.loadClass(name, false); + } else { + c = findBootstrapClass0(name); + } + } catch (ClassNotFoundException e) { + // If still not found, then invoke findClass in order + // to find the class. + c = findClass(name); } - } catch (ClassNotFoundException e) { - // If still not found, then invoke findClass in order - // to find the class. - c = findClass(name); + } + if (resolve) { + resolveClass(c); + } + return c; + } + } + + /** + * Returns the lock object for class loading operations. + * For backward compatibility, the default implementation of this method + * behaves as follows. If this ClassLoader object is registered as + * parallel capable, the method returns a dedicated object associated + * with the specified class name. Otherwise, the method returns this + * ClassLoader object. </p> + * + * @param className + * The name of the to-be-loaded class + * + * @return the lock for class loading operations + * + * @throws NullPointerException + * If registered as parallel capable and <tt>className</tt> is null + * + * @see #loadClass(String, boolean) + * + * @since 1.7 + */ + protected Object getClassLoadingLock(String className) { + Object lock = this; + if (parallelLockMap != null) { + Object newLock = new Object(); + lock = parallelLockMap.putIfAbsent(className, newLock); + if (lock == null) { + lock = newLock; } } - if (resolve) { - resolveClass(c); - } - return c; + return lock; } // This method is invoked by the virtual machine to load a class. - private synchronized Class loadClassInternal(String name) + private Class loadClassInternal(String name) throws ClassNotFoundException { - return loadClass(name); + // For backward compatibility, explicitly lock on 'this' when + // the current class loader is not parallel capable. + if (parallelLockMap == null) { + synchronized (this) { + return loadClass(name); + } + } else { + return loadClass(name); + } } + // Invoked by the VM after loading class with this loader. private void checkPackageAccess(Class cls, ProtectionDomain pd) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -486,31 +594,32 @@ public abstract class ClassLoader { /* Determine protection domain, and check that: - not define java.* class, - - signer of this class matches signers for the rest of the classes in package. + - signer of this class matches signers for the rest of the classes in + package. */ private ProtectionDomain preDefineClass(String name, - ProtectionDomain protectionDomain) + ProtectionDomain pd) { if (!checkName(name)) throw new NoClassDefFoundError("IllegalName: " + name); if ((name != null) && name.startsWith("java.")) { - throw new SecurityException("Prohibited package name: " + - name.substring(0, name.lastIndexOf('.'))); + throw new SecurityException + ("Prohibited package name: " + + name.substring(0, name.lastIndexOf('.'))); } - if (protectionDomain == null) { - protectionDomain = getDefaultDomain(); + if (pd == null) { + pd = defaultDomain; } - if (name != null) - checkCerts(name, protectionDomain.getCodeSource()); + if (name != null) checkCerts(name, pd.getCodeSource()); - return protectionDomain; + return pd; } - private String defineClassSourceLocation(ProtectionDomain protectionDomain) + private String defineClassSourceLocation(ProtectionDomain pd) { - CodeSource cs = protectionDomain.getCodeSource(); + CodeSource cs = pd.getCodeSource(); String source = null; if (cs != null && cs.getLocation() != null) { source = cs.getLocation().toString(); @@ -519,14 +628,15 @@ public abstract class ClassLoader { } private Class defineTransformedClass(String name, byte[] b, int off, int len, - ProtectionDomain protectionDomain, + ProtectionDomain pd, ClassFormatError cfe, String source) throws ClassFormatError { // Class format error - try to transform the bytecode and // define the class again // - ClassFileTransformer[] transformers = ClassFileTransformer.getTransformers(); + ClassFileTransformer[] transformers = + ClassFileTransformer.getTransformers(); Class c = null; if (transformers != null) { @@ -535,7 +645,7 @@ public abstract class ClassLoader { // Transform byte code using transformer byte[] tb = transformer.transform(b, off, len); c = defineClass1(name, tb, 0, tb.length, - protectionDomain, source); + pd, source); break; } catch (ClassFormatError cfe2) { // If ClassFormatError occurs, try next transformer @@ -552,11 +662,10 @@ public abstract class ClassLoader { return c; } - private void postDefineClass(Class c, ProtectionDomain protectionDomain) + private void postDefineClass(Class c, ProtectionDomain pd) { - if (protectionDomain.getCodeSource() != null) { - Certificate certs[] = - protectionDomain.getCodeSource().getCertificates(); + if (pd.getCodeSource() != null) { + Certificate certs[] = pd.getCodeSource().getCertificates(); if (certs != null) setSigners(c, certs); } @@ -641,7 +750,8 @@ public abstract class ClassLoader { try { c = defineClass1(name, b, off, len, protectionDomain, source); } catch (ClassFormatError cfe) { - c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source); + c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, + source); } postDefineClass(c, protectionDomain); @@ -656,10 +766,10 @@ public abstract class ClassLoader { * specified in the documentation for {@link #defineClass(String, byte[], * int, int)}. Before the class can be used it must be resolved. * - * <p>The rules about the first class defined in a package determining the set of - * certificates for the package, and the restrictions on class names are identical - * to those specified in the documentation for {@link #defineClass(String, byte[], - * int, int, ProtectionDomain)}. + * <p>The rules about the first class defined in a package determining the + * set of certificates for the package, and the restrictions on class names + * are identical to those specified in the documentation for {@link + * #defineClass(String, byte[], int, int, ProtectionDomain)}. * * <p> An invocation of this method of the form * <i>cl</i><tt>.defineClass(</tt><i>name</i><tt>,</tt> @@ -668,12 +778,13 @@ public abstract class ClassLoader { * * <blockquote><tt> * ...<br> - * byte[] temp = new byte[</tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#remaining - * remaining}()];<br> + * byte[] temp = new byte[</tt><i>bBuffer</i><tt>.{@link + * java.nio.ByteBuffer#remaining remaining}()];<br> * </tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#get(byte[]) * get}(temp);<br> * return {@link #defineClass(String, byte[], int, int, ProtectionDomain) - * </tt><i>cl</i><tt>.defineClass}(</tt><i>name</i><tt>, temp, 0, temp.length, </tt><i>pd</i><tt>);<br> + * </tt><i>cl</i><tt>.defineClass}(</tt><i>name</i><tt>, temp, 0, + * temp.length, </tt><i>pd</i><tt>);<br> * </tt></blockquote> * * @param name @@ -682,9 +793,9 @@ public abstract class ClassLoader { * * @param b * The bytes that make up the class data. The bytes from positions - * <tt>b.position()</tt> through <tt>b.position() + b.limit() -1 </tt> - * should have the format of a valid class file as defined by the <a - * href="http://java.sun.com/docs/books/vmspec/">Java Virtual + * <tt>b.position()</tt> through <tt>b.position() + b.limit() -1 + * </tt> should have the format of a valid class file as defined by + * the <a href="http://java.sun.com/docs/books/vmspec/">Java Virtual * Machine Specification</a>. * * @param protectionDomain @@ -738,11 +849,13 @@ public abstract class ClassLoader { String source = defineClassSourceLocation(protectionDomain); try { - c = defineClass2(name, b, b.position(), len, protectionDomain, source); + c = defineClass2(name, b, b.position(), len, protectionDomain, + source); } catch (ClassFormatError cfe) { byte[] tb = new byte[len]; b.get(tb); // get bytes out of byte buffer. - c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe, source); + c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe, + source); } postDefineClass(c, protectionDomain); @@ -769,33 +882,29 @@ public abstract class ClassLoader { return true; } - private synchronized void checkCerts(String name, CodeSource cs) { + private void checkCerts(String name, CodeSource cs) { int i = name.lastIndexOf('.'); String pname = (i == -1) ? "" : name.substring(0, i); - Certificate[] pcerts = package2certs.get(pname); - if (pcerts == null) { - // first class in this package gets to define which - // certificates must be the same for all other classes - // in this package - if (cs != null) { - pcerts = cs.getCertificates(); - } - if (pcerts == null) { - if (nocerts == null) - nocerts = new Certificate[0]; - pcerts = nocerts; - } - package2certs.put(pname, pcerts); - } else { - Certificate[] certs = null; - if (cs != null) { - certs = cs.getCertificates(); - } - if (!compareCerts(pcerts, certs)) { - throw new SecurityException("class \""+ name + - "\"'s signer information does not match signer information of other classes in the same package"); + Certificate[] certs = null; + if (cs != null) { + certs = cs.getCertificates(); + } + Certificate[] pcerts = null; + if (parallelLockMap == null) { + synchronized (this) { + pcerts = package2certs.get(pname); + if (pcerts == null) { + package2certs.put(pname, (certs == null? nocerts:certs)); + } } + } else { + pcerts = ((ConcurrentHashMap<String, Certificate[]>)package2certs). + putIfAbsent(pname, (certs == null? nocerts:certs)); + } + if (pcerts != null && !compareCerts(pcerts, certs)) { + throw new SecurityException("class \""+ name + + "\"'s signer information does not match signer information of other classes in the same package"); } } @@ -1075,6 +1184,47 @@ public abstract class ClassLoader { return java.util.Collections.emptyEnumeration(); } + // index 0: java.lang.ClassLoader.class + // index 1: the immediate caller of index 0. + // index 2: the immediate caller of index 1. + private static native Class<? extends ClassLoader> getCaller(int index); + + /** + * Registers the caller class loader as parallel capable. + * In order for the registration to succeed, all super classes + * of the caller class loader must also be registered as + * parallel capable when this method is called. </p> + * Note that once a class loader is registered as + * parallel capable, there is no way to change it back. + * In addition, registration should be done statically before + * any instance of the caller classloader being constructed. </p> + * + * @return true if the caller is successfully registered as + * parallel capable and false if otherwise. + * + * @since 1.7 + */ + protected static boolean registerAsParallelCapable() { + Class<? extends ClassLoader> caller = getCaller(1); + Class superCls = caller.getSuperclass(); + boolean result = false; + // Explicit synchronization needed for composite action + synchronized (parallelLoaders) { + if (!parallelLoaders.contains(caller)) { + if (parallelLoaders.contains(superCls)) { + // register the immediate caller as parallel capable + // if and only if all of its super classes are. + // Note: given current classloading sequence, if + // the immediate super class is parallel capable, + // all the super classes higher up must be too. + result = true; + parallelLoaders.add(caller); + } + } else result = true; + } + return result; + } + /** * Find a resource of the specified name from the search path used to load * classes. This method locates the resource through the system class @@ -1141,7 +1291,8 @@ public abstract class ClassLoader { private static Enumeration<URL> getBootstrapResources(String name) throws IOException { - final Enumeration<Resource> e = getBootstrapClassPath().getResources(name); + final Enumeration<Resource> e = + getBootstrapClassPath().getResources(name); return new Enumeration<URL> () { public URL nextElement() { return e.nextElement().getURL(); @@ -1377,9 +1528,11 @@ public abstract class ClassLoader { } // The class loader for the system + // @GuardedBy("ClassLoader.class") private static ClassLoader scl; // Set to true once the system class loader has been set + // @GuardedBy("ClassLoader.class") private static boolean sclSet; @@ -1592,19 +1745,6 @@ public abstract class ClassLoader { } } - // The "default" domain. Set as the default ProtectionDomain on newly - // created classes. - private ProtectionDomain defaultDomain = null; - - // Returns (and initializes) the default domain. - private synchronized ProtectionDomain getDefaultDomain() { - if (defaultDomain == null) { - CodeSource cs = new CodeSource(null, (Certificate[]) null); - defaultDomain = new ProtectionDomain(cs, null, this, null); - } - return defaultDomain; - } - // All native library names we've loaded. private static Vector<String> loadedLibraryNames = new Vector<String>(); @@ -1622,8 +1762,8 @@ public abstract class ClassLoader { = new Stack<NativeLibrary>(); // The paths searched for libraries - static private String usr_paths[]; - static private String sys_paths[]; + private static String usr_paths[]; + private static String sys_paths[]; private static String[] initializePath(String propname) { String ldpath = System.getProperty(propname, ""); @@ -1803,7 +1943,10 @@ public abstract class ClassLoader { // -- Assertion management -- + final Object assertionLock; + // The default toggle for assertion checking. + // @GuardedBy("assertionLock") private boolean defaultAssertionStatus = false; // Maps String packageName to Boolean package default assertion status Note @@ -1811,12 +1954,14 @@ public abstract class ClassLoader { // is null then we are delegating assertion status queries to the VM, i.e., // none of this ClassLoader's assertion status modification methods have // been invoked. + // @GuardedBy("assertionLock") private Map<String, Boolean> packageAssertionStatus = null; // Maps String fullyQualifiedClassName to Boolean assertionStatus If this // field is null then we are delegating assertion status queries to the VM, // i.e., none of this ClassLoader's assertion status modification methods // have been invoked. + // @GuardedBy("assertionLock") Map<String, Boolean> classAssertionStatus = null; /** @@ -1834,11 +1979,13 @@ public abstract class ClassLoader { * * @since 1.4 */ - public synchronized void setDefaultAssertionStatus(boolean enabled) { - if (classAssertionStatus == null) - initializeJavaAssertionMaps(); + public void setDefaultAssertionStatus(boolean enabled) { + synchronized (assertionLock) { + if (classAssertionStatus == null) + initializeJavaAssertionMaps(); - defaultAssertionStatus = enabled; + defaultAssertionStatus = enabled; + } } /** @@ -1878,13 +2025,14 @@ public abstract class ClassLoader { * * @since 1.4 */ - public synchronized void setPackageAssertionStatus(String packageName, - boolean enabled) - { - if (packageAssertionStatus == null) - initializeJavaAssertionMaps(); + public void setPackageAssertionStatus(String packageName, + boolean enabled) { + synchronized (assertionLock) { + if (packageAssertionStatus == null) + initializeJavaAssertionMaps(); - packageAssertionStatus.put(packageName, enabled); + packageAssertionStatus.put(packageName, enabled); + } } /** @@ -1909,13 +2057,13 @@ public abstract class ClassLoader { * * @since 1.4 */ - public synchronized void setClassAssertionStatus(String className, - boolean enabled) - { - if (classAssertionStatus == null) - initializeJavaAssertionMaps(); + public void setClassAssertionStatus(String className, boolean enabled) { + synchronized (assertionLock) { + if (classAssertionStatus == null) + initializeJavaAssertionMaps(); - classAssertionStatus.put(className, enabled); + classAssertionStatus.put(className, enabled); + } } /** @@ -1928,15 +2076,16 @@ public abstract class ClassLoader { * * @since 1.4 */ - public synchronized void clearAssertionStatus() { + public void clearAssertionStatus() { /* * Whether or not "Java assertion maps" are initialized, set * them to empty maps, effectively ignoring any present settings. */ - classAssertionStatus = new HashMap<String, Boolean>(); - packageAssertionStatus = new HashMap<String, Boolean>(); - - defaultAssertionStatus = false; + synchronized (assertionLock) { + classAssertionStatus = new HashMap<String, Boolean>(); + packageAssertionStatus = new HashMap<String, Boolean>(); + defaultAssertionStatus = false; + } } /** @@ -1961,39 +2110,40 @@ public abstract class ClassLoader { * * @since 1.4 */ - synchronized boolean desiredAssertionStatus(String className) { - Boolean result; + boolean desiredAssertionStatus(String className) { + synchronized (assertionLock) { + // assert classAssertionStatus != null; + // assert packageAssertionStatus != null; - // assert classAssertionStatus != null; - // assert packageAssertionStatus != null; - - // Check for a class entry - result = classAssertionStatus.get(className); - if (result != null) - return result.booleanValue(); - - // Check for most specific package entry - int dotIndex = className.lastIndexOf("."); - if (dotIndex < 0) { // default package - result = packageAssertionStatus.get(null); + // Check for a class entry + Boolean result = classAssertionStatus.get(className); if (result != null) return result.booleanValue(); - } - while(dotIndex > 0) { - className = className.substring(0, dotIndex); - result = packageAssertionStatus.get(className); - if (result != null) - return result.booleanValue(); - dotIndex = className.lastIndexOf(".", dotIndex-1); - } - // Return the classloader default - return defaultAssertionStatus; + // Check for most specific package entry + int dotIndex = className.lastIndexOf("."); + if (dotIndex < 0) { // default package + result = packageAssertionStatus.get(null); + if (result != null) + return result.booleanValue(); + } + while(dotIndex > 0) { + className = className.substring(0, dotIndex); + result = packageAssertionStatus.get(className); + if (result != null) + return result.booleanValue(); + dotIndex = className.lastIndexOf(".", dotIndex-1); + } + + // Return the classloader default + return defaultAssertionStatus; + } } // Set up the assertions with information provided by the VM. + // Note: Should only be called inside a synchronized block private void initializeJavaAssertionMaps() { - // assert Thread.holdsLock(this); + // assert Thread.holdsLock(assertionLock); classAssertionStatus = new HashMap<String, Boolean>(); packageAssertionStatus = new HashMap<String, Boolean>(); diff --git a/jdk/src/share/classes/java/lang/ConditionalSpecialCasing.java b/jdk/src/share/classes/java/lang/ConditionalSpecialCasing.java index d81e550eef5..0e66326069c 100644 --- a/jdk/src/share/classes/java/lang/ConditionalSpecialCasing.java +++ b/jdk/src/share/classes/java/lang/ConditionalSpecialCasing.java @@ -74,6 +74,7 @@ final class ConditionalSpecialCasing { new Entry(0x00CC, new char[]{0x0069, 0x0307, 0x0300}, new char[]{0x00CC}, "lt", 0), // # LATIN CAPITAL LETTER I WITH GRAVE new Entry(0x00CD, new char[]{0x0069, 0x0307, 0x0301}, new char[]{0x00CD}, "lt", 0), // # LATIN CAPITAL LETTER I WITH ACUTE new Entry(0x0128, new char[]{0x0069, 0x0307, 0x0303}, new char[]{0x0128}, "lt", 0), // # LATIN CAPITAL LETTER I WITH TILDE + new Entry(0x0130, new char[]{0x0069, 0x0307}, new char[]{0x0130}, "lt", 0), // # LATIN CAPITAL LETTER I WITH DOT ABOVE //# ================================================================================ //# Turkish and Azeri @@ -84,7 +85,10 @@ final class ConditionalSpecialCasing { new Entry(0x0049, new char[]{0x0131}, new char[]{0x0049}, "tr", NOT_BEFORE_DOT), // # LATIN CAPITAL LETTER I new Entry(0x0049, new char[]{0x0131}, new char[]{0x0049}, "az", NOT_BEFORE_DOT), // # LATIN CAPITAL LETTER I new Entry(0x0069, new char[]{0x0069}, new char[]{0x0130}, "tr", 0), // # LATIN SMALL LETTER I - new Entry(0x0069, new char[]{0x0069}, new char[]{0x0130}, "az", 0) // # LATIN SMALL LETTER I + new Entry(0x0069, new char[]{0x0069}, new char[]{0x0130}, "az", 0), // # LATIN SMALL LETTER I + //# ================================================================================ + //# Other + new Entry(0x0130, new char[]{0x0069, 0x0307}, new char[]{0x0130}, "en", 0), // # LATIN CAPITALLETTER I WITH DOT ABOVE }; // A hash table that contains the above entries diff --git a/jdk/src/share/classes/java/lang/Integer.java b/jdk/src/share/classes/java/lang/Integer.java index f984f177275..50863dd7e9f 100644 --- a/jdk/src/share/classes/java/lang/Integer.java +++ b/jdk/src/share/classes/java/lang/Integer.java @@ -25,6 +25,8 @@ package java.lang; +import java.util.Properties; + /** * The {@code Integer} class wraps a value of the primitive type * {@code int} in an object. An object of type {@code Integer} @@ -442,6 +444,12 @@ public final class Integer extends Number implements Comparable<Integer> { public static int parseInt(String s, int radix) throws NumberFormatException { + /* + * WARNING: This method may be invoked early during VM initialization + * before IntegerCache is initialized. Care must be taken to not use + * the valueOf method. + */ + if (s == null) { throw new NumberFormatException("null"); } @@ -545,7 +553,7 @@ public final class Integer extends Number implements Comparable<Integer> { * does not contain a parsable {@code int}. */ public static Integer valueOf(String s, int radix) throws NumberFormatException { - return new Integer(parseInt(s,radix)); + return Integer.valueOf(parseInt(s,radix)); } /** @@ -570,20 +578,56 @@ public final class Integer extends Number implements Comparable<Integer> { * @exception NumberFormatException if the string cannot be parsed * as an integer. */ - public static Integer valueOf(String s) throws NumberFormatException - { - return new Integer(parseInt(s, 10)); + public static Integer valueOf(String s) throws NumberFormatException { + return Integer.valueOf(parseInt(s, 10)); + } + + /** + * Cache to support the object identity semantics of autoboxing for values between + * -128 and 127 (inclusive) as required by JLS. + * + * The cache is initialized on first usage. During VM initialization the + * getAndRemoveCacheProperties method may be used to get and remove any system + * properites that configure the cache size. At this time, the size of the + * cache may be controlled by the -XX:AutoBoxCacheMax=<size> option. + */ + + // value of java.lang.Integer.IntegerCache.high property (obtained during VM init) + private static String integerCacheHighPropValue; + + static void getAndRemoveCacheProperties() { + if (!sun.misc.VM.isBooted()) { + Properties props = System.getProperties(); + integerCacheHighPropValue = + (String)props.remove("java.lang.Integer.IntegerCache.high"); + if (integerCacheHighPropValue != null) + System.setProperties(props); // remove from system props + } } private static class IntegerCache { - private IntegerCache(){} - - static final Integer cache[] = new Integer[-(-128) + 127 + 1]; + static final int low = -128; + static final int high; + static final Integer cache[]; static { - for(int i = 0; i < cache.length; i++) - cache[i] = new Integer(i - 128); + // high value may be configured by property + int h = 127; + if (integerCacheHighPropValue != null) { + int i = parseInt(integerCacheHighPropValue); + i = Math.max(i, 127); + // Maximum array size is Integer.MAX_VALUE + h = Math.min(i, Integer.MAX_VALUE - (-low)); + } + high = h; + + cache = new Integer[(high - low) + 1]; + int j = low; + for(int k = 0; k < cache.length; k++) + cache[k] = new Integer(j++); } + + private IntegerCache() {} } /** @@ -599,10 +643,9 @@ public final class Integer extends Number implements Comparable<Integer> { * @since 1.5 */ public static Integer valueOf(int i) { - final int offset = 128; - if (i >= -128 && i <= 127) { // must cache - return IntegerCache.cache[i + offset]; - } + assert IntegerCache.high >= 127; + if (i >= IntegerCache.low && i <= IntegerCache.high) + return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } @@ -806,7 +849,7 @@ public final class Integer extends Number implements Comparable<Integer> { */ public static Integer getInteger(String nm, int val) { Integer result = getInteger(nm, null); - return (result == null) ? new Integer(val) : result; + return (result == null) ? Integer.valueOf(val) : result; } /** @@ -938,7 +981,7 @@ public final class Integer extends Number implements Comparable<Integer> { try { result = Integer.valueOf(nm.substring(index), radix); - result = negative ? new Integer(-result.intValue()) : result; + result = negative ? Integer.valueOf(-result.intValue()) : result; } catch (NumberFormatException e) { // If number is Integer.MIN_VALUE, we'll end up here. The next line // handles this case, and causes any genuine format error to be diff --git a/jdk/src/share/classes/java/lang/Long.java b/jdk/src/share/classes/java/lang/Long.java index 62400a9b967..c632d5df2d9 100644 --- a/jdk/src/share/classes/java/lang/Long.java +++ b/jdk/src/share/classes/java/lang/Long.java @@ -510,7 +510,7 @@ public final class Long extends Number implements Comparable<Long> { * contain a parsable {@code long}. */ public static Long valueOf(String s, int radix) throws NumberFormatException { - return new Long(parseLong(s, radix)); + return Long.valueOf(parseLong(s, radix)); } /** @@ -537,7 +537,7 @@ public final class Long extends Number implements Comparable<Long> { */ public static Long valueOf(String s) throws NumberFormatException { - return new Long(parseLong(s, 10)); + return Long.valueOf(parseLong(s, 10)); } private static class LongCache { @@ -650,7 +650,7 @@ public final class Long extends Number implements Comparable<Long> { try { result = Long.valueOf(nm.substring(index), radix); - result = negative ? new Long(-result.longValue()) : result; + result = negative ? Long.valueOf(-result.longValue()) : result; } catch (NumberFormatException e) { // If number is Long.MIN_VALUE, we'll end up here. The next line // handles this case, and causes any genuine format error to be @@ -869,7 +869,7 @@ public final class Long extends Number implements Comparable<Long> { */ public static Long getLong(String nm, long val) { Long result = Long.getLong(nm, null); - return (result == null) ? new Long(val) : result; + return (result == null) ? Long.valueOf(val) : result; } /** diff --git a/jdk/src/share/classes/java/lang/Shutdown.java b/jdk/src/share/classes/java/lang/Shutdown.java index 18e32d96f8e..b77b45056a7 100644 --- a/jdk/src/share/classes/java/lang/Shutdown.java +++ b/jdk/src/share/classes/java/lang/Shutdown.java @@ -25,8 +25,6 @@ package java.lang; -import java.util.ArrayList; - /** * Package-private utility class containing data structures and logic @@ -47,8 +45,13 @@ class Shutdown { /* Should we run all finalizers upon exit? */ private static boolean runFinalizersOnExit = false; - /* The set of registered, wrapped hooks, or null if there aren't any */ - private static ArrayList<Runnable> hooks = new ArrayList<Runnable>(); + // The system shutdown hooks are registered with a predefined slot. + // The list of shutdown hooks is as follows: + // (0) Console restore hook + // (1) Application hooks + // (2) DeleteOnExit hook + private static final int MAX_SYSTEM_HOOKS = 10; + private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS]; /* The preceding static fields are protected by this lock */ private static class Lock { }; @@ -68,33 +71,18 @@ class Shutdown { /* Add a new shutdown hook. Checks the shutdown state and the hook itself, * but does not do any security checks. */ - static void add(Runnable hook) { + static void add(int slot, Runnable hook) { synchronized (lock) { if (state > RUNNING) throw new IllegalStateException("Shutdown in progress"); - hooks.add(hook); + if (hooks[slot] != null) + throw new InternalError("Shutdown hook at slot " + slot + " already registered"); + + hooks[slot] = hook; } } - - /* Remove a previously-registered hook. Like the add method, this method - * does not do any security checks. - */ - static boolean remove(Runnable hook) { - synchronized (lock) { - if (state > RUNNING) - throw new IllegalStateException("Shutdown in progress"); - if (hook == null) throw new NullPointerException(); - if (hooks == null) { - return false; - } else { - return hooks.remove(hook); - } - } - } - - /* Run all registered shutdown hooks */ private static void runHooks() { @@ -103,7 +91,7 @@ class Shutdown { */ for (Runnable hook : hooks) { try { - hook.run(); + if (hook != null) hook.run(); } catch(Throwable t) { if (t instanceof ThreadDeath) { ThreadDeath td = (ThreadDeath)t; diff --git a/jdk/src/share/classes/java/lang/String.java b/jdk/src/share/classes/java/lang/String.java index 28d96de741b..316da645f3c 100644 --- a/jdk/src/share/classes/java/lang/String.java +++ b/jdk/src/share/classes/java/lang/String.java @@ -2451,14 +2451,21 @@ public final class String } if (localeDependent || srcChar == '\u03A3') { // GREEK CAPITAL LETTER SIGMA lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale); + } else if (srcChar == '\u0130') { // LATIN CAPITAL LETTER I DOT + lowerChar = Character.ERROR; } else { lowerChar = Character.toLowerCase(srcChar); } if ((lowerChar == Character.ERROR) || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) { if (lowerChar == Character.ERROR) { - lowerCharArray = - ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale); + if (!localeDependent && srcChar == '\u0130') { + lowerCharArray = + ConditionalSpecialCasing.toLowerCaseCharArray(this, i, Locale.ENGLISH); + } else { + lowerCharArray = + ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale); + } } else if (srcCount == 2) { resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount; continue; diff --git a/jdk/src/share/classes/java/lang/StringCoding.java b/jdk/src/share/classes/java/lang/StringCoding.java index 833fdf5f603..885db317af5 100644 --- a/jdk/src/share/classes/java/lang/StringCoding.java +++ b/jdk/src/share/classes/java/lang/StringCoding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,10 @@ package java.lang; -import java.io.CharConversionException; import java.io.UnsupportedEncodingException; import java.lang.ref.SoftReference; import java.nio.ByteBuffer; import java.nio.CharBuffer; -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; @@ -39,11 +36,12 @@ import java.nio.charset.CharacterCodingException; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.MalformedInputException; import java.nio.charset.UnsupportedCharsetException; import java.util.Arrays; import sun.misc.MessageUtils; import sun.nio.cs.HistoricallyNamedCharset; +import sun.nio.cs.ArrayDecoder; +import sun.nio.cs.ArrayEncoder; /** * Utility class for string encoding and decoding. @@ -74,10 +72,8 @@ class StringCoding { // Trim the given byte array to the given length // - private static byte[] safeTrim(byte[] ba, int len, Charset cs) { - if (len == ba.length - && (System.getSecurityManager() == null - || cs.getClass().getClassLoader0() == null)) + private static byte[] safeTrim(byte[] ba, int len, Charset cs, boolean isTrusted) { + if (len == ba.length && (isTrusted || System.getSecurityManager() == null)) return ba; else return Arrays.copyOf(ba, len); @@ -85,10 +81,9 @@ class StringCoding { // Trim the given char array to the given length // - private static char[] safeTrim(char[] ca, int len, Charset cs) { - if (len == ca.length - && (System.getSecurityManager() == null - || cs.getClass().getClassLoader0() == null)) + private static char[] safeTrim(char[] ca, int len, + Charset cs, boolean isTrusted) { + if (len == ca.length && (isTrusted || System.getSecurityManager() == null)) return ca; else return Arrays.copyOf(ca, len); @@ -128,6 +123,7 @@ class StringCoding { private final String requestedCharsetName; private final Charset cs; private final CharsetDecoder cd; + private final boolean isTrusted; private StringDecoder(Charset cs, String rcn) { this.requestedCharsetName = rcn; @@ -135,6 +131,7 @@ class StringCoding { this.cd = cs.newDecoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); + this.isTrusted = (cs.getClass().getClassLoader0() == null); } String charsetName() { @@ -152,24 +149,28 @@ class StringCoding { char[] ca = new char[en]; if (len == 0) return ca; - cd.reset(); - ByteBuffer bb = ByteBuffer.wrap(ba, off, len); - CharBuffer cb = CharBuffer.wrap(ca); - try { - CoderResult cr = cd.decode(bb, cb, true); - if (!cr.isUnderflow()) - cr.throwException(); - cr = cd.flush(cb); - if (!cr.isUnderflow()) - cr.throwException(); - } catch (CharacterCodingException x) { - // Substitution is always enabled, - // so this shouldn't happen - throw new Error(x); + if (cd instanceof ArrayDecoder) { + int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca); + return safeTrim(ca, clen, cs, isTrusted); + } else { + cd.reset(); + ByteBuffer bb = ByteBuffer.wrap(ba, off, len); + CharBuffer cb = CharBuffer.wrap(ca); + try { + CoderResult cr = cd.decode(bb, cb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = cd.flush(cb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + // Substitution is always enabled, + // so this shouldn't happen + throw new Error(x); + } + return safeTrim(ca, cb.position(), cs, isTrusted); } - return safeTrim(ca, cb.position(), cs); } - } static char[] decode(String charsetName, byte[] ba, int off, int len) @@ -193,8 +194,57 @@ class StringCoding { } static char[] decode(Charset cs, byte[] ba, int off, int len) { - StringDecoder sd = new StringDecoder(cs, cs.name()); - return sd.decode(Arrays.copyOfRange(ba, off, off + len), 0, len); + // (1)We never cache the "external" cs, the only benefit of creating + // an additional StringDe/Encoder object to wrap it is to share the + // de/encode() method. These SD/E objects are short-lifed, the young-gen + // gc should be able to take care of them well. But the best approash + // is still not to generate them if not really necessary. + // (2)The defensive copy of the input byte/char[] has a big performance + // impact, as well as the outgoing result byte/char[]. Need to do the + // optimization check of (sm==null && classLoader0==null) for both. + // (3)getClass().getClassLoader0() is expensive + // (4)There might be a timing gap in isTrusted setting. getClassLoader0() + // is only chcked (and then isTrusted gets set) when (SM==null). It is + // possible that the SM==null for now but then SM is NOT null later + // when safeTrim() is invoked...the "safe" way to do is to redundant + // check (... && (isTrusted || SM == null || getClassLoader0())) in trim + // but it then can be argued that the SM is null when the opertaion + // is started... + CharsetDecoder cd = cs.newDecoder(); + int en = scale(len, cd.maxCharsPerByte()); + char[] ca = new char[en]; + if (len == 0) + return ca; + boolean isTrusted = false; + if (System.getSecurityManager() != null) { + if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) { + ba = Arrays.copyOfRange(ba, off, off + len); + off = 0; + } + } + if (cd instanceof ArrayDecoder) { + int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca); + return safeTrim(ca, clen, cs, isTrusted); + } else { + cd.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE) + .reset(); + ByteBuffer bb = ByteBuffer.wrap(ba, off, len); + CharBuffer cb = CharBuffer.wrap(ca); + try { + CoderResult cr = cd.decode(bb, cb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = cd.flush(cb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + // Substitution is always enabled, + // so this shouldn't happen + throw new Error(x); + } + return safeTrim(ca, cb.position(), cs, isTrusted); + } } static char[] decode(byte[] ba, int off, int len) { @@ -218,14 +268,12 @@ class StringCoding { } } - - - // -- Encoding -- private static class StringEncoder { private Charset cs; private CharsetEncoder ce; private final String requestedCharsetName; + private final boolean isTrusted; private StringEncoder(Charset cs, String rcn) { this.requestedCharsetName = rcn; @@ -233,6 +281,7 @@ class StringCoding { this.ce = cs.newEncoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); + this.isTrusted = (cs.getClass().getClassLoader0() == null); } String charsetName() { @@ -250,23 +299,27 @@ class StringCoding { byte[] ba = new byte[en]; if (len == 0) return ba; - - ce.reset(); - ByteBuffer bb = ByteBuffer.wrap(ba); - CharBuffer cb = CharBuffer.wrap(ca, off, len); - try { - CoderResult cr = ce.encode(cb, bb, true); - if (!cr.isUnderflow()) - cr.throwException(); - cr = ce.flush(bb); - if (!cr.isUnderflow()) - cr.throwException(); - } catch (CharacterCodingException x) { - // Substitution is always enabled, - // so this shouldn't happen - throw new Error(x); + if (ce instanceof ArrayEncoder) { + int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba); + return safeTrim(ba, blen, cs, isTrusted); + } else { + ce.reset(); + ByteBuffer bb = ByteBuffer.wrap(ba); + CharBuffer cb = CharBuffer.wrap(ca, off, len); + try { + CoderResult cr = ce.encode(cb, bb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = ce.flush(bb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + // Substitution is always enabled, + // so this shouldn't happen + throw new Error(x); + } + return safeTrim(ba, bb.position(), cs, isTrusted); } - return safeTrim(ba, bb.position(), cs); } } @@ -291,8 +344,39 @@ class StringCoding { } static byte[] encode(Charset cs, char[] ca, int off, int len) { - StringEncoder se = new StringEncoder(cs, cs.name()); - return se.encode(Arrays.copyOfRange(ca, off, off + len), 0, len); + CharsetEncoder ce = cs.newEncoder(); + int en = scale(len, ce.maxBytesPerChar()); + byte[] ba = new byte[en]; + if (len == 0) + return ba; + boolean isTrusted = false; + if (System.getSecurityManager() != null) { + if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) { + ca = Arrays.copyOfRange(ca, off, off + len); + off = 0; + } + } + if (ce instanceof ArrayEncoder) { + int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba); + return safeTrim(ba, blen, cs, isTrusted); + } else { + ce.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE) + .reset(); + ByteBuffer bb = ByteBuffer.wrap(ba); + CharBuffer cb = CharBuffer.wrap(ca, off, len); + try { + CoderResult cr = ce.encode(cb, bb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = ce.flush(bb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + throw new Error(x); + } + return safeTrim(ba, bb.position(), cs, isTrusted); + } } static byte[] encode(char[] ca, int off, int len) { diff --git a/jdk/src/share/classes/java/lang/System.java b/jdk/src/share/classes/java/lang/System.java index a81bfa70152..6c539b28e1c 100644 --- a/jdk/src/share/classes/java/lang/System.java +++ b/jdk/src/share/classes/java/lang/System.java @@ -34,7 +34,6 @@ import java.security.AllPermission; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; import sun.nio.ch.Interruptible; -import sun.net.InetAddressCachePolicy; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; import sun.reflect.annotation.AnnotationType; @@ -310,7 +309,6 @@ public final class System { } security = s; - InetAddressCachePolicy.setIfNotSet(InetAddressCachePolicy.FOREVER); } /** @@ -1107,6 +1105,13 @@ public final class System { props = new Properties(); initProperties(props); sun.misc.Version.init(); + + // Gets and removes system properties that configure the Integer + // cache used to support the object identity semantics of autoboxing. + // At this time, the size of the cache may be controlled by the + // -XX:AutoBoxCacheMax=<size> option. + Integer.getAndRemoveCacheProperties(); + FileInputStream fdIn = new FileInputStream(FileDescriptor.in); FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err); @@ -1121,14 +1126,6 @@ public final class System { // Setup Java signal handlers for HUP, TERM, and INT (where available). Terminator.setup(); - // The order in with the hooks are added here is important as it - // determines the order in which they are run. - // (1)Console restore hook needs to be called first. - // (2)Application hooks must be run before calling deleteOnExitHook. - Shutdown.add(sun.misc.SharedSecrets.getJavaIOAccess().consoleRestoreHook()); - Shutdown.add(ApplicationShutdownHooks.hook()); - Shutdown.add(sun.misc.SharedSecrets.getJavaIODeleteOnExitAccess()); - // Initialize any miscellenous operating system settings that need to be // set for the class libraries. Currently this is no-op everywhere except // for Windows where the process-wide error mode is set before the java.io @@ -1174,6 +1171,9 @@ public final class System { public void blockedOn(Thread t, Interruptible b) { t.blockedOn(b); } + public void registerShutdownHook(int slot, Runnable r) { + Shutdown.add(slot, r); + } }); } diff --git a/jdk/src/share/classes/java/lang/Thread.java b/jdk/src/share/classes/java/lang/Thread.java index 60300ebc911..d5d163bd6e3 100644 --- a/jdk/src/share/classes/java/lang/Thread.java +++ b/jdk/src/share/classes/java/lang/Thread.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,17 @@ package java.lang; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.security.AccessController; import java.security.AccessControlContext; import java.security.PrivilegedAction; import java.util.Map; import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.LockSupport; -import sun.misc.SoftCache; import sun.nio.ch.Interruptible; import sun.security.util.SecurityConstants; @@ -1640,8 +1644,17 @@ class Thread implements Runnable { new RuntimePermission("enableContextClassLoaderOverride"); /** cache of subclass security audit results */ - private static final SoftCache subclassAudits = new SoftCache(10); + /* Replace with ConcurrentReferenceHashMap when/if it appears in a future + * release */ + private static class Caches { + /** cache of subclass security audit results */ + static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = + new ConcurrentHashMap<WeakClassKey,Boolean>(); + /** queue for WeakReferences to audited subclasses */ + static final ReferenceQueue<Class<?>> subclassAuditsQueue = + new ReferenceQueue<Class<?>>(); + } /** * Verifies that this (possibly subclass) instance can be constructed @@ -1652,19 +1665,15 @@ class Thread implements Runnable { private static boolean isCCLOverridden(Class cl) { if (cl == Thread.class) return false; - Boolean result = null; - synchronized (subclassAudits) { - result = (Boolean) subclassAudits.get(cl); - if (result == null) { - /* - * Note: only new Boolean instances (i.e., not Boolean.TRUE or - * Boolean.FALSE) must be used as cache values, otherwise cache - * entry will pin associated class. - */ - result = new Boolean(auditSubclass(cl)); - subclassAudits.put(cl, result); - } + + processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); + WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); + Boolean result = Caches.subclassAudits.get(key); + if (result == null) { + result = Boolean.valueOf(auditSubclass(cl)); + Caches.subclassAudits.putIfAbsent(key, result); } + return result.booleanValue(); } @@ -1967,6 +1976,68 @@ class Thread implements Runnable { getUncaughtExceptionHandler().uncaughtException(this, e); } + /** + * Removes from the specified map any keys that have been enqueued + * on the specified reference queue. + */ + static void processQueue(ReferenceQueue<Class<?>> queue, + ConcurrentMap<? extends + WeakReference<Class<?>>, ?> map) + { + Reference<? extends Class<?>> ref; + while((ref = queue.poll()) != null) { + map.remove(ref); + } + } + + /** + * Weak key for Class objects. + **/ + static class WeakClassKey extends WeakReference<Class<?>> { + /** + * saved value of the referent's identity hash code, to maintain + * a consistent hash code after the referent has been cleared + */ + private final int hash; + + /** + * Create a new WeakClassKey to the given object, registered + * with a queue. + */ + WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) { + super(cl, refQueue); + hash = System.identityHashCode(cl); + } + + /** + * Returns the identity hash code of the original referent. + */ + @Override + public int hashCode() { + return hash; + } + + /** + * Returns true if the given object is this identical + * WeakClassKey instance, or, if this object's referent has not + * been cleared, if the given object is another WeakClassKey + * instance with the identical non-null referent as this one. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + + if (obj instanceof WeakClassKey) { + Object referent = get(); + return (referent != null) && + (referent == ((WeakClassKey) obj).get()); + } else { + return false; + } + } + } + /* Some private helper methods */ private native void setPriority0(int newPriority); private native void stop0(Object o); diff --git a/jdk/src/share/classes/java/lang/ref/ReferenceQueue.java b/jdk/src/share/classes/java/lang/ref/ReferenceQueue.java index 872ee14f8e2..9882844e5a8 100644 --- a/jdk/src/share/classes/java/lang/ref/ReferenceQueue.java +++ b/jdk/src/share/classes/java/lang/ref/ReferenceQueue.java @@ -51,7 +51,7 @@ public class ReferenceQueue<T> { static private class Lock { }; private Lock lock = new Lock(); - private Reference<? extends T> head = null; + private volatile Reference<? extends T> head = null; private long queueLength = 0; boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */ @@ -95,6 +95,8 @@ public class ReferenceQueue<T> { * otherwise <code>null</code> */ public Reference<? extends T> poll() { + if (head == null) + return null; synchronized (lock) { return reallyPoll(); } diff --git a/jdk/src/share/classes/java/lang/ref/SoftReference.java b/jdk/src/share/classes/java/lang/ref/SoftReference.java index 35c6710d18e..4a6428efaf4 100644 --- a/jdk/src/share/classes/java/lang/ref/SoftReference.java +++ b/jdk/src/share/classes/java/lang/ref/SoftReference.java @@ -63,11 +63,13 @@ package java.lang.ref; public class SoftReference<T> extends Reference<T> { - /* Timestamp clock, updated by the garbage collector + /** + * Timestamp clock, updated by the garbage collector */ static private long clock; - /* Timestamp updated by each invocation of the get method. The VM may use + /** + * Timestamp updated by each invocation of the get method. The VM may use * this field when selecting soft references to be cleared, but it is not * required to do so. */ @@ -108,7 +110,8 @@ public class SoftReference<T> extends Reference<T> { */ public T get() { T o = super.get(); - if (o != null) this.timestamp = clock; + if (o != null && this.timestamp != clock) + this.timestamp = clock; return o; } diff --git a/jdk/src/share/classes/java/lang/reflect/Constructor.java b/jdk/src/share/classes/java/lang/reflect/Constructor.java index 49d2478bd90..0c101ccacb8 100644 --- a/jdk/src/share/classes/java/lang/reflect/Constructor.java +++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java @@ -626,13 +626,11 @@ public final return (T) declaredAnnotations().get(annotationClass); } - private static final Annotation[] EMPTY_ANNOTATION_ARRAY=new Annotation[0]; - /** * @since 1.5 */ public Annotation[] getDeclaredAnnotations() { - return declaredAnnotations().values().toArray(EMPTY_ANNOTATION_ARRAY); + return AnnotationParser.toArray(declaredAnnotations()); } private transient Map<Class, Annotation> declaredAnnotations; diff --git a/jdk/src/share/classes/java/lang/reflect/Field.java b/jdk/src/share/classes/java/lang/reflect/Field.java index 33b6fc61ad8..5a3e9e9ab7d 100644 --- a/jdk/src/share/classes/java/lang/reflect/Field.java +++ b/jdk/src/share/classes/java/lang/reflect/Field.java @@ -1018,13 +1018,11 @@ class Field extends AccessibleObject implements Member { return (T) declaredAnnotations().get(annotationClass); } - private static final Annotation[] EMPTY_ANNOTATION_ARRAY=new Annotation[0]; - /** * @since 1.5 */ public Annotation[] getDeclaredAnnotations() { - return declaredAnnotations().values().toArray(EMPTY_ANNOTATION_ARRAY); + return AnnotationParser.toArray(declaredAnnotations()); } private transient Map<Class, Annotation> declaredAnnotations; diff --git a/jdk/src/share/classes/java/lang/reflect/Method.java b/jdk/src/share/classes/java/lang/reflect/Method.java index 97947468f08..c638869cd38 100644 --- a/jdk/src/share/classes/java/lang/reflect/Method.java +++ b/jdk/src/share/classes/java/lang/reflect/Method.java @@ -705,13 +705,11 @@ public final return (T) declaredAnnotations().get(annotationClass); } - private static final Annotation[] EMPTY_ANNOTATION_ARRAY=new Annotation[0]; - /** * @since 1.5 */ public Annotation[] getDeclaredAnnotations() { - return declaredAnnotations().values().toArray(EMPTY_ANNOTATION_ARRAY); + return AnnotationParser.toArray(declaredAnnotations()); } private transient Map<Class, Annotation> declaredAnnotations; diff --git a/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java b/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java index 597783bf730..18af8d6db64 100644 --- a/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java +++ b/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java @@ -33,6 +33,7 @@ import java.io.FileDescriptor; import java.io.ByteArrayOutputStream; import sun.net.ConnectionResetException; +import sun.net.NetHooks; /** * Default Socket Implementation. This implementation does @@ -304,6 +305,11 @@ abstract class AbstractPlainSocketImpl extends SocketImpl */ synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { + synchronized (fdLock) { + if (!closePending && (socket == null || !socket.isBound())) { + NetHooks.beforeTcpConnect(fd, address, port); + } + } try { FileDescriptor fd = acquireFD(); try { @@ -339,6 +345,11 @@ abstract class AbstractPlainSocketImpl extends SocketImpl protected synchronized void bind(InetAddress address, int lport) throws IOException { + synchronized (fdLock) { + if (!closePending && (socket == null || !socket.isBound())) { + NetHooks.beforeTcpBind(fd, address, lport); + } + } socketBind(address, lport); if (socket != null) socket.setBound(); diff --git a/jdk/src/share/classes/java/net/SocketPermission.java b/jdk/src/share/classes/java/net/SocketPermission.java index 9f948bed6a2..4c63ab9afba 100644 --- a/jdk/src/share/classes/java/net/SocketPermission.java +++ b/jdk/src/share/classes/java/net/SocketPermission.java @@ -113,7 +113,6 @@ import sun.security.util.SecurityConstants; * <p>Similarly, if the following permission: * * <pre> - * p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept"); * p2 = new SocketPermission("localhost:1024-", "accept,connect,listen"); * </pre> * diff --git a/jdk/src/share/classes/java/net/StandardProtocolFamily.java b/jdk/src/share/classes/java/net/StandardProtocolFamily.java index 7c11b32f59f..d4b03ed887f 100644 --- a/jdk/src/share/classes/java/net/StandardProtocolFamily.java +++ b/jdk/src/share/classes/java/net/StandardProtocolFamily.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ package java.net; /** - * Defines the standard family of communication protocols. + * Defines the standard families of communication protocols. * * @since 1.7 */ diff --git a/jdk/src/share/classes/java/net/StandardSocketOption.java b/jdk/src/share/classes/java/net/StandardSocketOption.java index 405038cc1c2..dba8ff22d90 100644 --- a/jdk/src/share/classes/java/net/StandardSocketOption.java +++ b/jdk/src/share/classes/java/net/StandardSocketOption.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ public final class StandardSocketOption { * * @see <a href="http://www.ietf.org/rfc/rfc919.txt">RFC 929: * Broadcasting Internet Datagrams</a> + * @see DatagramSocket#setBroadcast */ public static final SocketOption<Boolean> SO_BROADCAST = new StdSocketOption<Boolean>("SO_BROADCAST", Boolean.class); @@ -78,6 +79,7 @@ public final class StandardSocketOption { * * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC 1122 * Requirements for Internet Hosts -- Communication Layers</a> + * @see Socket#setKeepAlive */ public static final SocketOption<Boolean> SO_KEEPALIVE = new StdSocketOption<Boolean>("SO_KEEPALIVE", Boolean.class); @@ -107,6 +109,8 @@ public final class StandardSocketOption { * socket is bound or connected. Whether an implementation allows the * socket send buffer to be changed after the socket is bound is system * dependent. + * + * @see Socket#setSendBufferSize */ public static final SocketOption<Integer> SO_SNDBUF = new StdSocketOption<Integer>("SO_SNDBUF", Integer.class); @@ -145,6 +149,8 @@ public final class StandardSocketOption { * * @see <a href="http://www.ietf.org/rfc/rfc1323.txt">RFC 1323: TCP * Extensions for High Performance</a> + * @see Socket#setReceiveBufferSize + * @see ServerSocket#setReceiveBufferSize */ public static final SocketOption<Integer> SO_RCVBUF = new StdSocketOption<Integer>("SO_RCVBUF", Integer.class); @@ -175,6 +181,7 @@ public final class StandardSocketOption { * * @see <a href="http://www.ietf.org/rfc/rfc793.txt">RFC 793: Transmission * Control Protocol</a> + * @see ServerSocket#setReuseAddress */ public static final SocketOption<Boolean> SO_REUSEADDR = new StdSocketOption<Boolean>("SO_REUSEADDR", Boolean.class); @@ -205,6 +212,8 @@ public final class StandardSocketOption { * is system dependent. Setting the linger interval to a value that is * greater than its maximum value causes the linger interval to be set to * its maximum value. + * + * @see Socket#setSoLinger */ public static final SocketOption<Integer> SO_LINGER = new StdSocketOption<Integer>("SO_LINGER", Integer.class); @@ -215,15 +224,15 @@ public final class StandardSocketOption { /** * The Type of Service (ToS) octet in the Internet Protocol (IP) header. * - * <p> The value of this socket option is an {@code Integer}, the least - * significant 8 bits of which represents the value of the ToS octet in IP - * packets sent by sockets to an {@link StandardProtocolFamily#INET IPv4} - * socket. The interpretation of the ToS octet is network specific and - * is not defined by this class. Further information on the ToS octet can be - * found in <a href="http://www.ietf.org/rfc/rfc1349.txt">RFC 1349</a> - * and <a href="http://www.ietf.org/rfc/rfc2474.txt">RFC 2474</a>. The - * value of the socket option is a <em>hint</em>. An implementation may - * ignore the value, or ignore specific values. + * <p> The value of this socket option is an {@code Integer} representing + * the value of the ToS octet in IP packets sent by sockets to an {@link + * StandardProtocolFamily#INET IPv4} socket. The interpretation of the ToS + * octet is network specific and is not defined by this class. Further + * information on the ToS octet can be found in <a + * href="http://www.ietf.org/rfc/rfc1349.txt">RFC 1349</a> and <a + * href="http://www.ietf.org/rfc/rfc2474.txt">RFC 2474</a>. The value + * of the socket option is a <em>hint</em>. An implementation may ignore the + * value, or ignore specific values. * * <p> The initial/default value of the TOS field in the ToS octet is * implementation specific but will typically be {@code 0}. For @@ -235,6 +244,8 @@ public final class StandardSocketOption { * <p> The behavior of this socket option on a stream-oriented socket, or an * {@link StandardProtocolFamily#INET6 IPv6} socket, is not defined in this * release. + * + * @see DatagramSocket#setTrafficClass */ public static final SocketOption<Integer> IP_TOS = new StdSocketOption<Integer>("IP_TOS", Integer.class); @@ -257,6 +268,7 @@ public final class StandardSocketOption { * is system dependent. * * @see java.nio.channels.MulticastChannel + * @see MulticastSocket#setInterface */ public static final SocketOption<NetworkInterface> IP_MULTICAST_IF = new StdSocketOption<NetworkInterface>("IP_MULTICAST_IF", NetworkInterface.class); @@ -283,6 +295,7 @@ public final class StandardSocketOption { * prior to binding the socket is system dependent. * * @see java.nio.channels.MulticastChannel + * @see MulticastSocket#setTimeToLive */ public static final SocketOption<Integer> IP_MULTICAST_TTL = new StdSocketOption<Integer>("IP_MULTICAST_TTL", Integer.class); @@ -307,6 +320,7 @@ public final class StandardSocketOption { * binding the socket is system dependent. * * @see java.nio.channels.MulticastChannel + * @see MulticastSocket#setLoopbackMode */ public static final SocketOption<Boolean> IP_MULTICAST_LOOP = new StdSocketOption<Boolean>("IP_MULTICAST_LOOP", Boolean.class); @@ -328,11 +342,12 @@ public final class StandardSocketOption { * coalescing impacts performance. The socket option may be enabled at any * time. In other words, the Nagle Algorithm can be disabled. Once the option * is enabled, it is system dependent whether it can be subsequently - * disabled. In that case, invoking the {@code setOption} method to disable - * the option has no effect. + * disabled. If it cannot, then invoking the {@code setOption} method to + * disable the option has no effect. * * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC 1122: * Requirements for Internet Hosts -- Communication Layers</a> + * @see Socket#setTcpNoDelay */ public static final SocketOption<Boolean> TCP_NODELAY = new StdSocketOption<Boolean>("TCP_NODELAY", Boolean.class); diff --git a/jdk/src/share/classes/java/net/URLClassLoader.java b/jdk/src/share/classes/java/net/URLClassLoader.java index afb92b8c938..601601a5652 100644 --- a/jdk/src/share/classes/java/net/URLClassLoader.java +++ b/jdk/src/share/classes/java/net/URLClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,10 +74,10 @@ import sun.security.util.SecurityConstants; */ public class URLClassLoader extends SecureClassLoader implements Closeable { /* The search path for classes and resources */ - URLClassPath ucp; + private final URLClassPath ucp; /* The context to be used when loading classes and resources */ - private AccessControlContext acc; + private final AccessControlContext acc; /** * Constructs a new URLClassLoader for the given URLs. The URLs will be @@ -105,7 +105,19 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { security.checkCreateClassLoader(); } ucp = new URLClassPath(urls); - acc = AccessController.getContext(); + this.acc = AccessController.getContext(); + } + + URLClassLoader(URL[] urls, ClassLoader parent, + AccessControlContext acc) { + super(parent); + // this is to make the stack depth consistent with 1.1 + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + ucp = new URLClassPath(urls); + this.acc = acc; } /** @@ -136,7 +148,18 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { security.checkCreateClassLoader(); } ucp = new URLClassPath(urls); - acc = AccessController.getContext(); + this.acc = AccessController.getContext(); + } + + URLClassLoader(URL[] urls, AccessControlContext acc) { + super(); + // this is to make the stack depth consistent with 1.1 + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + ucp = new URLClassPath(urls); + this.acc = acc; } /** @@ -599,17 +622,14 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { public static URLClassLoader newInstance(final URL[] urls, final ClassLoader parent) { // Save the caller's context - AccessControlContext acc = AccessController.getContext(); + final AccessControlContext acc = AccessController.getContext(); // Need a privileged block to create the class loader URLClassLoader ucl = AccessController.doPrivileged( new PrivilegedAction<URLClassLoader>() { public URLClassLoader run() { - return new FactoryURLClassLoader(urls, parent); + return new FactoryURLClassLoader(urls, parent, acc); } }); - // Now set the context on the loader using the one we saved, - // not the one inside the privileged block... - ucl.acc = acc; return ucl; } @@ -626,18 +646,14 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { */ public static URLClassLoader newInstance(final URL[] urls) { // Save the caller's context - AccessControlContext acc = AccessController.getContext(); + final AccessControlContext acc = AccessController.getContext(); // Need a privileged block to create the class loader URLClassLoader ucl = AccessController.doPrivileged( new PrivilegedAction<URLClassLoader>() { public URLClassLoader run() { - return new FactoryURLClassLoader(urls); + return new FactoryURLClassLoader(urls, acc); } }); - - // Now set the context on the loader using the one we saved, - // not the one inside the privileged block... - ucl.acc = acc; return ucl; } @@ -649,20 +665,26 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { } } ); + ClassLoader.registerAsParallelCapable(); } } final class FactoryURLClassLoader extends URLClassLoader { - FactoryURLClassLoader(URL[] urls, ClassLoader parent) { - super(urls, parent); + static { + ClassLoader.registerAsParallelCapable(); } - FactoryURLClassLoader(URL[] urls) { - super(urls); + FactoryURLClassLoader(URL[] urls, ClassLoader parent, + AccessControlContext acc) { + super(urls, parent, acc); } - public final synchronized Class loadClass(String name, boolean resolve) + FactoryURLClassLoader(URL[] urls, AccessControlContext acc) { + super(urls, acc); + } + + public final Class loadClass(String name, boolean resolve) throws ClassNotFoundException { // First check if we have permission to access the package. This diff --git a/jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java b/jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java new file mode 100644 index 00000000000..7bc43357479 --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java @@ -0,0 +1,205 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.nio.ByteBuffer; +import java.util.concurrent.Future; + +/** + * An asynchronous channel that can read and write bytes. + * + * <p> Some channels may not allow more than one read or write to be outstanding + * at any given time. If a thread invokes a read method before a previous read + * operation has completed then a {@link ReadPendingException} will be thrown. + * Similarly, if a write method is invoked before a previous write has completed + * then {@link WritePendingException} is thrown. Whether or not other kinds of + * I/O operations may proceed concurrently with a read operation depends upon + * the type of the channel. + * + * <p> Note that {@link java.nio.ByteBuffer ByteBuffers} are not safe for use by + * multiple concurrent threads. When a read or write operation is initiated then + * care must be taken to ensure that the buffer is not accessed until the + * operation completes. + * + * @see Channels#newInputStream(AsynchronousByteChannel) + * @see Channels#newOutputStream(AsynchronousByteChannel) + * + * @since 1.7 + */ + +public interface AsynchronousByteChannel + extends AsynchronousChannel +{ + /** + * Reads a sequence of bytes from this channel into the given buffer. + * + * <p> This method initiates an operation to read a sequence of bytes from + * this channel into the given buffer. The method returns a {@link Future} + * representing the pending result of the operation. The result of the + * operation, obtained by invoking the {@code Future} 's {@link + * Future#get() get} method, is the number of bytes read or {@code -1} if + * all bytes have been read and the channel has reached end-of-stream. + * + * <p> This method initiates a read operation to read up to <i>r</i> bytes + * from the channel, where <i>r</i> is the number of bytes remaining in the + * buffer, that is, {@code dst.remaining()} at the time that the read is + * attempted. Where <i>r</i> is 0, the read operation completes immediately + * with a result of {@code 0} without initiating an I/O operation. + * + * <p> Suppose that a byte sequence of length <i>n</i> is read, where + * <tt>0</tt> <tt><</tt> <i>n</i> <tt><=</tt> <i>r</i>. + * This byte sequence will be transferred into the buffer so that the first + * byte in the sequence is at index <i>p</i> and the last byte is at index + * <i>p</i> <tt>+</tt> <i>n</i> <tt>-</tt> <tt>1</tt>, + * where <i>p</i> is the buffer's position at the moment the read is + * performed. Upon completion the buffer's position will be equal to + * <i>p</i> <tt>+</tt> <i>n</i>; its limit will not have changed. + * + * <p> Buffers are not safe for use by multiple concurrent threads so care + * should be taken to not to access the buffer until the operaton has completed. + * + * <p> This method may be invoked at any time. Some channel types may not + * allow more than one read to be outstanding at any given time. If a thread + * initiates a read operation before a previous read operation has + * completed then a {@link ReadPendingException} will be thrown. + * + * <p> The <tt>handler</tt> parameter is used to specify a {@link + * CompletionHandler}. When the read operation completes the handler's + * {@link CompletionHandler#completed completed} method is executed. + * + * + * @param dst + * The buffer into which bytes are to be transferred + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The completion handler object; can be {@code null} + * + * @return A Future representing the result of the operation + * + * @throws IllegalArgumentException + * If the buffer is read-only + * @throws ReadPendingException + * If the channel does not allow more than one read to be outstanding + * and a previous read has not completed + */ + <A> Future<Integer> read(ByteBuffer dst, + A attachment, + CompletionHandler<Integer,? super A> handler); + + /** + * Reads a sequence of bytes from this channel into the given buffer. + * + * <p> An invocation of this method of the form <tt>c.read(dst)</tt> + * behaves in exactly the same manner as the invocation + * <blockquote><pre> + * c.read(dst, null, null);</pre></blockquote> + * + * @param dst + * The buffer into which bytes are to be transferred + * + * @return A Future representing the result of the operation + * + * @throws IllegalArgumentException + * If the buffer is read-only + * @throws ReadPendingException + * If the channel does not allow more than one read to be outstanding + * and a previous read has not completed + */ + Future<Integer> read(ByteBuffer dst); + + /** + * Writes a sequence of bytes to this channel from the given buffer. + * + * <p> This method initiates an operation to write a sequence of bytes to + * this channel from the given buffer. This method returns a {@link + * Future} representing the pending result of the operation. The result + * of the operation, obtained by invoking the <tt>Future</tt>'s {@link + * Future#get() get} method, is the number of bytes written, possibly zero. + * + * <p> This method initiates a write operation to write up to <i>r</i> bytes + * to the channel, where <i>r</i> is the number of bytes remaining in the + * buffer, that is, {@code src.remaining()} at the moment the write is + * attempted. Where <i>r</i> is 0, the write operation completes immediately + * with a result of {@code 0} without initiating an I/O operation. + * + * <p> Suppose that a byte sequence of length <i>n</i> is written, where + * <tt>0</tt> <tt><</tt> <i>n</i> <tt><=</tt> <i>r</i>. + * This byte sequence will be transferred from the buffer starting at index + * <i>p</i>, where <i>p</i> is the buffer's position at the moment the + * write is performed; the index of the last byte written will be + * <i>p</i> <tt>+</tt> <i>n</i> <tt>-</tt> <tt>1</tt>. + * Upon completion the buffer's position will be equal to + * <i>p</i> <tt>+</tt> <i>n</i>; its limit will not have changed. + * + * <p> Buffers are not safe for use by multiple concurrent threads so care + * should be taken to not to access the buffer until the operaton has completed. + * + * <p> This method may be invoked at any time. Some channel types may not + * allow more than one write to be outstanding at any given time. If a thread + * initiates a write operation before a previous write operation has + * completed then a {@link WritePendingException} will be thrown. + * + * <p> The <tt>handler</tt> parameter is used to specify a {@link + * CompletionHandler}. When the write operation completes the handler's + * {@link CompletionHandler#completed completed} method is executed. + * + * @param src + * The buffer from which bytes are to be retrieved + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The completion handler object; can be {@code null} + * + * @return A Future representing the result of the operation + * + * @throws WritePendingException + * If the channel does not allow more than one write to be outstanding + * and a previous write has not completed + */ + <A> Future<Integer> write(ByteBuffer src, + A attachment, + CompletionHandler<Integer,? super A> handler); + + /** + * Writes a sequence of bytes to this channel from the given buffer. + * + * <p> An invocation of this method of the form <tt>c.write(src)</tt> + * behaves in exactly the same manner as the invocation + * <blockquote><pre> + * c.write(src, null, null);</pre></blockquote> + * + * @param src + * The buffer from which bytes are to be retrieved + * + * @return A Future representing the result of the operation + * + * @throws WritePendingException + * If the channel does not allow more than one write to be outstanding + * and a previous write has not completed + */ + Future<Integer> write(ByteBuffer src); +} diff --git a/jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java b/jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java new file mode 100644 index 00000000000..f3e4ffe4ea5 --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java @@ -0,0 +1,116 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.io.IOException; +import java.util.concurrent.Future; // javadoc + +/** + * A channel that supports asynchronous I/O operations. Asynchronous I/O + * operations will usually take one of two forms: + * + * <ol> + * <li><pre>{@link Future}<V> <em>operation</em>(<em>...</em>)</pre></li> + * <li><pre>Future<V> <em>operation</em>(<em>...</em> A attachment, {@link CompletionHandler}<V,? super A> handler)</pre></li> + * </ol> + * + * where <i>operation</i> is the name of the I/O operation (read or write for + * example), <i>V</i> is the result type of the I/O operation, and <i>A</i> is + * the type of an object attached to the I/O operation to provide context when + * consuming the result. The attachment is important for cases where a + * <em>state-less</em> {@code CompletionHandler} is used to consume the result + * of many I/O operations. + * + * <p> In the first form, the methods defined by the {@link Future Future} + * interface may be used to check if the operation has completed, wait for its + * completion, and to retrieve the result. In the second form, a {@link + * CompletionHandler} is invoked to consume the result of the I/O operation when + * it completes, fails, or is cancelled. + * + * <p> A channel that implements this interface is <em>asynchronously + * closeable</em>: If an I/O operation is outstanding on the channel and the + * channel's {@link #close close} method is invoked, then the I/O operation + * fails with the exception {@link AsynchronousCloseException}. + * + * <p> Asynchronous channels are safe for use by multiple concurrent threads. + * Some channel implementations may support concurrent reading and writing, but + * may not allow more than one read and one write operation to be outstanding at + * any given time. + * + * <h4>Cancellation</h4> + * + * <p> The {@code Future} interface defines the {@link Future#cancel cancel} + * method to cancel execution of a task. + * + * <p> Where the {@code cancel} method is invoked with the {@code + * mayInterruptIfRunning} parameter set to {@code true} then the I/O operation + * may be interrupted by closing the channel. This will cause any other I/O + * operations outstanding on the channel to complete with the exception {@link + * AsynchronousCloseException}. + * + * <p> If a {@code CompletionHandler} is specified when initiating an I/O + * operation, and the {@code cancel} method is invoked to cancel the I/O + * operation before it completes, then the {@code CompletionHandler}'s {@link + * CompletionHandler#cancelled cancelled} method is invoked. + * + * <p> If an implementation of this interface supports a means to cancel I/O + * operations, and where cancellation may leave the channel, or the entity to + * which it is connected, in an inconsistent state, then the channel is put into + * an implementation specific <em>error state</em> that prevents further + * attempts to initiate I/O operations on the channel. For example, if a read + * operation is cancelled but the implementation cannot guarantee that bytes + * have not been read from the channel then it puts the channel into error state + * state; further attempts to initiate a {@code read} operation causes an + * unspecified runtime exception to be thrown. + * + * <p> Where the {@code cancel} method is invoked to cancel read or write + * operations then it recommended that all buffers used in the I/O operations be + * discarded or care taken to ensure that the buffers are not accessed while the + * channel remains open. + * + * @since 1.7 + */ + +public interface AsynchronousChannel + extends Channel +{ + /** + * Closes this channel. + * + * <p> Any outstanding asynchronous operations upon this channel will + * complete with the exception {@link AsynchronousCloseException}. After a + * channel is closed then further attempts to initiate asynchronous I/O + * operations complete immediately with cause {@link ClosedChannelException}. + * + * <p> This method otherwise behaves exactly as specified by the {@link + * Channel} interface. + * + * @throws IOException + * If an I/O error occurs + */ + @Override + void close() throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/channels/AsynchronousChannelGroup.java b/jdk/src/share/classes/java/nio/channels/AsynchronousChannelGroup.java new file mode 100644 index 00000000000..1199e16b51f --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousChannelGroup.java @@ -0,0 +1,344 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +/** + * A grouping of asynchronous channels for the purpose of resource sharing. + * + * <p> An asynchronous channel group encapsulates the mechanics required to + * handle the completion of I/O operations initiated by {@link AsynchronousChannel + * asynchronous channels} that are bound to the group. A group has an associated + * thread pool to which tasks are submitted to handle I/O events and dispatch to + * {@link CompletionHandler completion-handlers} that consume the result of + * asynchronous operations performed on channels in the group. In addition to + * handling I/O events, the pooled threads may also execute other tasks required + * to support the execution of asynchronous I/O operations. + * + * <p> An asynchronous channel group is created by invoking the {@link + * #withFixedThreadPool withFixedThreadPool} or {@link #withCachedThreadPool + * withCachedThreadPool} methods defined here. Channels are bound to a group by + * specifying the group when constructing the channel. The associated thread + * pool is <em>owned</em> by the group; termination of the group results in the + * shutdown of the associated thread pool. + * + * <p> In addition to groups created explicitly, the Java virtual machine + * maintains a system-wide <em>default group</em> that is constructed + * automatically. Asynchronous channels that do not specify a group at + * construction time are bound to the default group. The default group has an + * associated thread pool that creates new threads as needed. The default group + * may be configured by means of system properties defined in the table below. + * Where the {@link java.util.concurrent.ThreadFactory ThreadFactory} for the + * default group is not configured then the pooled threads of the default group + * are {@link Thread#isDaemon daemon} threads. + * + * <table border> + * <tr> + * <th>System property</th> + * <th>Description</th> + * </tr> + * <tr> + * <tr> + * <td> {@code java.nio.channels.DefaultThreadPool.threadFactory} </td> + * <td> The value of this property is taken to be the fully-qualified name + * of a concrete {@link java.util.concurrent.ThreadFactory ThreadFactory} + * class. The class is loaded using the system class loader and instantiated. + * The factory's {@link java.util.concurrent.ThreadFactory#newThread + * newThread} method is invoked to create each thread for the default + * group's thread pool. If the process to load and instantiate the value + * of the property fails then an unspecified error is thrown during the + * construction of the default group. </td> + * </tr> + * <tr> + * <td> {@code java.nio.channels.DefaultThreadPool.initialSize} </td> + * <td> The value of the {@code initialSize} parameter for the default + * group (see {@link #withCachedThreadPool withCachedThreadPool}). + * The value of the property is taken to be the {@code String} + * representation of an {@code Integer} that is the initial size parameter. + * If the value cannot be parsed as an {@code Integer} it causes an + * unspecified error to be thrown during the construction of the default + * group. </td> + * </tr> + * </table> + * + * <a name="threading"><h4>Threading</h4></a> + * + * <p> The completion handler for an I/O operation initiated on a channel bound + * to a group is guaranteed to be invoked by one of the pooled threads in the + * group. This ensures that the completion handler is run by a thread with the + * expected <em>identity</em>. + * + * <p> Where an I/O operation completes immediately, and the initiating thread + * is one of the pooled threads in the group then the completion handler may + * be invoked directly by the initiating thread. To avoid stack overflow, an + * implementation may impose a limit as to the number of activations on the + * thread stack. Some I/O operations may prohibit invoking the completion + * handler directly by the initiating thread (see {@link + * AsynchronousServerSocketChannel#accept(Object,CompletionHandler) accept}). + * + * <a name="shutdown"><h4>Shutdown and Termination</h4></a> + * + * <p> The {@link #shutdown() shutdown} method is used to initiate an <em>orderly + * shutdown</em> of a group. An orderly shutdown marks the group as shutdown; + * further attempts to construct a channel that binds to the group will throw + * {@link ShutdownChannelGroupException}. Whether or not a group is shutdown can + * be tested using the {@link #isShutdown() isShutdown} method. Once shutdown, + * the group <em>terminates</em> when all asynchronous channels that are bound to + * the group are closed, all actively executing completion handlers have run to + * completion, and resources used by the group are released. No attempt is made + * to stop or interrupt threads that are executing completion handlers. The + * {@link #isTerminated() isTerminated} method is used to test if the group has + * terminated, and the {@link #awaitTermination awaitTermination} method can be + * used to block until the group has terminated. + * + * <p> The {@link #shutdownNow() shutdownNow} method can be used to initiate a + * <em>forceful shutdown</em> of the group. In addition to the actions performed + * by an orderly shutdown, the {@code shutdownNow} method closes all open channels + * in the group as if by invoking the {@link AsynchronousChannel#close close} + * method. + * + * @since 1.7 + * + * @see AsynchronousSocketChannel#open(AsynchronousChannelGroup) + * @see AsynchronousServerSocketChannel#open(AsynchronousChannelGroup) + */ + +public abstract class AsynchronousChannelGroup { + private final AsynchronousChannelProvider provider; + + /** + * Initialize a new instance of this class. + * + * @param provider + * The asynchronous channel provider for this group + */ + protected AsynchronousChannelGroup(AsynchronousChannelProvider provider) { + this.provider = provider; + } + + /** + * Returns the provider that created this channel group. + * + * @return The provider that created this channel group + */ + public final AsynchronousChannelProvider provider() { + return provider; + } + + /** + * Creates an asynchronous channel group with a fixed thread pool. + * + * <p> The resulting asynchronous channel group reuses a fixed number of + * threads. At any point, at most {@code nThreads} threads will be active + * processing tasks that are submitted to handle I/O events and dispatch + * completion results for operations initiated on asynchronous channels in + * the group. + * + * <p> The group is created by invoking the {@link + * AsynchronousChannelProvider#openAsynchronousChannelGroup(int,ThreadFactory) + * openAsynchronousChannelGroup(int,ThreadFactory)} method of the system-wide + * default {@link AsynchronousChannelProvider} object. + * + * @param nThreads + * The number of threads in the pool + * @param threadFactory + * The factory to use when creating new threads + * + * @return A new asynchronous channel group + * + * @throws IllegalArgumentException + * If {@code nThreads <= 0} + * @throws IOException + * If an I/O error occurs + */ + public static AsynchronousChannelGroup withFixedThreadPool(int nThreads, + ThreadFactory threadFactory) + throws IOException + { + return AsynchronousChannelProvider.provider() + .openAsynchronousChannelGroup(nThreads, threadFactory); + } + + /** + * Creates an asynchronous channel group with a given thread pool that + * creates new threads as needed. + * + * <p> The {@code executor} parameter is an {@code ExecutorService} that + * creates new threads as needed to execute tasks that are submitted to + * handle I/O events and dispatch completion results for operations initiated + * on asynchronous channels in the group. It may reuse previously constructed + * threads when they are available. + * + * <p> The {@code initialSize} parameter may be used by the implementation + * as a <em>hint</em> as to the initial number of tasks it may submit. For + * example, it may be used to indictae the initial number of threads that + * wait on I/O events. + * + * <p> The executor is intended to be used exclusively by the resulting + * asynchronous channel group. Termination of the group results in the + * orderly {@link ExecutorService#shutdown shutdown} of the executor + * service. Shutting down the executor service by other means results in + * unspecified behavior. + * + * <p> The group is created by invoking the {@link + * AsynchronousChannelProvider#openAsynchronousChannelGroup(ExecutorService,int) + * openAsynchronousChannelGroup(ExecutorService,int)} method of the system-wide + * default {@link AsynchronousChannelProvider} object. + * + * @param executor + * The thread pool for the resulting group + * @param initialSize + * A value {@code >=0} or a negative value for implementation + * specific default + * + * @return A new asynchronous channel group + * + * @throws IOException + * If an I/O error occurs + * + * @see java.util.concurrent.Executors#newCachedThreadPool + */ + public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor, + int initialSize) + throws IOException + { + return AsynchronousChannelProvider.provider() + .openAsynchronousChannelGroup(executor, initialSize); + } + + /** + * Creates an asynchronous channel group with a given thread pool. + * + * <p> The {@code executor} parameter is an {@code ExecutorService} that + * executes tasks submitted to dispatch completion results for operations + * initiated on asynchronous channels in the group. + * + * <p> Care should be taken when configuring the executor service. It + * should support <em>direct handoff</em> or <em>unbounded queuing</em> of + * submitted tasks, and the thread that invokes the {@link + * ExecutorService#execute execute} method should never invoke the task + * directly. An implementation may mandate additional constraints. + * + * <p> The executor is intended to be used exclusively by the resulting + * asynchronous channel group. Termination of the group results in the + * orderly {@link ExecutorService#shutdown shutdown} of the executor + * service. Shutting down the executor service by other means results in + * unspecified behavior. + * + * <p> The group is created by invoking the {@link + * AsynchronousChannelProvider#openAsynchronousChannelGroup(ExecutorService,int) + * openAsynchronousChannelGroup(ExecutorService,int)} method of the system-wide + * default {@link AsynchronousChannelProvider} object with an {@code + * initialSize} of {@code 0}. + * + * @param executor + * The thread pool for the resulting group + * + * @return A new asynchronous channel group + * + * @throws IOException + * If an I/O error occurs + */ + public static AsynchronousChannelGroup withThreadPool(ExecutorService executor) + throws IOException + { + return AsynchronousChannelProvider.provider() + .openAsynchronousChannelGroup(executor, 0); + } + + /** + * Tells whether or not this asynchronous channel group is shutdown. + * + * @return {@code true} if this asynchronous channel group is shutdown or + * has been marked for shutdown. + */ + public abstract boolean isShutdown(); + + /** + * Tells whether or not this group has terminated. + * + * <p> Where this method returns {@code true}, then the associated thread + * pool has also {@link ExecutorService#isTerminated terminated}. + * + * @return {@code true} if this group has terminated + */ + public abstract boolean isTerminated(); + + /** + * Initiates an orderly shutdown of the group. + * + * <p> This method marks the group as shutdown. Further attempts to construct + * channel that binds to this group will throw {@link ShutdownChannelGroupException}. + * The group terminates when all asynchronous channels in the group are + * closed, all actively executing completion handlers have run to completion, + * and all resources have been released. This method has no effect if the + * group is already shutdown. + */ + public abstract void shutdown(); + + /** + * Shuts down the group and closes all open channels in the group. + * + * <p> In addition to the actions performed by the {@link #shutdown() shutdown} + * method, this method invokes the {@link AsynchronousChannel#close close} + * method on all open channels in the group. This method does not attempt to + * stop or interrupt threads that are executing completion handlers. The + * group terminates when all actively executing completion handlers have run + * to completion and all resources have been released. This method may be + * invoked at any time. If some other thread has already invoked it, then + * another invocation will block until the first invocation is complete, + * after which it will return without effect. + * + * @throws IOException + * If an I/O error occurs + */ + public abstract void shutdownNow() throws IOException; + + /** + * Awaits termination of the group. + + * <p> This method blocks until the group has terminated, or the timeout + * occurs, or the current thread is interrupted, whichever happens first. + * + * @param timeout + * The maximum time to wait, or zero or less to not wait + * @param unit + * The time unit of the timeout argument + * + * @return {@code true} if the group has terminated; {@code false} if the + * timeout elapsed before termination + * + * @throws InterruptedException + * If interrupted while waiting + */ + public abstract boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException; +} diff --git a/jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java b/jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java new file mode 100644 index 00000000000..6a9d9f09715 --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java @@ -0,0 +1,718 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.nio.channels.spi.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.Future; +import java.io.IOException; +import java.net.SocketOption; +import java.net.SocketAddress; +import java.net.ProtocolFamily; +import java.nio.ByteBuffer; + +/** + * An asynchronous channel for datagram-oriented sockets. + * + * <p> An asynchronous datagram channel is created by invoking one of the {@link + * #open open} methods defined by this class. It is not possible to create a channel + * for an arbitrary, pre-existing datagram socket. A newly-created asynchronous + * datagram channel is open but not connected. It need not be connected in order + * for the {@link #send send} and {@link #receive receive} methods to be used. + * A datagram channel may be connected, by invoking its {@link #connect connect} + * method, in order to avoid the overhead of the security checks that are otherwise + * performed as part of every send and receive operation when a security manager + * is set. The channel must be connected in order to use the {@link #read read} + * and {@link #write write} methods, since those methods do not accept or return + * socket addresses. Once connected, an asynchronous datagram channel remains + * connected until it is disconnected or closed. + * + * <p> Socket options are configured using the {@link #setOption(SocketOption,Object) + * setOption} method. An asynchronous datagram channel to an Internet Protocol + * (IP) socket supports the following options: + * <blockquote> + * <table border> + * <tr> + * <th>Option Name</th> + * <th>Description</th> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} </td> + * <td> The size of the socket send buffer </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td> + * <td> The size of the socket receive buffer </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td> + * <td> Re-use address </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_BROADCAST SO_BROADCAST} </td> + * <td> Allow transmission of broadcast datagrams </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#IP_TOS IP_TOS} </td> + * <td> The Type of Service (ToS) octet in the Internet Protocol (IP) header </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#IP_MULTICAST_IF IP_MULTICAST_IF} </td> + * <td> The network interface for Internet Protocol (IP) multicast datagrams </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#IP_MULTICAST_TTL + * IP_MULTICAST_TTL} </td> + * <td> The <em>time-to-live</em> for Internet Protocol (IP) multicast + * datagrams </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#IP_MULTICAST_LOOP + * IP_MULTICAST_LOOP} </td> + * <td> Loopback for Internet Protocol (IP) multicast datagrams </td> + * </tr> + * </table> + * </blockquote> + * Additional (implementation specific) options may also be supported. + * + * <p> Asynchronous datagram channels allow more than one read/receive and + * write/send to be oustanding at any given time. + * + * <p> <b>Usage Example:</b> + * <pre> + * final AsynchronousDatagramChannel dc = AsynchronousDatagramChannel.open() + * .bind(new InetSocketAddress(4000)); + * + * // print the source address of all packets that we receive + * dc.receive(buffer, buffer, new CompletionHandler<SocketAddress,ByteBuffer>() { + * public void completed(SocketAddress sa, ByteBuffer buffer) { + * try { + * System.out.println(sa); + * + * buffer.clear(); + * dc.receive(buffer, buffer, this); + * } catch (...) { ... } + * } + * public void failed(Throwable exc, ByteBuffer buffer) { + * ... + * } + * public void cancelled(ByteBuffer buffer) { + * ... + * } + * }); + * </pre> + * + * @since 1.7 + */ + +public abstract class AsynchronousDatagramChannel + implements AsynchronousByteChannel, MulticastChannel +{ + private final AsynchronousChannelProvider provider; + + /** + * Initializes a new instance of this class. + */ + protected AsynchronousDatagramChannel(AsynchronousChannelProvider provider) { + this.provider = provider; + } + + /** + * Returns the provider that created this channel. + */ + public final AsynchronousChannelProvider provider() { + return provider; + } + + /** + * Opens an asynchronous datagram channel. + * + * <p> The new channel is created by invoking the {@link + * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousDatagramChannel + * openAsynchronousDatagramChannel} method on the {@link + * java.nio.channels.spi.AsynchronousChannelProvider} object that created + * the given group (or the default provider where {@code group} is {@code + * null}). + * + * <p> The {@code family} parameter is used to specify the {@link ProtocolFamily}. + * If the datagram channel is to be used for Internet Protocol {@link + * MulticastChannel multicasting} then this parameter should correspond to + * the address type of the multicast groups that this channel will join. + * + * @param family + * The protocol family, or {@code null} to use the default protocol + * family + * @param group + * The group to which the newly constructed channel should be bound, + * or {@code null} for the default group + * + * @return A new asynchronous datagram channel + * + * @throws UnsupportedOperationException + * If the specified protocol family is not supported. For example, + * suppose the parameter is specified as {@link + * java.net.StandardProtocolFamily#INET6 INET6} but IPv6 is not + * enabled on the platform. + * @throws ShutdownChannelGroupException + * The specified group is shutdown + * @throws IOException + * If an I/O error occurs + */ + public static AsynchronousDatagramChannel open(ProtocolFamily family, + AsynchronousChannelGroup group) + throws IOException + { + AsynchronousChannelProvider provider = (group == null) ? + AsynchronousChannelProvider.provider() : group.provider(); + return provider.openAsynchronousDatagramChannel(family, group); + } + + /** + * Opens an asynchronous datagram channel. + * + * <p> This method returns an asynchronous datagram channel that is + * bound to the <em>default group</em>. This method is equivalent to evaluating + * the expression: + * <blockquote><pre> + * open((ProtocolFamily)null, (AsynchronousChannelGroup)null); + * </pre></blockquote> + * + * @return A new asynchronous datagram channel + * + * @throws IOException + * If an I/O error occurs + */ + public static AsynchronousDatagramChannel open() + throws IOException + { + return open(null, null); + } + + // -- Socket-specific operations -- + + /** + * @throws AlreadyBoundException {@inheritDoc} + * @throws UnsupportedAddressTypeException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException + * If a security manager has been installed and its {@link + * SecurityManager#checkListen checkListen} method denies the + * operation + */ + @Override + public abstract AsynchronousDatagramChannel bind(SocketAddress local) + throws IOException; + + /** + * @throws IllegalArgumentException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + @Override + public abstract <T> AsynchronousDatagramChannel setOption(SocketOption<T> name, T value) + throws IOException; + + /** + * Returns the remote address to which this channel is connected. + * + * <p> Where the channel is connected to an Internet Protocol socket address + * then the return value from this method is of type {@link + * java.net.InetSocketAddress}. + * + * @return The remote address; {@code null} if the channel's socket is not + * connected + * + * @throws ClosedChannelException + * If the channel is closed + * @throws IOException + * If an I/O error occurs + */ + public abstract SocketAddress getRemoteAddress() throws IOException; + + /** + * Connects this channel's socket. + * + * <p> The channel's socket is configured so that it only receives + * datagrams from, and sends datagrams to, the given remote <i>peer</i> + * address. Once connected, datagrams may not be received from or sent to + * any other address. A datagram socket remains connected until it is + * explicitly disconnected or until it is closed. + * + * <p> This method performs exactly the same security checks as the {@link + * java.net.DatagramSocket#connect connect} method of the {@link + * java.net.DatagramSocket} class. That is, if a security manager has been + * installed then this method verifies that its {@link + * java.lang.SecurityManager#checkAccept checkAccept} and {@link + * java.lang.SecurityManager#checkConnect checkConnect} methods permit + * datagrams to be received from and sent to, respectively, the given + * remote address. + * + * <p> This method may be invoked at any time. Whether it has any effect + * on outstanding read or write operations is implementation specific and + * therefore not specified. + * + * @param remote + * The remote address to which this channel is to be connected + * + * @return This datagram channel + * + * @throws ClosedChannelException + * If this channel is closed + * + * @throws SecurityException + * If a security manager has been installed + * and it does not permit access to the given remote address + * + * @throws IOException + * If some other I/O error occurs + */ + public abstract AsynchronousDatagramChannel connect(SocketAddress remote) + throws IOException; + + /** + * Disconnects this channel's socket. + * + * <p> The channel's socket is configured so that it can receive datagrams + * from, and sends datagrams to, any remote address so long as the security + * manager, if installed, permits it. + * + * <p> This method may be invoked at any time. Whether it has any effect + * on outstanding read or write operations is implementation specific and + * therefore not specified. + * + * @return This datagram channel + * + * @throws IOException + * If some other I/O error occurs + */ + public abstract AsynchronousDatagramChannel disconnect() throws IOException; + + /** + * Receives a datagram via this channel. + * + * <p> This method initiates the receiving of a datagram, returning a + * {@code Future} representing the pending result of the operation. + * The {@code Future}'s {@link Future#get() get} method returns + * the source address of the datagram upon successful completion. + * + * <p> The datagram is transferred into the given byte buffer starting at + * its current position, as if by a regular {@link AsynchronousByteChannel#read + * read} operation. If there are fewer bytes remaining in the buffer + * than are required to hold the datagram then the remainder of the datagram + * is silently discarded. + * + * <p> If a timeout is specified and the timeout elapses before the operation + * completes then the operation completes with the exception {@link + * InterruptedByTimeoutException}. When a timeout elapses then the state of + * the {@link ByteBuffer} is not defined. The buffers should be discarded or + * at least care must be taken to ensure that the buffer is not accessed + * while the channel remains open. + * + * <p> When a security manager has been installed and the channel is not + * connected, then it verifies that the source's address and port number are + * permitted by the security manager's {@link SecurityManager#checkAccept + * checkAccept} method. The permission check is performed with privileges that + * are restricted by the calling context of this method. If the permission + * check fails then the operation completes with a {@link SecurityException}. + * The overhead of this security check can be avoided by first connecting the + * socket via the {@link #connect connect} method. + * + * @param dst + * The buffer into which the datagram is to be transferred + * @param timeout + * The timeout, or {@code 0L} for no timeout + * @param unit + * The time unit of the {@code timeout} argument + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return a {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the timeout is negative or the buffer is read-only + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public abstract <A> Future<SocketAddress> receive(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<SocketAddress,? super A> handler); + + /** + * Receives a datagram via this channel. + * + * <p> This method initiates the receiving of a datagram, returning a + * {@code Future} representing the pending result of the operation. + * The {@code Future}'s {@link Future#get() get} method returns + * the source address of the datagram upon successful completion. + * + * <p> This method is equivalent to invoking {@link + * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a + * timeout of {@code 0L}. + * + * @param dst + * The buffer into which the datagram is to be transferred + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return a {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the buffer is read-only + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public final <A> Future<SocketAddress> receive(ByteBuffer dst, + A attachment, + CompletionHandler<SocketAddress,? super A> handler) + { + return receive(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + } + + /** + * Receives a datagram via this channel. + * + * <p> This method initiates the receiving of a datagram, returning a + * {@code Future} representing the pending result of the operation. + * The {@code Future}'s {@link Future#get() get} method returns + * the source address of the datagram upon successful completion. + * + * <p> This method is equivalent to invoking {@link + * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a + * timeout of {@code 0L}, and an attachment and completion handler + * of {@code null}. + * + * @param dst + * The buffer into which the datagram is to be transferred + * + * @return a {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the buffer is read-only + */ + public final <A> Future<SocketAddress> receive(ByteBuffer dst) { + return receive(dst, 0L, TimeUnit.MILLISECONDS, null, null); + } + + /** + * Sends a datagram via this channel. + * + * <p> This method initiates sending of a datagram, returning a + * {@code Future} representing the pending result of the operation. + * The operation sends the remaining bytes in the given buffer as a single + * datagram to the given target address. The result of the operation, obtained + * by invoking the {@code Future}'s {@link Future#get() get} + * method, is the number of bytes sent. + * + * <p> The datagram is transferred from the byte buffer as if by a regular + * {@link AsynchronousByteChannel#write write} operation. + * + * <p> If a timeout is specified and the timeout elapses before the operation + * completes then the operation completes with the exception {@link + * InterruptedByTimeoutException}. When a timeout elapses then the state of + * the {@link ByteBuffer} is not defined. The buffers should be discarded or + * at least care must be taken to ensure that the buffer is not accessed + * while the channel remains open. + * + * <p> If there is a security manager installed and the the channel is not + * connected then this method verifies that the target address and port number + * are permitted by the security manager's {@link SecurityManager#checkConnect + * checkConnect} method. The overhead of this security check can be avoided + * by first connecting the socket via the {@link #connect connect} method. + * + * @param src + * The buffer containing the datagram to be sent + * @param target + * The address to which the datagram is to be sent + * @param timeout + * The timeout, or {@code 0L} for no timeout + * @param unit + * The time unit of the {@code timeout} argument + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return a {@code Future} object representing the pending result + * + * @throws UnresolvedAddressException + * If the given remote address is not fully resolved + * @throws UnsupportedAddressTypeException + * If the type of the given remote address is not supported + * @throws IllegalArgumentException + * If the timeout is negative, or if the channel's socket is + * connected to an address that is not equal to {@code target} + * @throws SecurityException + * If a security manager has been installed and it does not permit + * datagrams to be sent to the given address + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public abstract <A> Future<Integer> send(ByteBuffer src, + SocketAddress target, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Integer,? super A> handler); + + /** + * Sends a datagram via this channel. + * + * <p> This method initiates sending of a datagram, returning a + * {@code Future} representing the pending result of the operation. + * The operation sends the remaining bytes in the given buffer as a single + * datagram to the given target address. The result of the operation, obtained + * by invoking the {@code Future}'s {@link Future#get() get} + * method, is the number of bytes sent. + * + * <p> This method is equivalent to invoking {@link + * #send(ByteBuffer,SocketAddress,long,TimeUnit,Object,CompletionHandler)} + * with a timeout of {@code 0L}. + * + * @param src + * The buffer containing the datagram to be sent + * @param target + * The address to which the datagram is to be sent + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return a {@code Future} object representing the pending result + * + * @throws UnresolvedAddressException + * If the given remote address is not fully resolved + * @throws UnsupportedAddressTypeException + * If the type of the given remote address is not supported + * @throws IllegalArgumentException + * If the channel's socket is connected and is connected to an + * address that is not equal to {@code target} + * @throws SecurityException + * If a security manager has been installed and it does not permit + * datagrams to be sent to the given address + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public final <A> Future<Integer> send(ByteBuffer src, + SocketAddress target, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + return send(src, target, 0L, TimeUnit.MILLISECONDS, attachment, handler); + } + + /** + * Sends a datagram via this channel. + * + * <p> This method initiates sending of a datagram, returning a + * {@code Future} representing the pending result of the operation. + * The operation sends the remaining bytes in the given buffer as a single + * datagram to the given target address. The result of the operation, obtained + * by invoking the {@code Future}'s {@link Future#get() get} + * method, is the number of bytes sent. + * + * <p> This method is equivalent to invoking {@link + * #send(ByteBuffer,SocketAddress,long,TimeUnit,Object,CompletionHandler)} + * with a timeout of {@code 0L} and an attachment and completion handler + * of {@code null}. + * + * @param src + * The buffer containing the datagram to be sent + * @param target + * The address to which the datagram is to be sent + * + * @return a {@code Future} object representing the pending result + * + * @throws UnresolvedAddressException + * If the given remote address is not fully resolved + * @throws UnsupportedAddressTypeException + * If the type of the given remote address is not supported + * @throws IllegalArgumentException + * If the channel's socket is connected and is connected to an + * address that is not equal to {@code target} + * @throws SecurityException + * If a security manager has been installed and it does not permit + * datagrams to be sent to the given address + */ + public final Future<Integer> send(ByteBuffer src, SocketAddress target) { + return send(src, target, 0L, TimeUnit.MILLISECONDS, null, null); + } + + /** + * Receives a datagram via this channel. + * + * <p> This method initiates the receiving of a datagram, returning a + * {@code Future} representing the pending result of the operation. + * The {@code Future}'s {@link Future#get() get} method returns + * the number of bytes transferred upon successful completion. + * + * <p> This method may only be invoked if this channel is connected, and it + * only accepts datagrams from the peer that the channel is connected too. + * The datagram is transferred into the given byte buffer starting at + * its current position and exactly as specified in the {@link + * AsynchronousByteChannel} interface. If there are fewer bytes + * remaining in the buffer than are required to hold the datagram then the + * remainder of the datagram is silently discarded. + * + * <p> If a timeout is specified and the timeout elapses before the operation + * completes then the operation completes with the exception {@link + * InterruptedByTimeoutException}. When a timeout elapses then the state of + * the {@link ByteBuffer} is not defined. The buffers should be discarded or + * at least care must be taken to ensure that the buffer is not accessed + * while the channel remains open. + * + * @param dst + * The buffer into which the datagram is to be transferred + * @param timeout + * The timeout, or {@code 0L} for no timeout + * @param unit + * The time unit of the {@code timeout} argument + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return a {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the timeout is negative or buffer is read-only + * @throws NotYetConnectedException + * If this channel is not connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public abstract <A> Future<Integer> read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Integer,? super A> handler); + + /** + * @throws NotYetConnectedException + * If this channel is not connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + @Override + public final <A> Future<Integer> read(ByteBuffer dst, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + } + + /** + * @throws NotYetConnectedException + * If this channel is not connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + @Override + public final Future<Integer> read(ByteBuffer dst) { + return read(dst, 0L, TimeUnit.MILLISECONDS, null, null); + } + + /** + * Writes a datagram to this channel. + * + * <p> This method initiates sending of a datagram, returning a + * {@code Future} representing the pending result of the operation. + * The operation sends the remaining bytes in the given buffer as a single + * datagram. The result of the operation, obtained by invoking the + * {@code Future}'s {@link Future#get() get} method, is the + * number of bytes sent. + * + * <p> The datagram is transferred from the byte buffer as if by a regular + * {@link AsynchronousByteChannel#write write} operation. + * + * <p> This method may only be invoked if this channel is connected, + * in which case it sends datagrams directly to the socket's peer. Otherwise + * it behaves exactly as specified in the {@link + * AsynchronousByteChannel} interface. + * + * <p> If a timeout is specified and the timeout elapses before the operation + * completes then the operation completes with the exception {@link + * InterruptedByTimeoutException}. When a timeout elapses then the state of + * the {@link ByteBuffer} is not defined. The buffers should be discarded or + * at least care must be taken to ensure that the buffer is not accessed + * while the channel remains open. + * + * @param src + * The buffer containing the datagram to be sent + * @param timeout + * The timeout, or {@code 0L} for no timeout + * @param unit + * The time unit of the {@code timeout} argument + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return a {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the timeout is negative + * @throws NotYetConnectedException + * If this channel is not connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public abstract <A> Future<Integer> write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Integer,? super A> handler); + /** + * @throws NotYetConnectedException + * If this channel is not connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + @Override + public final <A> Future<Integer> write(ByteBuffer src, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler); + } + + /** + * @throws NotYetConnectedException + * If this channel is not connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + @Override + public final Future<Integer> write(ByteBuffer src) { + return write(src, 0L, TimeUnit.MILLISECONDS, null, null); + } +} diff --git a/jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java b/jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java new file mode 100644 index 00000000000..a9bff5f16d4 --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java @@ -0,0 +1,774 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.nio.file.*; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.spi.*; +import java.nio.ByteBuffer; +import java.io.IOException; +import java.util.concurrent.Future; +import java.util.concurrent.ExecutorService; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; + +/** + * An asynchronous channel for reading, writing, and manipulating a file. + * + * <p> An asynchronous file channel is created when a file is opened by invoking + * one of the {@link #open open} methods defined by this class. The file contains + * a variable-length sequence of bytes that can be read and written and whose + * current size can be {@link #size() queried}. The size of the file increases + * when bytes are written beyond its current size; the size of the file decreases + * when it is {@link #truncate truncated}. + * + * <p> An asynchronous file channel does not have a <i>current position</i> + * within the file. Instead, the file position is specified to each read and + * write operation. + * + * <p> In addition to read and write operations, this class defines the + * following operations: </p> + * + * <ul> + * + * <li><p> Updates made to a file may be {@link #force <i>forced + * out</i>} to the underlying storage device, ensuring that data are not + * lost in the event of a system crash. </p></li> + * + * <li><p> A region of a file may be {@link FileLock <i>locked</i>} + * against access by other programs. </p></li> + * + * </ul> + * + * <p> The {@link #read read}, {@link #write write}, and {@link #lock lock} + * methods defined by this class are asynchronous and return a {@link Future} + * to represent the pending result of the operation. This may be used to check + * if the operation has completed, to wait for its completion, and to retrieve + * the result. These method may optionally specify a {@link CompletionHandler} + * that is invoked to consume the result of the I/O operation when it completes. + * + * <p> An {@code AsynchronousFileChannel} is associated with a thread pool to + * which tasks are submitted to handle I/O events and dispatch to completion + * handlers that consume the results of I/O operations on the channel. The + * completion handler for an I/O operation initiated on a channel is guaranteed + * to be invoked by one threads in the thread pool (This ensures that the + * completion handler is run by a thread with the expected <em>identity</em>). + * Where an I/O operation completes immediately, and the initiating thread is + * itself a thread in the thread pool, then the completion handler may be invoked + * directly by the initiating thread. When an {@code AsynchronousFileChannel} is + * created without specifying a thread pool then the channel is associated with + * a system-dependent and default thread pool that may be shared with other + * channels. The default thread pool is configured by the system properties + * defined by the {@link AsynchronousChannelGroup} class. + * + * <p> Channels of this type are safe for use by multiple concurrent threads. The + * {@link Channel#close close} method may be invoked at any time, as specified + * by the {@link Channel} interface. This causes all outstanding asynchronous + * operations on the channel to complete with the exception {@link + * AsynchronousCloseException}. Multiple read and write operations may be + * outstanding at the same time. When multiple read and write operations are + * outstanding then the ordering of the I/O operations, and the order that the + * completion handlers are invoked, is not specified; they are not, in particular, + * guaranteed to execute in the order that the operations were initiated. The + * {@link java.nio.ByteBuffer ByteBuffers} used when reading or writing are not + * safe for use by multiple concurrent I/O operations. Furthermore, after an I/O + * operation is initiated then care should be taken to ensure that the buffer is + * not accessed until after the operation has completed. + * + * <p> As with {@link FileChannel}, the view of a file provided by an instance of + * this class is guaranteed to be consistent with other views of the same file + * provided by other instances in the same program. The view provided by an + * instance of this class may or may not, however, be consistent with the views + * seen by other concurrently-running programs due to caching performed by the + * underlying operating system and delays induced by network-filesystem protocols. + * This is true regardless of the language in which these other programs are + * written, and whether they are running on the same machine or on some other + * machine. The exact nature of any such inconsistencies are system-dependent + * and are therefore unspecified. + * + * @since 1.7 + */ + +public abstract class AsynchronousFileChannel + implements AsynchronousChannel +{ + /** + * Initializes a new instance of this class. + */ + protected AsynchronousFileChannel() { + } + + /** + * Closes this channel. + * + * <p> If this channel is associated with its own thread pool then closing + * the channel causes the thread pool to shutdown after all actively + * executing completion handlers have completed. No attempt is made to stop + * or interrupt actively completion handlers. + * + * <p> This method otherwise behaves exactly as specified by the {@link + * AsynchronousChannel} interface. + * + * @throws IOException {@inheritDoc} + */ + @Override + public abstract void close() throws IOException; + + /** + * Opens or creates a file for reading and/or writing, returning an + * asynchronous file channel to access the file. + * + * <p> The {@code options} parameter determines how the file is opened. + * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE + * WRITE} options determines if the file should be opened for reading and/or + * writing. If neither option is contained in the array then an existing file + * is opened for reading. + * + * <p> In addition to {@code READ} and {@code WRITE}, the following options + * may be present: + * + * <table border=1 cellpadding=5 summary=""> + * <tr> <th>Option</th> <th>Description</th> </tr> + * <tr> + * <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td> + * <td> When opening an existing file, the file is first truncated to a + * size of 0 bytes. This option is ignored when the file is opened only + * for reading.</td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td> + * <td> If this option is present then a new file is created, failing if + * the file already exists. When creating a file the check for the + * existence of the file and the creation of the file if it does not exist + * is atomic with respect to other file system operations. This option is + * ignored when the file is opened only for reading. </td> + * </tr> + * <tr> + * <td > {@link StandardOpenOption#CREATE CREATE} </td> + * <td> If this option is present then an existing file is opened if it + * exists, otherwise a new file is created. When creating a file the check + * for the existence of the file and the creation of the file if it does + * not exist is atomic with respect to other file system operations. This + * option is ignored if the {@code CREATE_NEW} option is also present or + * the file is opened only for reading. </td> + * </tr> + * <tr> + * <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td> + * <td> When this option is present then the implementation makes a + * <em>best effort</em> attempt to delete the file when closed by the + * the {@link #close close} method. If the {@code close} method is not + * invoked then a <em>best effort</em> attempt is made to delete the file + * when the Java virtual machine terminates. </td> + * </tr> + * <tr> + * <td>{@link StandardOpenOption#SPARSE SPARSE} </td> + * <td> When creating a new file this option is a <em>hint</em> that the + * new file will be sparse. This option is ignored when not creating + * a new file. </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#SYNC SYNC} </td> + * <td> Requires that every update to the file's content or metadata be + * written synchronously to the underlying storage device. (see <a + * href="../file/package-summary.html#integrity"> Synchronized I/O file + * integrity</a>). </td> + * <tr> + * <tr> + * <td> {@link StandardOpenOption#DSYNC DSYNC} </td> + * <td> Requires that every update to the file's content be written + * synchronously to the underlying storage device. (see <a + * href="../file/package-summary.html#integrity"> Synchronized I/O file + * integrity</a>). </td> + * </tr> + * </table> + * + * <p> An implementation may also support additional options. + * + * <p> The {@code executor} parameter is the {@link ExecutorService} to + * which tasks are submitted to handle I/O events and dispatch completion + * results for operations initiated on resulting channel. + * The nature of these tasks is highly implementation specific and so care + * should be taken when configuring the {@code Executor}. Minimally it + * should support an unbounded work queue and should not run tasks on the + * caller thread of the {@link ExecutorService#execute execute} method. + * {@link #close Closing} the channel results in the orderly {@link + * ExecutorService#shutdown shutdown} of the executor service. Shutting down + * the executor service by other means results in unspecified behavior. + * + * <p> The {@code attrs} parameter is an optional array of file {@link + * FileAttribute file-attributes} to set atomically when creating the file. + * + * <p> The new channel is created by invoking the {@link + * FileSystemProvider#newFileChannel newFileChannel} method on the + * provider that created the {@code Path}. + * + * @param file + * The path of the file to open or create + * @param options + * Options specifying how the file is opened + * @param executor + * The thread pool or {@code null} to associate the channel with + * the default thread pool + * @param attrs + * An optional list of file attributes to set atomically when + * creating the file + * + * @return A new asynchronous file channel + * + * @throws IllegalArgumentException + * If the set contains an invalid combination of options + * @throws UnsupportedOperationException + * If the {@code file} is associated with a provider that does not + * support creating asynchronous file channels, or an unsupported + * open option is specified, or the array contains an attribute that + * cannot be set atomically when creating the file + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * If a security manager is installed and it denies an + * unspecified permission required by the implementation. + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String)} method is invoked to check + * read access if the file is opened for reading. The {@link + * SecurityManager#checkWrite(String)} method is invoked to check + * write access if the file is opened for writing + */ + public static AsynchronousFileChannel open(Path file, + Set<? extends OpenOption> options, + ExecutorService executor, + FileAttribute<?>... attrs) + throws IOException + { + FileSystemProvider provider = file.getFileSystem().provider(); + return provider.newAsynchronousFileChannel(file, options, executor, attrs); + } + + private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0]; + + /** + * Opens or creates a file for reading and/or writing, returning an + * asynchronous file channel to access the file. + * + * <p> An invocation of this method behaves in exactly the same way as the + * invocation + * <pre> + * ch.{@link #open(Path,Set,ExecutorService,FileAttribute[]) open}(file, opts, null, new FileAttribute<?>[0]); + * </pre> + * where {@code opts} is a {@code Set} containing the options specified to + * this method. + * + * <p> The resulting channel is associated with default thread pool to which + * tasks are submitted to handle I/O events and dispatch to completion + * handlers that consume the result of asynchronous operations performed on + * the resulting channel. + * + * @param file + * The path of the file to open or create + * @param options + * Options specifying how the file is opened + * + * @return A new asynchronous file channel + * + * @throws IllegalArgumentException + * If the set contains an invalid combination of options + * @throws UnsupportedOperationException + * If the {@code file} is associated with a provider that does not + * support creating file channels, or an unsupported open option is + * specified + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * If a security manager is installed and it denies an + * unspecified permission required by the implementation. + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String)} method is invoked to check + * read access if the file is opened for reading. The {@link + * SecurityManager#checkWrite(String)} method is invoked to check + * write access if the file is opened for writing + */ + public static AsynchronousFileChannel open(Path file, OpenOption... options) + throws IOException + { + Set<OpenOption> set = new HashSet<OpenOption>(options.length); + Collections.addAll(set, options); + return open(file, set, null, NO_ATTRIBUTES); + } + + /** + * Returns the current size of this channel's file. + * + * @return The current size of this channel's file, measured in bytes + * + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If some other I/O error occurs + */ + public abstract long size() throws IOException; + + /** + * Truncates this channel's file to the given size. + * + * <p> If the given size is less than the file's current size then the file + * is truncated, discarding any bytes beyond the new end of the file. If + * the given size is greater than or equal to the file's current size then + * the file is not modified. </p> + * + * @param size + * The new size, a non-negative byte count + * + * @return This file channel + * + * @throws NonWritableChannelException + * If this channel was not opened for writing + * + * @throws ClosedChannelException + * If this channel is closed + * + * @throws IllegalArgumentException + * If the new size is negative + * + * @throws IOException + * If some other I/O error occurs + */ + public abstract AsynchronousFileChannel truncate(long size) throws IOException; + + /** + * Forces any updates to this channel's file to be written to the storage + * device that contains it. + * + * <p> If this channel's file resides on a local storage device then when + * this method returns it is guaranteed that all changes made to the file + * since this channel was created, or since this method was last invoked, + * will have been written to that device. This is useful for ensuring that + * critical information is not lost in the event of a system crash. + * + * <p> If the file does not reside on a local device then no such guarantee + * is made. + * + * <p> The {@code metaData} parameter can be used to limit the number of + * I/O operations that this method is required to perform. Passing + * {@code false} for this parameter indicates that only updates to the + * file's content need be written to storage; passing {@code true} + * indicates that updates to both the file's content and metadata must be + * written, which generally requires at least one more I/O operation. + * Whether this parameter actually has any effect is dependent upon the + * underlying operating system and is therefore unspecified. + * + * <p> Invoking this method may cause an I/O operation to occur even if the + * channel was only opened for reading. Some operating systems, for + * example, maintain a last-access time as part of a file's metadata, and + * this time is updated whenever the file is read. Whether or not this is + * actually done is system-dependent and is therefore unspecified. + * + * <p> This method is only guaranteed to force changes that were made to + * this channel's file via the methods defined in this class. + * + * @param metaData + * If {@code true} then this method is required to force changes + * to both the file's content and metadata to be written to + * storage; otherwise, it need only force content changes to be + * written + * + * @throws ClosedChannelException + * If this channel is closed + * + * @throws IOException + * If some other I/O error occurs + */ + public abstract void force(boolean metaData) throws IOException; + + /** + * Acquires a lock on the given region of this channel's file. + * + * <p> This method initiates an operation to acquire a lock on the given region + * of this channel's file. The method returns a {@code Future} representing + * the pending result of the operation. Its {@link Future#get() get} + * method returns the {@link FileLock} on successful completion. + * + * <p> The region specified by the {@code position} and {@code size} + * parameters need not be contained within, or even overlap, the actual + * underlying file. Lock regions are fixed in size; if a locked region + * initially contains the end of the file and the file grows beyond the + * region then the new portion of the file will not be covered by the lock. + * If a file is expected to grow in size and a lock on the entire file is + * required then a region starting at zero, and no smaller than the + * expected maximum size of the file, should be locked. The two-argument + * {@link #lock(Object,CompletionHandler)} method simply locks a region + * of size {@link Long#MAX_VALUE}. If a lock that overlaps the requested + * region is already held by this Java virtual machine, or this method has + * been invoked to lock an overlapping region and that operation has not + * completed, then this method throws {@link OverlappingFileLockException}. + * + * <p> Some operating systems do not support a mechanism to acquire a file + * lock in an asynchronous manner. Consequently an implementation may + * acquire the file lock in a background thread or from a task executed by + * a thread in the associated thread pool. If there are many lock operations + * outstanding then it may consume threads in the Java virtual machine for + * indefinite periods. + * + * <p> Some operating systems do not support shared locks, in which case a + * request for a shared lock is automatically converted into a request for + * an exclusive lock. Whether the newly-acquired lock is shared or + * exclusive may be tested by invoking the resulting lock object's {@link + * FileLock#isShared() isShared} method. + * + * <p> File locks are held on behalf of the entire Java virtual machine. + * They are not suitable for controlling access to a file by multiple + * threads within the same virtual machine. + * + * @param position + * The position at which the locked region is to start; must be + * non-negative + * @param size + * The size of the locked region; must be non-negative, and the sum + * {@code position} + {@code size} must be non-negative + * @param shared + * {@code true} to request a shared lock, in which case this + * channel must be open for reading (and possibly writing); + * {@code false} to request an exclusive lock, in which case this + * channel must be open for writing (and possibly reading) + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return a {@code Future} object representing the pending result + * + * @throws OverlappingFileLockException + * If a lock that overlaps the requested region is already held by + * this Java virtual machine, or there is already a pending attempt + * to lock an overlapping region + * @throws IllegalArgumentException + * If the preconditions on the parameters do not hold + * @throws NonReadableChannelException + * If {@code shared} is true this channel but was not opened for reading + * @throws NonWritableChannelException + * If {@code shared} is false but this channel was not opened for writing + * @throws ShutdownChannelGroupException + * If a handler is specified, the channel is closed, and the channel + * was originally created with its own thread pool + */ + public abstract <A> Future<FileLock> lock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler<FileLock,? super A> handler); + + /** + * Acquires an exclusive lock on this channel's file. + * + * <p> This method initiates an operation to acquire an exclusive lock on this + * channel's file. The method returns a {@code Future} representing + * the pending result of the operation. Its {@link Future#get() get} + * method returns the {@link FileLock} on successful completion. + * + * <p> An invocation of this method of the form {@code ch.lock(att,handler)} + * behaves in exactly the same way as the invocation + * <pre> + * ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, att, handler) + * </pre> + * + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return a {@code Future} object representing the pending result + * + * @throws OverlappingFileLockException + * If a lock is already held by this Java virtual machine, or there + * is already a pending attempt to lock a region + * @throws NonWritableChannelException + * If this channel was not opened for writing + * @throws ShutdownChannelGroupException + * If a handler is specified, the channel is closed, and the channel + * was originally created with its own thread pool + */ + public final <A> Future<FileLock> lock(A attachment, + CompletionHandler<FileLock,? super A> handler) + { + return lock(0L, Long.MAX_VALUE, false, attachment, handler); + } + + /** + * Acquires an exclusive lock on this channel's file. + * + * <p> This method initiates an operation to acquire an exclusive lock on this + * channel's file. The method returns a {@code Future} representing the + * pending result of the operation. Its {@link Future#get() get} method + * returns the {@link FileLock} on successful completion. + * + * <p> An invocation of this method behaves in exactly the same way as the + * invocation + * <pre> + * ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, null, null) + * </pre> + * + * @return A {@code Future} object representing the pending result + * + * @throws OverlappingFileLockException + * If a lock is already held by this Java virtual machine, or there + * is already a pending attempt to lock a region + * @throws NonWritableChannelException + * If this channel was not opened for writing + */ + public final Future<FileLock> lock() { + return lock(0L, Long.MAX_VALUE, false, null, null); + } + + /** + * Attempts to acquire a lock on the given region of this channel's file. + * + * <p> This method does not block. An invocation always returns immediately, + * either having acquired a lock on the requested region or having failed to + * do so. If it fails to acquire a lock because an overlapping lock is held + * by another program then it returns {@code null}. If it fails to acquire + * a lock for any other reason then an appropriate exception is thrown. + * + * @param position + * The position at which the locked region is to start; must be + * non-negative + * + * @param size + * The size of the locked region; must be non-negative, and the sum + * {@code position} + {@code size} must be non-negative + * + * @param shared + * {@code true} to request a shared lock, + * {@code false} to request an exclusive lock + * + * @return A lock object representing the newly-acquired lock, + * or {@code null} if the lock could not be acquired + * because another program holds an overlapping lock + * + * @throws IllegalArgumentException + * If the preconditions on the parameters do not hold + * @throws ClosedChannelException + * If this channel is closed + * @throws OverlappingFileLockException + * If a lock that overlaps the requested region is already held by + * this Java virtual machine, or if another thread is already + * blocked in this method and is attempting to lock an overlapping + * region of the same file + * @throws NonReadableChannelException + * If {@code shared} is true this channel but was not opened for reading + * @throws NonWritableChannelException + * If {@code shared} is false but this channel was not opened for writing + * + * @throws IOException + * If some other I/O error occurs + * + * @see #lock(Object,CompletionHandler) + * @see #lock(long,long,boolean,Object,CompletionHandler) + * @see #tryLock() + */ + public abstract FileLock tryLock(long position, long size, boolean shared) + throws IOException; + + /** + * Attempts to acquire an exclusive lock on this channel's file. + * + * <p> An invocation of this method of the form {@code ch.tryLock()} + * behaves in exactly the same way as the invocation + * + * <pre> + * ch.{@link #tryLock(long,long,boolean) tryLock}(0L, Long.MAX_VALUE, false) </pre> + * + * @return A lock object representing the newly-acquired lock, + * or {@code null} if the lock could not be acquired + * because another program holds an overlapping lock + * + * @throws ClosedChannelException + * If this channel is closed + * @throws OverlappingFileLockException + * If a lock that overlaps the requested region is already held by + * this Java virtual machine, or if another thread is already + * blocked in this method and is attempting to lock an overlapping + * region + * @throws NonWritableChannelException + * If {@code shared} is false but this channel was not opened for writing + * + * @throws IOException + * If some other I/O error occurs + * + * @see #lock(Object,CompletionHandler) + * @see #lock(long,long,boolean,Object,CompletionHandler) + * @see #tryLock(long,long,boolean) + */ + public final FileLock tryLock() throws IOException { + return tryLock(0L, Long.MAX_VALUE, false); + } + + /** + * Reads a sequence of bytes from this channel into the given buffer, + * starting at the given file position. + * + * <p> This method initiates the reading of a sequence of bytes from this + * channel into the given buffer, starting at the given file position. This + * method returns a {@code Future} representing the pending result of the + * operation. The Future's {@link Future#get() get} method returns the + * number of bytes read or {@code -1} if the given position is greater than + * or equal to the file's size at the time that the read is attempted. + * + * <p> This method works in the same manner as the {@link + * AsynchronousByteChannel#read(ByteBuffer,Object,CompletionHandler)} + * method, except that bytes are read starting at the given file position. + * If the given file position is greater than the file's size at the time + * that the read is attempted then no bytes are read. + * + * @param dst + * The buffer into which bytes are to be transferred + * @param position + * The file position at which the transfer is to begin; + * must be non-negative + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return A {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the position is negative or the buffer is read-only + * @throws NonReadableChannelException + * If this channel was not opened for reading + * @throws ShutdownChannelGroupException + * If a handler is specified, the channel is closed, and the channel + * was originally created with its own thread pool + */ + public abstract <A> Future<Integer> read(ByteBuffer dst, + long position, + A attachment, + CompletionHandler<Integer,? super A> handler); + + /** + * Reads a sequence of bytes from this channel into the given buffer, + * starting at the given file position. + * + * <p> This method initiates the reading of a sequence of bytes from this + * channel into the given buffer, starting at the given file position. This + * method returns a {@code Future} representing the pending result of the + * operation. The Future's {@link Future#get() get} method returns the + * number of bytes read or {@code -1} if the given position is greater + * than or equal to the file's size at the time that the read is attempted. + * + * <p> This method is equivalent to invoking {@link + * #read(ByteBuffer,long,Object,CompletionHandler)} with the {@code attachment} + * and handler parameters set to {@code null}. + * + * @param dst + * The buffer into which bytes are to be transferred + * @param position + * The file position at which the transfer is to begin; + * must be non-negative + * + * @return A {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the position is negative or the buffer is read-only + * @throws NonReadableChannelException + * If this channel was not opened for reading + */ + public final Future<Integer> read(ByteBuffer dst, long position) { + return read(dst, position, null, null); + } + + /** + * Writes a sequence of bytes to this channel from the given buffer, starting + * at the given file position. + * + * <p> This method initiates the writing of a sequence of bytes to this channel + * from the given buffer, starting at the given file position. The method + * returns a {@code Future} representing the pending result of the write + * operation. The Future's {@link Future#get() get} method returns the + * number of bytes written. + * + * <p> This method works in the same manner as the {@link + * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)} + * method, except that bytes are written starting at the given file position. + * If the given position is greater than the file's size, at the time that + * the write is attempted, then the file will be grown to accommodate the new + * bytes; the values of any bytes between the previous end-of-file and the + * newly-written bytes are unspecified. + * + * @param src + * The buffer from which bytes are to be transferred + * @param position + * The file position at which the transfer is to begin; + * must be non-negative + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return A {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the position is negative + * @throws NonWritableChannelException + * If this channel was not opened for writing + * @throws ShutdownChannelGroupException + * If a handler is specified, the channel is closed, and the channel + * was originally created with its own thread pool + */ + public abstract <A> Future<Integer> write(ByteBuffer src, + long position, + A attachment, + CompletionHandler<Integer,? super A> handler); + + /** + * Writes a sequence of bytes to this channel from the given buffer, starting + * at the given file position. + * + * <p> This method initiates the writing of a sequence of bytes to this channel + * from the given buffer, starting at the given file position. The method + * returns a {@code Future} representing the pending result of the write + * operation. The Future's {@link Future#get() get} method returns the + * number of bytes written. + * + * <p> This method is equivalent to invoking {@link + * #write(ByteBuffer,long,Object,CompletionHandler)} with the {@code attachment} + * and handler parameters set to {@code null}. + * + * @param src + * The buffer from which bytes are to be transferred + * @param position + * The file position at which the transfer is to begin; + * must be non-negative + * + * @return A {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the position is negative + * @throws NonWritableChannelException + * If this channel was not opened for writing + */ + public final Future<Integer> write(ByteBuffer src, long position) { + return write(src, position, null, null); + } +} diff --git a/jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java b/jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java new file mode 100644 index 00000000000..99c56fa59c0 --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java @@ -0,0 +1,303 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.nio.channels.spi.*; +import java.net.SocketOption; +import java.net.SocketAddress; +import java.util.concurrent.Future; +import java.io.IOException; + +/** + * An asynchronous channel for stream-oriented listening sockets. + * + * <p> An asynchronous server-socket channel is created by invoking the + * {@link #open open} method of this class. + * A newly-created asynchronous server-socket channel is open but not yet bound. + * It can be bound to a local address and configured to listen for connections + * by invoking the {@link #bind(SocketAddress,int) bind} method. Once bound, + * the {@link #accept(Object,CompletionHandler) accept} method + * is used to initiate the accepting of connections to the channel's socket. + * An attempt to invoke the <tt>accept</tt> method on an unbound channel will + * cause a {@link NotYetBoundException} to be thrown. + * + * <p> Channels of this type are safe for use by multiple concurrent threads + * though at most one accept operation can be outstanding at any time. + * If a thread initiates an accept operation before a previous accept operation + * has completed then an {@link AcceptPendingException} will be thrown. + * + * <p> Socket options are configured using the {@link #setOption(SocketOption,Object) + * setOption} method. Channels of this type support the following options: + * <blockquote> + * <table border> + * <tr> + * <th>Option Name</th> + * <th>Description</th> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td> + * <td> The size of the socket receive buffer </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td> + * <td> Re-use address </td> + * </tr> + * </table> + * </blockquote> + * Additional (implementation specific) options may also be supported. + * + * <p> <b>Usage Example:</b> + * <pre> + * final AsynchronousServerSocketChannel listener = + * AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(5000)); + * + * listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() { + * public void completed(AsynchronousSocketChannel ch, Void att) { + * // accept the next connection + * listener.accept(null, this); + * + * // handle this connection + * handle(ch); + * } + * public void failed(Throwable exc, Void att) { + * ... + * } + * public void cancelled(Void att) { + * ... + * } + * }); + * </pre> + * + * @since 1.7 + */ + +public abstract class AsynchronousServerSocketChannel + implements AsynchronousChannel, NetworkChannel +{ + private final AsynchronousChannelProvider provider; + + /** + * Initializes a new instance of this class. + */ + protected AsynchronousServerSocketChannel(AsynchronousChannelProvider provider) { + this.provider = provider; + } + + /** + * Returns the provider that created this channel. + */ + public final AsynchronousChannelProvider provider() { + return provider; + } + + /** + * Opens an asynchronous server-socket channel. + * + * <p> The new channel is created by invoking the {@link + * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousServerSocketChannel + * openAsynchronousServerSocketChannel} method on the {@link + * java.nio.channels.spi.AsynchronousChannelProvider} object that created + * the given group. If the group parameter is <tt>null</tt> then the + * resulting channel is created by the system-wide default provider, and + * bound to the <em>default group</em>. + * + * @param group + * The group to which the newly constructed channel should be bound, + * or <tt>null</tt> for the default group + * + * @return A new asynchronous server socket channel + * + * @throws ShutdownChannelGroupException + * If the channel group is shutdown + * @throws IOException + * If an I/O error occurs + */ + public static AsynchronousServerSocketChannel open(AsynchronousChannelGroup group) + throws IOException + { + AsynchronousChannelProvider provider = (group == null) ? + AsynchronousChannelProvider.provider() : group.provider(); + return provider.openAsynchronousServerSocketChannel(group); + } + + /** + * Opens an asynchronous server-socket channel. + * + * <p> This method returns an asynchronous server socket channel that is + * bound to the <em>default group</em>. This method is equivalent to evaluating + * the expression: + * <blockquote><pre> + * open((AsynchronousChannelGroup)null); + * </pre></blockquote> + * + * @return A new asynchronous server socket channel + * + * @throws IOException + * If an I/O error occurs + */ + public static AsynchronousServerSocketChannel open() + throws IOException + { + return open(null); + } + + /** + * Binds the channel's socket to a local address and configures the socket to + * listen for connections. + * + * <p> An invocation of this method is equivalent to the following: + * <blockquote><pre> + * bind(local, 0); + * </pre></blockquote> + * + * @param local + * The local address to bind the socket, or <tt>null</tt> to bind + * to an automatically assigned socket address + * + * @return This channel + * + * @throws AlreadyBoundException {@inheritDoc} + * @throws UnsupportedAddressTypeException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + public final AsynchronousServerSocketChannel bind(SocketAddress local) + throws IOException + { + return bind(local, 0); + } + + /** + * Binds the channel's socket to a local address and configures the socket to + * listen for connections. + * + * <p> This method is used to establish an association between the socket and + * a local address. Once an association is established then the socket remains + * bound until the associated channel is closed. + * + * <p> The {@code backlog} parameter is the maximum number of pending + * connections on the socket. Its exact semantics are implementation specific. + * In particular, an implementation may impose a maximum length or may choose + * to ignore the parameter altogther. If the {@code backlog} parameter has + * the value {@code 0}, or a negative value, then an implementation specific + * default is used. + * + * @param local + * The local address to bind the socket, or {@code null} to bind + * to an automatically assigned socket address + * @param backlog + * The maximum number of pending connections + * + * @return This channel + * + * @throws AlreadyBoundException + * If the socket is already bound + * @throws UnsupportedAddressTypeException + * If the type of the given address is not supported + * @throws SecurityException + * If a security manager has been installed and its {@link + * SecurityManager#checkListen checkListen} method denies the operation + * @throws ClosedChannelException + * If the channel is closed + * @throws IOException + * If some other I/O error occurs + */ + public abstract AsynchronousServerSocketChannel bind(SocketAddress local, int backlog) + throws IOException; + + /** + * @throws IllegalArgumentException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + public abstract <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name, T value) + throws IOException; + + /** + * Accepts a connection. + * + * <p> This method initiates accepting a connection made to this channel's + * socket, returning a {@link Future} representing the pending result + * of the operation. The {@code Future}'s {@link Future#get() get} + * method will return the {@link AsynchronousSocketChannel} for the new + * connection on successful completion. + * + * <p> When a new connection is accepted then the resulting {@code + * AsynchronousSocketChannel} will be bound to the same {@link + * AsynchronousChannelGroup} as this channel. If the group is {@link + * AsynchronousChannelGroup#isShutdown shutdown} and a connection is accepted, + * then the connection is closed, and the operation completes with an {@code + * IOException} and cause {@link ShutdownChannelGroupException}. + * + * <p> To allow for concurrent handling of new connections, the completion + * handler is not invoked directly by the initiating thread when a new + * connection is accepted immediately (see <a + * href="AsynchronousChannelGroup.html#threading">Threading<a>). + * + * <p> If a security manager has been installed then it verifies that the + * address and port number of the connection's remote endpoint are permitted + * by the security manager's {@link SecurityManager#checkAccept checkAccept} + * method. The permission check is performed with privileges that are restricted + * by the calling context of this method. If the permission check fails then + * the connection is closed and the operation completes with a {@link + * SecurityException}. + * + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return an <tt>Future</tt> object representing the pending result + * + * @throws AcceptPendingException + * If an accept operation is already in progress on this channel + * @throws NotYetBoundException + * If this channel's socket has not yet been bound + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public abstract <A> Future<AsynchronousSocketChannel> + accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler); + + /** + * Accepts a connection. + * + * <p> This method is equivalent to invoking {@link + * #accept(Object,CompletionHandler)} with the {@code attachment} + * and {@code handler} parameters set to {@code null}. + * + * @return an <tt>Future</tt> object representing the pending result + * + * @throws AcceptPendingException + * If an accept operation is already in progress on this channel + * @throws NotYetBoundException + * If this channel's socket has not yet been bound + */ + public final Future<AsynchronousSocketChannel> accept() { + return accept(null, null); + } +} diff --git a/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java b/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java new file mode 100644 index 00000000000..b6a5da8105d --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java @@ -0,0 +1,670 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.nio.channels.spi.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.Future; +import java.io.IOException; +import java.net.SocketOption; +import java.net.SocketAddress; +import java.nio.ByteBuffer; + +/** + * An asynchronous channel for stream-oriented connecting sockets. + * + * <p> Asynchronous socket channels are created in one of two ways. A newly-created + * {@code AsynchronousSocketChannel} is created by invoking one of the {@link + * #open open} methods defined by this class. A newly-created channel is open but + * not yet connected. A connected {@code AsynchronousSocketChannel} is created + * when a connection is made to the socket of an {@link AsynchronousServerSocketChannel}. + * It is not possible to create an asynchronous socket channel for an arbitrary, + * pre-existing {@link java.net.Socket socket}. + * + * <p> A newly-created channel is connected by invoking its {@link #connect connect} + * method; once connected, a channel remains connected until it is closed. Whether + * or not a socket channel is connected may be determined by invoking its {@link + * #getRemoteAddress getRemoteAddress} method. An attempt to invoke an I/O + * operation upon an unconnected channel will cause a {@link NotYetConnectedException} + * to be thrown. + * + * <p> Channels of this type are safe for use by multiple concurrent threads. + * They support concurrent reading and writing, though at most one read operation + * and one write operation can be outstanding at any time. + * If a thread initiates a read operation before a previous read operation has + * completed then a {@link ReadPendingException} will be thrown. Similarly, an + * attempt to initiate a write operation before a previous write has completed + * will throw a {@link WritePendingException}. + * + * <p> Socket options are configured using the {@link #setOption(SocketOption,Object) + * setOption} method. Asynchronous socket channels support the following options: + * <blockquote> + * <table border> + * <tr> + * <th>Option Name</th> + * <th>Description</th> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} </td> + * <td> The size of the socket send buffer </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td> + * <td> The size of the socket receive buffer </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_KEEPALIVE SO_KEEPALIVE} </td> + * <td> Keep connection alive </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td> + * <td> Re-use address </td> + * </tr> + * <tr> + * <td> {@link java.net.StandardSocketOption#TCP_NODELAY TCP_NODELAY} </td> + * <td> Disable the Nagle algorithm </td> + * </tr> + * </table> + * </blockquote> + * Additional (implementation specific) options may also be supported. + * + * <h4>Timeouts</h4> + * + * <p> The {@link #read(ByteBuffer,long,TimeUnit,Object,CompletionHandler) read} + * and {@link #write(ByteBuffer,long,TimeUnit,Object,CompletionHandler) write} + * methods defined by this class allow a timeout to be specified when initiating + * a read or write operation. If the timeout elapses before an operation completes + * then the operation completes with the exception {@link + * InterruptedByTimeoutException}. A timeout may leave the channel, or the + * underlying connection, in an inconsistent state. Where the implementation + * cannot guarantee that bytes have not been read from the channel then it puts + * the channel into an implementation specific <em>error state</em>. A subsequent + * attempt to initiate a {@code read} operation causes an unspecified runtime + * exception to be thrown. Similarly if a {@code write} operation times out and + * the implementation cannot guarantee bytes have not been written to the + * channel then further attempts to {@code write} to the channel cause an + * unspecified runtime exception to be thrown. When a timeout elapses then the + * state of the {@link ByteBuffer}, or the sequence of buffers, for the I/O + * operation is not defined. Buffers should be discarded or at least care must + * be taken to ensure that the buffers are not accessed while the channel remains + * open. + * + * @since 1.7 + */ + +public abstract class AsynchronousSocketChannel + implements AsynchronousByteChannel, NetworkChannel +{ + private final AsynchronousChannelProvider provider; + + /** + * Initializes a new instance of this class. + */ + protected AsynchronousSocketChannel(AsynchronousChannelProvider provider) { + this.provider = provider; + } + + /** + * Returns the provider that created this channel. + */ + public final AsynchronousChannelProvider provider() { + return provider; + } + + /** + * Opens an asynchronous socket channel. + * + * <p> The new channel is created by invoking the {@link + * AsynchronousChannelProvider#openAsynchronousSocketChannel + * openAsynchronousSocketChannel} method on the {@link + * AsynchronousChannelProvider} that created the group. If the group parameter + * is {@code null} then the resulting channel is created by the system-wide + * default provider, and bound to the <em>default group</em>. + * + * @param group + * The group to which the newly constructed channel should be bound, + * or {@code null} for the default group + * + * @return A new asynchronous socket channel + * + * @throws ShutdownChannelGroupException + * If the channel group is shutdown + * @throws IOException + * If an I/O error occurs + */ + public static AsynchronousSocketChannel open(AsynchronousChannelGroup group) + throws IOException + { + AsynchronousChannelProvider provider = (group == null) ? + AsynchronousChannelProvider.provider() : group.provider(); + return provider.openAsynchronousSocketChannel(group); + } + + /** + * Opens an asynchronous socket channel. + * + * <p> This method returns an asynchronous socket channel that is bound to + * the <em>default group</em>.This method is equivalent to evaluating the + * expression: + * <blockquote><pre> + * open((AsynchronousChannelGroup)null); + * </pre></blockquote> + * + * @return A new asynchronous socket channel + * + * @throws IOException + * If an I/O error occurs + */ + public static AsynchronousSocketChannel open() + throws IOException + { + return open(null); + } + + + // -- socket options and related -- + + /** + * @throws ConnectionPendingException + * If a connection operation is already in progress on this channel + * @throws AlreadyBoundException {@inheritDoc} + * @throws UnsupportedAddressTypeException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + @Override + public abstract AsynchronousSocketChannel bind(SocketAddress local) + throws IOException; + + /** + * @throws IllegalArgumentException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + @Override + public abstract <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value) + throws IOException; + + /** + * Shutdown the connection for reading without closing the channel. + * + * <p> Once shutdown for reading then further reads on the channel will + * return {@code -1}, the end-of-stream indication. If the input side of the + * connection is already shutdown then invoking this method has no effect. + * The effect on an outstanding read operation is system dependent and + * therefore not specified. The effect, if any, when there is data in the + * socket receive buffer that has not been read, or data arrives subsequently, + * is also system dependent. + * + * @return The channel + * + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If some other I/O error occurs + */ + public abstract AsynchronousSocketChannel shutdownInput() throws IOException; + + /** + * Shutdown the connection for writing without closing the channel. + * + * <p> Once shutdown for writing then further attempts to write to the + * channel will throw {@link ClosedChannelException}. If the output side of + * the connection is already shutdown then invoking this method has no + * effect. The effect on an outstanding write operation is system dependent + * and therefore not specified. + * + * @return The channel + * + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If some other I/O error occurs + */ + public abstract AsynchronousSocketChannel shutdownOutput() throws IOException; + + // -- state -- + + /** + * Returns the remote address to which this channel's socket is connected. + * + * <p> Where the channel is bound and connected to an Internet Protocol + * socket address then the return value from this method is of type {@link + * java.net.InetSocketAddress}. + * + * @return The remote address; {@code null} if the channel's socket is not + * connected + * + * @throws ClosedChannelException + * If the channel is closed + * @throws IOException + * If an I/O error occurs + */ + public abstract SocketAddress getRemoteAddress() throws IOException; + + // -- asynchronous operations -- + + /** + * Connects this channel. + * + * <p> This method initiates an operation to connect this channel, returning + * a {@code Future} representing the pending result of the operation. If + * the connection is successfully established then the {@code Future}'s + * {@link Future#get() get} method will return {@code null}. If the + * connection cannot be established then the channel is closed. In that case, + * invoking the {@code get} method throws {@link + * java.util.concurrent.ExecutionException} with an {@code IOException} as + * the cause. + * + * <p> This method performs exactly the same security checks as the {@link + * java.net.Socket} class. That is, if a security manager has been + * installed then this method verifies that its {@link + * java.lang.SecurityManager#checkConnect checkConnect} method permits + * connecting to the address and port number of the given remote endpoint. + * + * @param remote + * The remote address to which this channel is to be connected + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return A {@code Future} object representing the pending result + * + * @throws UnresolvedAddressException + * If the given remote address is not fully resolved + * @throws UnsupportedAddressTypeException + * If the type of the given remote address is not supported + * @throws AlreadyConnectedException + * If this channel is already connected + * @throws ConnectionPendingException + * If a connection operation is already in progress on this channel + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + * @throws SecurityException + * If a security manager has been installed + * and it does not permit access to the given remote endpoint + * + * @see #getRemoteAddress + */ + public abstract <A> Future<Void> connect(SocketAddress remote, + A attachment, + CompletionHandler<Void,? super A> handler); + + /** + * Connects this channel. + * + * <p> This method is equivalent to invoking {@link + * #connect(SocketAddress,Object,CompletionHandler)} with the {@code attachment} + * and handler parameters set to {@code null}. + * + * @param remote + * The remote address to which this channel is to be connected + * + * @return A {@code Future} object representing the pending result + * + * @throws UnresolvedAddressException + * If the given remote address is not fully resolved + * @throws UnsupportedAddressTypeException + * If the type of the given remote address is not supported + * @throws AlreadyConnectedException + * If this channel is already connected + * @throws ConnectionPendingException + * If a connection operation is already in progress on this channel + * @throws SecurityException + * If a security manager has been installed + * and it does not permit access to the given remote endpoint + */ + public final Future<Void> connect(SocketAddress remote) { + return connect(remote, null, null); + } + + /** + * Reads a sequence of bytes from this channel into the given buffer. + * + * <p> This method initiates the reading of a sequence of bytes from this + * channel into the given buffer, returning a {@code Future} representing + * the pending result of the operation. The {@code Future}'s {@link + * Future#get() get} method returns the number of bytes read or {@code -1} + * if all bytes have been read and channel has reached end-of-stream. + * + * <p> If a timeout is specified and the timeout elapses before the operation + * completes then the operation completes with the exception {@link + * InterruptedByTimeoutException}. Where a timeout occurs, and the + * implementation cannot guarantee that bytes have not been read, or will not + * be read from the channel into the given buffer, then further attempts to + * read from the channel will cause an unspecific runtime exception to be + * thrown. + * + * <p> Otherwise this method works in the same manner as the {@link + * AsynchronousByteChannel#read(ByteBuffer,Object,CompletionHandler)} + * method. + * + * @param dst + * The buffer into which bytes are to be transferred + * @param timeout + * The timeout, or {@code 0L} for no timeout + * @param unit + * The time unit of the {@code timeout} argument + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return A {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the {@code timeout} parameter is negative or the buffer is + * read-only + * @throws ReadPendingException + * If a read operation is already in progress on this channel + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public abstract <A> Future<Integer> read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Integer,? super A> handler); + + /** + * @throws IllegalArgumentException {@inheritDoc} + * @throws ReadPendingException {@inheritDoc} + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + @Override + public final <A> Future<Integer> read(ByteBuffer dst, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + } + + /** + * @throws IllegalArgumentException {@inheritDoc} + * @throws ReadPendingException {@inheritDoc} + * @throws NotYetConnectedException + * If this channel is not yet connected + */ + @Override + public final Future<Integer> read(ByteBuffer dst) { + return read(dst, 0L, TimeUnit.MILLISECONDS, null, null); + } + + /** + * Reads a sequence of bytes from this channel into a subsequence of the + * given buffers. This operation, sometimes called a <em>scattering read</em>, + * is often useful when implementing network protocols that group data into + * segments consisting of one or more fixed-length headers followed by a + * variable-length body. + * + * <p> This method initiates a read of up to <i>r</i> bytes from this channel, + * where <i>r</i> is the total number of bytes remaining in the specified + * subsequence of the given buffer array, that is, + * + * <blockquote><pre> + * dsts[offset].remaining() + * + dsts[offset+1].remaining() + * + ... + dsts[offset+length-1].remaining()</pre></blockquote> + * + * at the moment that the read is attempted. + * + * <p> Suppose that a byte sequence of length <i>n</i> is read, where + * <tt>0</tt> <tt><</tt> <i>n</i> <tt><=</tt> <i>r</i>. + * Up to the first <tt>dsts[offset].remaining()</tt> bytes of this sequence + * are transferred into buffer <tt>dsts[offset]</tt>, up to the next + * <tt>dsts[offset+1].remaining()</tt> bytes are transferred into buffer + * <tt>dsts[offset+1]</tt>, and so forth, until the entire byte sequence + * is transferred into the given buffers. As many bytes as possible are + * transferred into each buffer, hence the final position of each updated + * buffer, except the last updated buffer, is guaranteed to be equal to + * that buffer's limit. The underlying operating system may impose a limit + * on the number of buffers that may be used in an I/O operation. Where the + * number of buffers (with bytes remaining), exceeds this limit, then the + * I/O operation is performed with the maximum number of buffers allowed by + * the operating system. + * + * <p> The return value from this method is a {@code Future} representing + * the pending result of the operation. The {@code Future}'s {@link + * Future#get() get} method returns the number of bytes read or {@code -1L} + * if all bytes have been read and the channel has reached end-of-stream. + * + * <p> If a timeout is specified and the timeout elapses before the operation + * completes then it completes with the exception {@link + * InterruptedByTimeoutException}. Where a timeout occurs, and the + * implementation cannot guarantee that bytes have not been read, or will not + * be read from the channel into the given buffers, then further attempts to + * read from the channel will cause an unspecific runtime exception to be + * thrown. + * + * @param dsts + * The buffers into which bytes are to be transferred + * @param offset + * The offset within the buffer array of the first buffer into which + * bytes are to be transferred; must be non-negative and no larger than + * {@code dsts.length} + * @param length + * The maximum number of buffers to be accessed; must be non-negative + * and no larger than {@code dsts.length - offset} + * @param timeout + * The timeout, or {@code 0L} for no timeout + * @param unit + * The time unit of the {@code timeout} argument + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return A {@code Future} object representing the pending result + * + * @throws IndexOutOfBoundsException + * If the pre-conditions for the {@code offset} and {@code length} + * parameter aren't met + * @throws IllegalArgumentException + * If the {@code timeout} parameter is negative, or a buffer is + * read-only + * @throws ReadPendingException + * If a read operation is already in progress on this channel + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public abstract <A> Future<Long> read(ByteBuffer[] dsts, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Long,? super A> handler); + + /** + * Writes a sequence of bytes to this channel from the given buffer. + * + * <p> This method initiates the writing of a sequence of bytes to this channel + * from the given buffer, returning a {@code Future} representing the + * pending result of the operation. The {@code Future}'s {@link Future#get() + * get} method will return the number of bytes written. + * + * <p> If a timeout is specified and the timeout elapses before the operation + * completes then it completes with the exception {@link + * InterruptedByTimeoutException}. Where a timeout occurs, and the + * implementation cannot guarantee that bytes have not been written, or will + * not be written to the channel from the given buffer, then further attempts + * to write to the channel will cause an unspecific runtime exception to be + * thrown. + * + * <p> Otherwise this method works in the same manner as the {@link + * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)} + * method. + * + * @param src + * The buffer from which bytes are to be retrieved + * @param timeout + * The timeout, or {@code 0L} for no timeout + * @param unit + * The time unit of the {@code timeout} argument + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return A {@code Future} object representing the pending result + * + * @throws IllegalArgumentException + * If the {@code timeout} parameter is negative + * @throws WritePendingException + * If a write operation is already in progress on this channel + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public abstract <A> Future<Integer> write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Integer,? super A> handler); + + /** + * @throws WritePendingException {@inheritDoc} + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + @Override + public final <A> Future<Integer> write(ByteBuffer src, + A attachment, + CompletionHandler<Integer,? super A> handler) + + { + return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler); + } + + /** + * @throws WritePendingException {@inheritDoc} + * @throws NotYetConnectedException + * If this channel is not yet connected + */ + @Override + public final Future<Integer> write(ByteBuffer src) { + return write(src, 0L, TimeUnit.MILLISECONDS, null, null); + } + + /** + * Writes a sequence of bytes to this channel from a subsequence of the given + * buffers. This operation, sometimes called a <em>gathering write</em>, is + * often useful when implementing network protocols that group data into + * segments consisting of one or more fixed-length headers followed by a + * variable-length body. + * + * <p> This method initiates a write of up to <i>r</i> bytes to this channel, + * where <i>r</i> is the total number of bytes remaining in the specified + * subsequence of the given buffer array, that is, + * + * <blockquote><pre> + * srcs[offset].remaining() + * + srcs[offset+1].remaining() + * + ... + srcs[offset+length-1].remaining()</pre></blockquote> + * + * at the moment that the write is attempted. + * + * <p> Suppose that a byte sequence of length <i>n</i> is written, where + * <tt>0</tt> <tt><</tt> <i>n</i> <tt><=</tt> <i>r</i>. + * Up to the first <tt>srcs[offset].remaining()</tt> bytes of this sequence + * are written from buffer <tt>srcs[offset]</tt>, up to the next + * <tt>srcs[offset+1].remaining()</tt> bytes are written from buffer + * <tt>srcs[offset+1]</tt>, and so forth, until the entire byte sequence is + * written. As many bytes as possible are written from each buffer, hence + * the final position of each updated buffer, except the last updated + * buffer, is guaranteed to be equal to that buffer's limit. The underlying + * operating system may impose a limit on the number of buffers that may be + * used in an I/O operation. Where the number of buffers (with bytes + * remaining), exceeds this limit, then the I/O operation is performed with + * the maximum number of buffers allowed by the operating system. + * + * <p> The return value from this method is a {@code Future} representing + * the pending result of the operation. The {@code Future}'s {@link + * Future#get() get} method will return the number of bytes written. + * + * <p> If a timeout is specified and the timeout elapses before the operation + * completes then it completes with the exception {@link + * InterruptedByTimeoutException}. Where a timeout occurs, and the + * implementation cannot guarantee that bytes have not been written, or will + * not be written to the channel from the given buffers, then further attempts + * to write to the channel will cause an unspecific runtime exception to be + * thrown. + * + * @param srcs + * The buffers from which bytes are to be retrieved + * @param offset + * The offset within the buffer array of the first buffer from which + * bytes are to be retrieved; must be non-negative and no larger + * than {@code srcs.length} + * @param length + * The maximum number of buffers to be accessed; must be non-negative + * and no larger than {@code srcs.length - offset} + * @param timeout + * The timeout, or {@code 0L} for no timeout + * @param unit + * The time unit of the {@code timeout} argument + * @param attachment + * The object to attach to the I/O operation; can be {@code null} + * @param handler + * The handler for consuming the result; can be {@code null} + * + * @return A {@code Future} object representing the pending result + * + * @throws IndexOutOfBoundsException + * If the pre-conditions for the {@code offset} and {@code length} + * parameter aren't met + * @throws IllegalArgumentException + * If the {@code timeout} parameter is negative + * @throws WritePendingException + * If a write operation is already in progress on this channel + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ShutdownChannelGroupException + * If a handler is specified, and the channel group is shutdown + */ + public abstract <A> Future<Long> write(ByteBuffer[] srcs, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Long,? super A> handler); +} diff --git a/jdk/src/share/classes/java/nio/channels/Channels.java b/jdk/src/share/classes/java/nio/channels/Channels.java index cab96048629..4fdcef8abb0 100644 --- a/jdk/src/share/classes/java/nio/channels/Channels.java +++ b/jdk/src/share/classes/java/nio/channels/Channels.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,15 +33,12 @@ import java.io.Reader; import java.io.Writer; import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; import java.nio.charset.UnsupportedCharsetException; import java.nio.channels.spi.AbstractInterruptibleChannel; +import java.util.concurrent.ExecutionException; import sun.nio.ch.ChannelInputStream; import sun.nio.cs.StreamDecoder; import sun.nio.cs.StreamEncoder; @@ -184,6 +181,155 @@ public final class Channels { }; } + /** + * {@note new} + * Constructs a stream that reads bytes from the given channel. + * + * <p> The stream will not be buffered, and it will not support the {@link + * InputStream#mark mark} or {@link InputStream#reset reset} methods. The + * stream will be safe for access by multiple concurrent threads. Closing + * the stream will in turn cause the channel to be closed. </p> + * + * @param ch + * The channel from which bytes will be read + * + * @return A new input stream + * + * @since 1.7 + */ + public static InputStream newInputStream(final AsynchronousByteChannel ch) { + checkNotNull(ch, "ch"); + return new InputStream() { + + private ByteBuffer bb = null; + private byte[] bs = null; // Invoker's previous array + private byte[] b1 = null; + + @Override + public synchronized int read() throws IOException { + if (b1 == null) + b1 = new byte[1]; + int n = this.read(b1); + if (n == 1) + return b1[0] & 0xff; + return -1; + } + + @Override + public synchronized int read(byte[] bs, int off, int len) + throws IOException + { + if ((off < 0) || (off > bs.length) || (len < 0) || + ((off + len) > bs.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) + return 0; + + ByteBuffer bb = ((this.bs == bs) + ? this.bb + : ByteBuffer.wrap(bs)); + bb.position(off); + bb.limit(Math.min(off + len, bb.capacity())); + this.bb = bb; + this.bs = bs; + + boolean interrupted = false; + try { + for (;;) { + try { + return ch.read(bb).get(); + } catch (ExecutionException ee) { + throw new IOException(ee.getCause()); + } catch (InterruptedException ie) { + interrupted = true; + } + } + } finally { + if (interrupted) + Thread.currentThread().interrupt(); + } + } + + @Override + public void close() throws IOException { + ch.close(); + } + }; + } + + /** + * {@note new} + * Constructs a stream that writes bytes to the given channel. + * + * <p> The stream will not be buffered. The stream will be safe for access + * by multiple concurrent threads. Closing the stream will in turn cause + * the channel to be closed. </p> + * + * @param ch + * The channel to which bytes will be written + * + * @return A new output stream + * + * @since 1.7 + */ + public static OutputStream newOutputStream(final AsynchronousByteChannel ch) { + checkNotNull(ch, "ch"); + return new OutputStream() { + + private ByteBuffer bb = null; + private byte[] bs = null; // Invoker's previous array + private byte[] b1 = null; + + @Override + public synchronized void write(int b) throws IOException { + if (b1 == null) + b1 = new byte[1]; + b1[0] = (byte)b; + this.write(b1); + } + + @Override + public synchronized void write(byte[] bs, int off, int len) + throws IOException + { + if ((off < 0) || (off > bs.length) || (len < 0) || + ((off + len) > bs.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + ByteBuffer bb = ((this.bs == bs) + ? this.bb + : ByteBuffer.wrap(bs)); + bb.limit(Math.min(off + len, bb.capacity())); + bb.position(off); + this.bb = bb; + this.bs = bs; + + boolean interrupted = false; + try { + while (bb.remaining() > 0) { + try { + ch.write(bb).get(); + } catch (ExecutionException ee) { + throw new IOException(ee.getCause()); + } catch (InterruptedException ie) { + interrupted = true; + } + } + } finally { + if (interrupted) + Thread.currentThread().interrupt(); + } + } + + @Override + public void close() throws IOException { + ch.close(); + } + }; + } + // -- Channels from streams -- @@ -468,5 +614,4 @@ public final class Channels { checkNotNull(csName, "csName"); return newWriter(ch, Charset.forName(csName).newEncoder(), -1); } - } diff --git a/jdk/src/share/classes/java/nio/channels/CompletionHandler.java b/jdk/src/share/classes/java/nio/channels/CompletionHandler.java new file mode 100644 index 00000000000..c4d4add8ff9 --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/CompletionHandler.java @@ -0,0 +1,77 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +/** + * A handler for consuming the result of an asynchronous I/O operation. + * + * <p> The asynchronous channels defined in this package allow a completion + * handler to be specified to consume the result of an asynchronous operation. + * The {@link #completed completed} method is invoked when the I/O operation + * completes successfully. The {@link #failed failed} method is invoked if the + * I/O operations fails. The {@link #cancelled cancelled} method is invoked when + * the I/O operation is cancelled by invoking the {@link + * java.util.concurrent.Future#cancel cancel} method. The implementations of + * these methods should complete in a timely manner so as to avoid keeping the + * invoking thread from dispatching to other completion handlers. + * + * @param <V> The result type of the I/O operation + * @param <A> The type of the object attached to the I/O operation + * + * @since 1.7 + */ + +public interface CompletionHandler<V,A> { + + /** + * Invoked when an operation has completed. + * + * @param result + * The result of the I/O operation. + * @param attachment + * The object attached to the I/O operation when it was initiated. + */ + void completed(V result, A attachment); + + /** + * Invoked when an operation fails. + * + * @param exc + * The exception to indicate why the I/O operation failed + * @param attachment + * The object attached to the I/O operation when it was initiated. + */ + void failed(Throwable exc, A attachment); + + /** + * Invoked when an operation is cancelled by invoking the {@link + * java.util.concurrent.Future#cancel cancel} method. + * + * @param attachment + * The object attached to the I/O operation when it was initiated. + */ + void cancelled(A attachment); +} diff --git a/jdk/src/share/classes/java/nio/channels/DatagramChannel.java b/jdk/src/share/classes/java/nio/channels/DatagramChannel.java index b8697fa1dc6..cbf402f5933 100644 --- a/jdk/src/share/classes/java/nio/channels/DatagramChannel.java +++ b/jdk/src/share/classes/java/nio/channels/DatagramChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,8 @@ import java.net.DatagramSocket; import java.net.SocketOption; import java.net.SocketAddress; import java.nio.ByteBuffer; -import java.nio.channels.spi.*; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.SelectorProvider; /** * A selectable channel for datagram-oriented sockets. @@ -53,7 +54,8 @@ import java.nio.channels.spi.*; * be determined by invoking its {@link #isConnected isConnected} method. * * <p> Socket options are configured using the {@link #setOption(SocketOption,Object) - * setOption} method. Datagram channels support the following options: + * setOption} method. A datagram channel to an Internet Protocol socket supports + * the following options: * <blockquote> * <table border> * <tr> @@ -211,6 +213,7 @@ public abstract class DatagramChannel throws IOException; /** + * @throws UnsupportedOperationException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws ClosedChannelException {@inheritDoc} * @throws IOException {@inheritDoc} @@ -220,7 +223,6 @@ public abstract class DatagramChannel public abstract <T> DatagramChannel setOption(SocketOption<T> name, T value) throws IOException; - /** * Retrieves a datagram socket associated with this channel. * @@ -259,7 +261,10 @@ public abstract class DatagramChannel * * <p> This method may be invoked at any time. It will not have any effect * on read or write operations that are already in progress at the moment - * that it is invoked. </p> + * that it is invoked. If this channel's socket is not bound then this method + * will first cause the socket to be bound to an address that is assigned + * automatically, as if invoking the {@link #bind bind} method with a + * parameter of {@code null}. </p> * * @param remote * The remote address to which this channel is to be connected @@ -313,15 +318,17 @@ public abstract class DatagramChannel /** * Returns the remote address to which this channel's socket is connected. * - * @return The remote address; {@code null} if the channel is not {@link - * #isOpen open} or the channel's socket is not connected + * @return The remote address; {@code null} if the channel's socket is not + * connected * + * @throws ClosedChannelException + * If the channel is closed * @throws IOException * If an I/O error occurs * * @since 1.7 */ - public abstract SocketAddress getConnectedAddress() throws IOException; + public abstract SocketAddress getRemoteAddress() throws IOException; /** * Receives a datagram via this channel. @@ -352,7 +359,10 @@ public abstract class DatagramChannel * <p> This method may be invoked at any time. If another thread has * already initiated a read operation upon this channel, however, then an * invocation of this method will block until the first operation is - * complete. </p> + * complete. If this channel's socket is not bound then this method will + * first cause the socket to be bound to an address that is assigned + * automatically, as if invoking the {@link #bind bind} method with a + * parameter of {@code null}. </p> * * @param dst * The buffer into which the datagram is to be transferred @@ -409,7 +419,10 @@ public abstract class DatagramChannel * <p> This method may be invoked at any time. If another thread has * already initiated a write operation upon this channel, however, then an * invocation of this method will block until the first operation is - * complete. </p> + * complete. If this channel's socket is not bound then this method will + * first cause the socket to be bound to an address that is assigned + * automatically, as if by invoking the {@link #bind bind) method with a + * parameter of {@code null}. </p> * * @param src * The buffer containing the datagram to be sent diff --git a/jdk/src/share/classes/java/nio/channels/FileChannel.java b/jdk/src/share/classes/java/nio/channels/FileChannel.java index e3b5f5bcb79..ab780a520a9 100644 --- a/jdk/src/share/classes/java/nio/channels/FileChannel.java +++ b/jdk/src/share/classes/java/nio/channels/FileChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,16 +29,23 @@ import java.io.*; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.spi.AbstractInterruptibleChannel; - +import java.nio.file.*; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.spi.*; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; /** * A channel for reading, writing, mapping, and manipulating a file. * - * <p> A file channel has a current <i>position</i> within its file which can - * be both {@link #position() </code>queried<code>} and {@link #position(long) - * </code>modified<code>}. The file itself contains a variable-length sequence + * <p> {@note revised} + * A file channel is a {@link SeekableByteChannel} that is connected to + * a file. It has a current <i>position</i> within its file which can + * be both {@link #position() <i>queried</i>} and {@link #position(long) + * <i>modified</i>}. The file itself contains a variable-length sequence * of bytes that can be read and written and whose current {@link #size - * </code><i>size</i><code>} can be queried. The size of the file increases + * <i>size</i>} can be queried. The size of the file increases * when bytes are written beyond its current size; the size of the file * decreases when it is {@link #truncate </code><i>truncated</i><code>}. The * file may also have some associated <i>metadata</i> such as access @@ -50,27 +57,27 @@ import java.nio.channels.spi.AbstractInterruptibleChannel; * * <ul> * - * <li><p> Bytes may be {@link #read(ByteBuffer, long) </code>read<code>} or - * {@link #write(ByteBuffer, long) </code>written<code>} at an absolute + * <li><p> Bytes may be {@link #read(ByteBuffer, long) read} or + * {@link #write(ByteBuffer, long) <i>written</i>} at an absolute * position in a file in a way that does not affect the channel's current * position. </p></li> * - * <li><p> A region of a file may be {@link #map </code>mapped<code>} + * <li><p> A region of a file may be {@link #map <i>mapped</i>} * directly into memory; for large files this is often much more efficient * than invoking the usual <tt>read</tt> or <tt>write</tt> methods. * </p></li> * - * <li><p> Updates made to a file may be {@link #force </code>forced - * out<code>} to the underlying storage device, ensuring that data are not + * <li><p> Updates made to a file may be {@link #force <i>forced + * out</i>} to the underlying storage device, ensuring that data are not * lost in the event of a system crash. </p></li> * - * <li><p> Bytes can be transferred from a file {@link #transferTo </code>to - * some other channel<code>}, and {@link #transferFrom </code>vice - * versa<code>}, in a way that can be optimized by many operating systems + * <li><p> Bytes can be transferred from a file {@link #transferTo <i>to + * some other channel</i>}, and {@link #transferFrom <i>vice + * versa</i>}, in a way that can be optimized by many operating systems * into a very fast transfer directly to or from the filesystem cache. * </p></li> * - * <li><p> A region of a file may be {@link FileLock </code>locked<code>} + * <li><p> A region of a file may be {@link FileLock <i>locked</i>} * against access by other programs. </p></li> * * </ul> @@ -96,25 +103,23 @@ import java.nio.channels.spi.AbstractInterruptibleChannel; * machine. The exact nature of any such inconsistencies are system-dependent * and are therefore unspecified. * - * <p> This class does not define methods for opening existing files or for - * creating new ones; such methods may be added in a future release. In this - * release a file channel can be obtained from an existing {@link - * java.io.FileInputStream#getChannel FileInputStream}, {@link + * <p> A file channel is created by invoking one of the {@link #open open} + * methods defined by this class. A file channel can also be obtained from an + * existing {@link java.io.FileInputStream#getChannel FileInputStream}, {@link * java.io.FileOutputStream#getChannel FileOutputStream}, or {@link * java.io.RandomAccessFile#getChannel RandomAccessFile} object by invoking * that object's <tt>getChannel</tt> method, which returns a file channel that - * is connected to the same underlying file. + * is connected to the same underlying file. Where the file channel is obtained + * from an existing stream or random access file then the state of the file + * channel is intimately connected to that of the object whose <tt>getChannel</tt> + * method returned the channel. Changing the channel's position, whether + * explicitly or by reading or writing bytes, will change the file position of + * the originating object, and vice versa. Changing the file's length via the + * file channel will change the length seen via the originating object, and vice + * versa. Changing the file's content by writing bytes will change the content + * seen by the originating object, and vice versa. * - * <p> The state of a file channel is intimately connected to that of the - * object whose <tt>getChannel</tt> method returned the channel. Changing the - * channel's position, whether explicitly or by reading or writing bytes, will - * change the file position of the originating object, and vice versa. - * Changing the file's length via the file channel will change the length seen - * via the originating object, and vice versa. Changing the file's content by - * writing bytes will change the content seen by the originating object, and - * vice versa. - * - * <a name="open-mode"><p> At various points this class specifies that an + * <a name="open-mode"></a> <p> At various points this class specifies that an * instance that is "open for reading," "open for writing," or "open for * reading and writing" is required. A channel obtained via the {@link * java.io.FileInputStream#getChannel getChannel} method of a {@link @@ -127,7 +132,7 @@ import java.nio.channels.spi.AbstractInterruptibleChannel; * was created with mode <tt>"r"</tt> and will be open for reading and writing * if the instance was created with mode <tt>"rw"</tt>. * - * <a name="append-mode"><p> A file channel that is open for writing may be in + * <a name="append-mode"></a><p> A file channel that is open for writing may be in * <i>append mode</i>, for example if it was obtained from a file-output stream * that was created by invoking the {@link * java.io.FileOutputStream#FileOutputStream(java.io.File,boolean) @@ -138,7 +143,6 @@ import java.nio.channels.spi.AbstractInterruptibleChannel; * of the data are done in a single atomic operation is system-dependent and * therefore unspecified. * - * * @see java.io.FileInputStream#getChannel() * @see java.io.FileOutputStream#getChannel() * @see java.io.RandomAccessFile#getChannel() @@ -147,18 +151,190 @@ import java.nio.channels.spi.AbstractInterruptibleChannel; * @author Mike McCloskey * @author JSR-51 Expert Group * @since 1.4 + * @updated 1.7 */ public abstract class FileChannel extends AbstractInterruptibleChannel - implements ByteChannel, GatheringByteChannel, ScatteringByteChannel + implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel { - /** * Initializes a new instance of this class. */ protected FileChannel() { } + /** + * {@note new} + * Opens or creates a file, returning a file channel to access the file. + * + * <p> The {@code options} parameter determines how the file is opened. + * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE + * WRITE} options determine if the file should be opened for reading and/or + * writing. If neither option (or the {@link StandardOpenOption#APPEND APPEND} + * option) is contained in the array then the file is opened for reading. + * By default reading or writing commences at the beginning of the file. + * + * <p> In the addition to {@code READ} and {@code WRITE}, the following + * options may be present: + * + * <table border=1 cellpadding=5 summary=""> + * <tr> <th>Option</th> <th>Description</th> </tr> + * <tr> + * <td> {@link StandardOpenOption#APPEND APPEND} </td> + * <td> If this option is present then the file is opened for writing and + * each invocation of the channel's {@code write} method first advances + * the position to the end of the file and then writes the requested + * data. Whether the advancement of the position and the writing of the + * data are done in a single atomic operation is system-dependent and + * therefore unspecified. This option may not be used in conjunction + * with the {@code READ} or {@code TRUNCATE_EXISTING} options. </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td> + * <td> If this option is present then the existing file is truncated to + * a size of 0 bytes. This option is ignored when the file is opened only + * for reading. </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td> + * <td> If this option is present then a new file is created, failing if + * the file already exists. When creating a file the check for the + * existence of the file and the creation of the file if it does not exist + * is atomic with respect to other file system operations. This option is + * ignored when the file is opened only for reading. </td> + * </tr> + * <tr> + * <td > {@link StandardOpenOption#CREATE CREATE} </td> + * <td> If this option is present then an existing file is opened if it + * exists, otherwise a new file is created. When creating a file the check + * for the existence of the file and the creation of the file if it does + * not exist is atomic with respect to other file system operations. This + * option is ignored if the {@code CREATE_NEW} option is also present or + * the file is opened only for reading. </td> + * </tr> + * <tr> + * <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td> + * <td> When this option is present then the implementation makes a + * <em>best effort</em> attempt to delete the file when closed by the + * the {@link #close close} method. If the {@code close} method is not + * invoked then a <em>best effort</em> attempt is made to delete the file + * when the Java virtual machine terminates. </td> + * </tr> + * <tr> + * <td>{@link StandardOpenOption#SPARSE SPARSE} </td> + * <td> When creating a new file this option is a <em>hint</em> that the + * new file will be sparse. This option is ignored when not creating + * a new file. </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#SYNC SYNC} </td> + * <td> Requires that every update to the file's content or metadata be + * written synchronously to the underlying storage device. (see <a + * href="../file/package-summary.html#integrity"> Synchronized I/O file + * integrity</a>). </td> + * <tr> + * <tr> + * <td> {@link StandardOpenOption#DSYNC DSYNC} </td> + * <td> Requires that every update to the file's content be written + * synchronously to the underlying storage device. (see <a + * href="../file/package-summary.html#integrity"> Synchronized I/O file + * integrity</a>). </td> + * </tr> + * </table> + * + * <p> An implementation may also support additional options. + * + * <p> The {@code attrs} parameter is an optional array of file {@link + * FileAttribute file-attributes} to set atomically when creating the file. + * + * <p> The new channel is created by invoking the {@link + * FileSystemProvider#newFileChannel newFileChannel} method on the + * provider that created the {@code Path}. + * + * @param file + * The path of the file to open or create + * @param options + * Options specifying how the file is opened + * @param attrs + * An optional list of file attributes to set atomically when + * creating the file + * + * @return A new file channel + * + * @throws IllegalArgumentException + * If the set contains an invalid combination of options + * @throws UnsupportedOperationException + * If the {@code file} is associated with a provider that does not + * support creating file channels, or an unsupported open option is + * specified, or the array contains an attribute that cannot be set + * atomically when creating the file + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * If a security manager is installed and it denies an + * unspecified permission required by the implementation. + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String)} method is invoked to check + * read access if the file is opened for reading. The {@link + * SecurityManager#checkWrite(String)} method is invoked to check + * write access if the file is opened for writing + * + * @since 1.7 + */ + public static FileChannel open(Path file, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + FileSystemProvider provider = file.getFileSystem().provider(); + return provider.newFileChannel(file, options, attrs); + } + + private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0]; + + /** + * {@note new} + * Opens or creates a file, returning a file channel to access the file. + * + * <p> An invocation of this method behaves in exactly the same way as the + * invocation + * <pre> + * fc.{@link #open(Path,Set,FileAttribute[]) open}(file, options, new FileAttribute<?>[0]); + * </pre> + * + * @param file + * The path of the file to open or create + * @param options + * Options specifying how the file is opened + * + * @return A new file channel + * + * @throws IllegalArgumentException + * If the set contains an invalid combination of options + * @throws UnsupportedOperationException + * If the {@code file} is associated with a provider that does not + * support creating file channels, or an unsupported open option is + * specified + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * If a security manager is installed and it denies an + * unspecified permission required by the implementation. + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String)} method is invoked to check + * read access if the file is opened for reading. The {@link + * SecurityManager#checkWrite(String)} method is invoked to check + * write access if the file is opened for writing + * + * @since 1.7 + */ + public static FileChannel open(Path file, OpenOption... options) + throws IOException + { + Set<OpenOption> set = new HashSet<OpenOption>(options.length); + Collections.addAll(set, options); + return open(file, set, NO_ATTRIBUTES); + } // -- Channel operations -- @@ -286,7 +462,7 @@ public abstract class FileChannel public abstract FileChannel position(long newPosition) throws IOException; /** - * Returns the current size of this channel's file. </p> + * Returns the current size of this channel's file. </p> * * @return The current size of this channel's file, * measured in bytes @@ -359,7 +535,7 @@ public abstract class FileChannel * <p> This method is only guaranteed to force changes that were made to * this channel's file via the methods defined in this class. It may or * may not force changes that were made by modifying the content of a - * {@link MappedByteBuffer </code>mapped byte buffer<code>} obtained by + * {@link MappedByteBuffer <i>mapped byte buffer</i>} obtained by * invoking the {@link #map map} method. Invoking the {@link * MappedByteBuffer#force force} method of the mapped byte buffer will * force changes made to the buffer's content to be written. </p> @@ -678,7 +854,7 @@ public abstract class FileChannel * reading; for a read/write or private mapping, this channel must have * been opened for both reading and writing. * - * <p> The {@link MappedByteBuffer </code>mapped byte buffer<code>} + * <p> The {@link MappedByteBuffer <i>mapped byte buffer</i>} * returned by this method will have a position of zero and a limit and * capacity of <tt>size</tt>; its mark will be undefined. The buffer and * the mapping that it represents will remain valid until the buffer itself @@ -717,6 +893,8 @@ public abstract class FileChannel * The size of the region to be mapped; must be non-negative and * no greater than {@link java.lang.Integer#MAX_VALUE} * + * @return The mapped byte buffer + * * @throws NonReadableChannelException * If the <tt>mode</tt> is {@link MapMode#READ_ONLY READ_ONLY} but * this channel was not opened for reading diff --git a/jdk/src/share/classes/java/nio/channels/FileLock.java b/jdk/src/share/classes/java/nio/channels/FileLock.java index 921922242d7..b0ec37f1ba5 100644 --- a/jdk/src/share/classes/java/nio/channels/FileLock.java +++ b/jdk/src/share/classes/java/nio/channels/FileLock.java @@ -1,5 +1,5 @@ /* - * Copyright 2001 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,16 @@ package java.nio.channels; import java.io.IOException; - /** * A token representing a lock on a region of a file. * * <p> A file-lock object is created each time a lock is acquired on a file via * one of the {@link FileChannel#lock(long,long,boolean) lock} or {@link - * FileChannel#tryLock(long,long,boolean) tryLock} methods of the {@link - * FileChannel} class. + * FileChannel#tryLock(long,long,boolean) tryLock} methods of the + * {@link FileChannel} class, or the {@link + * AsynchronousFileChannel#lock(long,long,boolean,Object,CompletionHandler) lock} + * or {@link AsynchronousFileChannel#tryLock(long,long,boolean) tryLock} + * methods of the {@link AsynchronousFileChannel} class. * * <p> A file-lock object is initially valid. It remains valid until the lock * is released by invoking the {@link #release release} method, by closing the @@ -70,8 +72,7 @@ import java.io.IOException; * <p> File-lock objects are safe for use by multiple concurrent threads. * * - * <a name="pdep"> - * <h4> Platform dependencies </h4> + * <a name="pdep"><h4> Platform dependencies </h4></a> * * <p> This file-locking API is intended to map directly to the native locking * facility of the underlying operating system. Thus the locks held on a file @@ -93,7 +94,7 @@ import java.io.IOException; * * <p> On some systems, acquiring a mandatory lock on a region of a file * prevents that region from being {@link java.nio.channels.FileChannel#map - * </code>mapped into memory<code>}, and vice versa. Programs that combine + * <i>mapped into memory</i>}, and vice versa. Programs that combine * locking and mapping should be prepared for this combination to fail. * * <p> On some systems, closing a channel releases all locks held by the Java @@ -113,11 +114,12 @@ import java.io.IOException; * @author Mark Reinhold * @author JSR-51 Expert Group * @since 1.4 + * @updated 1.7 */ public abstract class FileLock { - private final FileChannel channel; + private final Channel channel; private final long position; private final long size; private final boolean shared; @@ -159,11 +161,66 @@ public abstract class FileLock { } /** - * Returns the file channel upon whose file this lock is held. </p> + * {@note new} Initializes a new instance of this class. * - * @return The file channel + * @param channel + * The channel upon whose file this lock is held + * + * @param position + * The position within the file at which the locked region starts; + * must be non-negative + * + * @param size + * The size of the locked region; must be non-negative, and the sum + * <tt>position</tt> + <tt>size</tt> must be non-negative + * + * @param shared + * <tt>true</tt> if this lock is shared, + * <tt>false</tt> if it is exclusive + * + * @throws IllegalArgumentException + * If the preconditions on the parameters do not hold + * + * @since 1.7 + */ + protected FileLock(AsynchronousFileChannel channel, + long position, long size, boolean shared) + { + if (position < 0) + throw new IllegalArgumentException("Negative position"); + if (size < 0) + throw new IllegalArgumentException("Negative size"); + if (position + size < 0) + throw new IllegalArgumentException("Negative position + size"); + this.channel = channel; + this.position = position; + this.size = size; + this.shared = shared; + } + + /** + * {@note revised} + * Returns the file channel upon whose file this lock was acquired. + * + * <p> This method has been superseded by the {@link #acquiredBy acquiredBy} + * method. + * + * @return The file channel, or {@code null} if the file lock was not + * acquired by a file channel. */ public final FileChannel channel() { + return (channel instanceof FileChannel) ? (FileChannel)channel : null; + } + + /** + * {@note new} + * Returns the channel upon whose file this lock was acquired. + * + * @return The channel upon whose file this lock was acquired. + * + * @since 1.7 + */ + public Channel acquiredBy() { return channel; } diff --git a/jdk/src/share/classes/java/nio/channels/MembershipKey.java b/jdk/src/share/classes/java/nio/channels/MembershipKey.java index 0d2fc52bc4d..804e6724ad0 100644 --- a/jdk/src/share/classes/java/nio/channels/MembershipKey.java +++ b/jdk/src/share/classes/java/nio/channels/MembershipKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package java.nio.channels; import java.net.InetAddress; import java.net.NetworkInterface; import java.io.IOException; -import java.util.List; /** * A token representing the membership of an Internet Protocol (IP) multicast @@ -38,7 +37,7 @@ import java.util.List; * to the group, or it may be <em>source-specific</em>, meaning that it * represents a membership that receives only datagrams from a specific source * address. Whether or not a membership key is source-specific may be determined - * by invoking its {@link #getSourceAddress() getSourceAddress} method. + * by invoking its {@link #sourceAddress() sourceAddress} method. * * <p> A membership key is valid upon creation and remains valid until the * membership is dropped by invoking the {@link #drop() drop} method, or @@ -93,11 +92,8 @@ public abstract class MembershipKey { * If the multicast group membership is already invalid then invoking this * method has no effect. Once a multicast group membership is invalid, * it remains invalid forever. - * - * @throws IOException - * If an I/O error occurs */ - public abstract void drop() throws IOException; + public abstract void drop(); /** * Block multicast datagrams from the given source address. @@ -140,10 +136,8 @@ public abstract class MembershipKey { * @throws IllegalStateException * If the given source address is not currently blocked or the * membership key is no longer valid - * @throws IOException - * If an I/O error occurs */ - public abstract MembershipKey unblock(InetAddress source) throws IOException; + public abstract MembershipKey unblock(InetAddress source); /** * Returns the channel for which this membership key was created. This @@ -152,7 +146,7 @@ public abstract class MembershipKey { * * @return the channel */ - public abstract MulticastChannel getChannel(); + public abstract MulticastChannel channel(); /** * Returns the multicast group for which this membership key was created. @@ -161,7 +155,7 @@ public abstract class MembershipKey { * * @return the multicast group */ - public abstract InetAddress getGroup(); + public abstract InetAddress group(); /** * Returns the network interface for which this membership key was created. @@ -170,7 +164,7 @@ public abstract class MembershipKey { * * @return the network interface */ - public abstract NetworkInterface getNetworkInterface(); + public abstract NetworkInterface networkInterface(); /** * Returns the source address if this membership key is source-specific, @@ -179,5 +173,5 @@ public abstract class MembershipKey { * @return The source address if this membership key is source-specific, * otherwise {@code null} */ - public abstract InetAddress getSourceAddress(); + public abstract InetAddress sourceAddress(); } diff --git a/jdk/src/share/classes/java/nio/channels/MulticastChannel.java b/jdk/src/share/classes/java/nio/channels/MulticastChannel.java index 440dd2a8b85..1cacf98e69c 100644 --- a/jdk/src/share/classes/java/nio/channels/MulticastChannel.java +++ b/jdk/src/share/classes/java/nio/channels/MulticastChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,6 +122,22 @@ import java.net.StandardSocketOption; // javadoc public interface MulticastChannel extends NetworkChannel { + /** + * Closes this channel. + * + * <p> If the channel is a member of a multicast group then the membership + * is {@link MembershipKey#drop dropped}. Upon return, the {@link + * MembershipKey membership-key} will be {@link MembershipKey#isValid + * invalid}. + * + * <p> This method otherwise behaves exactly as specified by the {@link + * Channel} interface. + * + * @throws IOException + * If an I/O error occurs + */ + @Override void close() throws IOException; + /** * Joins a multicast group to begin receiving all datagrams sent to the group, * returning a membership key. @@ -130,7 +146,7 @@ public interface MulticastChannel * interface to receive all datagrams then the membership key, representing * that membership, is returned. Otherwise this channel joins the group and * the resulting new membership key is returned. The resulting membership key - * is not {@link MembershipKey#getSourceAddress source-specific}. + * is not {@link MembershipKey#sourceAddress source-specific}. * * <p> A multicast channel may join several multicast groups, including * the same group on more than one interface. An implementation may impose a @@ -150,6 +166,8 @@ public interface MulticastChannel * @throws IllegalStateException * If the channel already has source-specific membership of the * group on the interface + * @throws UnsupportedOperationException + * If the channel's socket is not an Internet Protocol socket * @throws ClosedChannelException * If this channel is closed * @throws IOException @@ -170,7 +188,7 @@ public interface MulticastChannel * interface to receive datagrams from the given source address then the * membership key, representing that membership, is returned. Otherwise this * channel joins the group and the resulting new membership key is returned. - * The resulting membership key is {@link MembershipKey#getSourceAddress + * The resulting membership key is {@link MembershipKey#sourceAddress * source-specific}. * * <p> Membership is <em>cumulative</em> and this method may be invoked @@ -196,7 +214,8 @@ public interface MulticastChannel * If the channel is currently a member of the group on the given * interface to receive all datagrams * @throws UnsupportedOperationException - * If the underlying operation system does not support source filtering + * If the channel's socket is not an Internet Protocol socket or + * source filtering is not supported * @throws ClosedChannelException * If this channel is closed * @throws IOException diff --git a/jdk/src/share/classes/java/nio/channels/NetworkChannel.java b/jdk/src/share/classes/java/nio/channels/NetworkChannel.java index fae642fcbdb..103427759e7 100644 --- a/jdk/src/share/classes/java/nio/channels/NetworkChannel.java +++ b/jdk/src/share/classes/java/nio/channels/NetworkChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,9 +95,10 @@ public interface NetworkChannel * java.net.InetSocketAddress}. * * @return The socket address that the socket is bound to, or {@code null} - * if the channel is not {@link #isOpen open} or the channel's socket - * is not bound + * if the channel's socket is not bound * + * @throws ClosedChannelException + * If the channel is closed * @throws IOException * If an I/O error occurs */ @@ -114,9 +115,10 @@ public interface NetworkChannel * * @return This channel * + * @throws UnsupportedOperationException + * If the socket option is not supported by this channel * @throws IllegalArgumentException - * If the socket option is not supported by this channel, or - * the value is not a valid value for this socket option + * If the value is not a valid value for this socket option * @throws ClosedChannelException * If this channel is closed * @throws IOException @@ -135,7 +137,7 @@ public interface NetworkChannel * @return The value of the socket option. A value of {@code null} may be * a valid value for some socket options. * - * @throws IllegalArgumentException + * @throws UnsupportedOperationException * If the socket option is not supported by this channel * @throws ClosedChannelException * If this channel is closed @@ -154,5 +156,5 @@ public interface NetworkChannel * * @return A set of the socket options supported by this channel */ - Set<SocketOption<?>> options(); + Set<SocketOption<?>> supportedOptions(); } diff --git a/jdk/src/share/classes/java/nio/channels/SeekableByteChannel.java b/jdk/src/share/classes/java/nio/channels/SeekableByteChannel.java new file mode 100644 index 00000000000..33efc248861 --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/SeekableByteChannel.java @@ -0,0 +1,168 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.nio.ByteBuffer; +import java.io.IOException; + +/** + * A byte channel that maintains a current <i>position</i> and allows the + * position to be changed. + * + * <p> A seekable byte channel is connected to an entity, typically a file, + * that contains a variable-length sequence of bytes that can be read and + * written. The current position can be {@link #position() <i>queried</i>} and + * {@link #position(long) <i>modified</i>}. The channel also provides access to + * the current <i>size</i> of the entity to which the channel is connected. The + * size increases when bytes are written beyond its current size; the size + * decreases when it is {@link #truncate <i>truncated</i>}. + * + * <p> The {@link #position(long) position} and {@link #truncate truncate} methods + * which do not otherwise have a value to return are specified to return the + * channel upon which they are invoked. This allows method invocations to be + * chained. Implementations of this interface should specialize the return type + * so that method invocations on the implementation class can be chained. + * + * @since 1.7 + * @see java.nio.file.FileRef#newByteChannel + */ + +public interface SeekableByteChannel + extends ByteChannel +{ + /** + * Reads a sequence of bytes from this channel into the given buffer. + * + * <p> Bytes are read starting at this channel's current position, and + * then the position is updated with the number of bytes actually read. + * Otherwise this method behaves exactly as specified in the {@link + * ReadableByteChannel} interface. + */ + @Override + int read(ByteBuffer dst) throws IOException; + + /** + * Writes a sequence of bytes to this channel from the given buffer. + * + * <p> Bytes are written starting at this channel's current position, unless + * the channel is connected to an entity such as a file that is opened with + * the {@link java.nio.file.StandardOpenOption#APPEND APPEND} option, in + * which case the position is first advanced to the end. The entity to which + * the channel is connected is grown, if necessary, to accommodate the + * written bytes, and then the position is updated with the number of bytes + * actually written. Otherwise this method behaves exactly as specified by + * the {@link WritableByteChannel} interface. + */ + @Override + int write(ByteBuffer src) throws IOException; + + /** + * Returns this channel's position. + * + * @return This channel's position, + * a non-negative integer counting the number of bytes + * from the beginning of the entity to the current position + * + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If some other I/O error occurs + */ + long position() throws IOException; + + /** + * Sets this channel's position. + * + * <p> Setting the position to a value that is greater than the current size + * is legal but does not change the size of the entity. A later attempt to + * read bytes at such a position will immediately return an end-of-file + * indication. A later attempt to write bytes at such a position will cause + * the entity to grow to accommodate the new bytes; the values of any bytes + * between the previous end-of-file and the newly-written bytes are + * unspecified. + * + * <p> Setting the channel's position is not recommended when connected to + * an entity, typically a file, that is opened with the {@link + * java.nio.file.StandardOpenOption#APPEND APPEND} option. When opened for + * append, the position is first advanced to the end before writing. + * + * @param newPosition + * The new position, a non-negative integer counting + * the number of bytes from the beginning of the entity + * + * @return This channel + * + * @throws ClosedChannelException + * If this channel is closed + * @throws IllegalArgumentException + * If the new position is negative + * @throws IOException + * If some other I/O error occurs + */ + SeekableByteChannel position(long newPosition) throws IOException; + + /** + * Returns the current size of entity to which this channel is connected. + * + * @return The current size, measured in bytes + * + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If some other I/O error occurs + */ + long size() throws IOException; + + /** + * Truncates the entity, to which this channel is connected, to the given + * size. + * + * <p> If the given size is less than the current size then the entity is + * truncated, discarding any bytes beyond the new end. If the given size is + * greater than or equal to the current size then the entity is not modified. + * In either case, if the current position is greater than the given size + * then it is set to that size. + * + * <p> An implementation of this interface may prohibit truncation when + * connected to an entity, typically a file, opened with the {@link + * java.nio.file.StandardOpenOption#APPEND APPEND} option. + * + * @param size + * The new size, a non-negative byte count + * + * @return This channel + * + * @throws NonWritableChannelException + * If this channel was not opened for writing + * @throws ClosedChannelException + * If this channel is closed + * @throws IllegalArgumentException + * If the new size is negative + * @throws IOException + * If some other I/O error occurs + */ + SeekableByteChannel truncate(long size) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java b/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java index 84ea062c9f0..5be9bc7cb15 100644 --- a/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java +++ b/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,8 @@ import java.io.IOException; import java.net.ServerSocket; import java.net.SocketOption; import java.net.SocketAddress; -import java.nio.channels.spi.*; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.SelectorProvider; /** * A selectable channel for stream-oriented listening sockets. @@ -195,6 +196,7 @@ public abstract class ServerSocketChannel throws IOException; /** + * @throws UnsupportedOperationException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws ClosedChannelException {@inheritDoc} * @throws IOException {@inheritDoc} diff --git a/jdk/src/share/classes/java/nio/channels/SocketChannel.java b/jdk/src/share/classes/java/nio/channels/SocketChannel.java index 2e96bd2e4ce..975048df0c0 100644 --- a/jdk/src/share/classes/java/nio/channels/SocketChannel.java +++ b/jdk/src/share/classes/java/nio/channels/SocketChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,8 @@ import java.net.Socket; import java.net.SocketOption; import java.net.SocketAddress; import java.nio.ByteBuffer; -import java.nio.channels.spi.*; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.SelectorProvider; /** * A selectable channel for stream-oriented connecting sockets. @@ -212,7 +213,7 @@ public abstract class SocketChannel /** * @throws ConnectionPendingException - * If a non-blocking connection operation is already in progress on + * If a non-blocking connect operation is already in progress on * this channel * @throws AlreadyBoundException {@inheritDoc} * @throws UnsupportedAddressTypeException {@inheritDoc} @@ -226,6 +227,7 @@ public abstract class SocketChannel throws IOException; /** + * @throws UnsupportedOperationException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws ClosedChannelException {@inheritDoc} * @throws IOException {@inheritDoc} @@ -432,15 +434,17 @@ public abstract class SocketChannel * socket address then the return value from this method is of type {@link * java.net.InetSocketAddress}. * - * @return The remote address; {@code null} if the channel is not {@link - * #isOpen open} or the channel's socket is not connected + * @return The remote address; {@code null} if the channel's socket is not + * connected * + * @throws ClosedChannelException + * If the channel is closed * @throws IOException * If an I/O error occurs * * @since 1.7 */ - public abstract SocketAddress getConnectedAddress() throws IOException; + public abstract SocketAddress getRemoteAddress() throws IOException; // -- ByteChannel operations -- diff --git a/jdk/src/share/classes/java/nio/channels/exceptions b/jdk/src/share/classes/java/nio/channels/exceptions index 04cfbe03e29..fed9f72ab2e 100644 --- a/jdk/src/share/classes/java/nio/channels/exceptions +++ b/jdk/src/share/classes/java/nio/channels/exceptions @@ -1,5 +1,5 @@ # -# Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -150,6 +150,21 @@ gen OverlappingFileLockException " SINCE=1.7 +SUPER=java.io.IOException + +gen InterruptedByTimeoutException " + * Checked exception received by a thread when a timeout elapses before an + * asynchronous operation completes." \ + -4268008601014042947L + +SUPER=IllegalArgumentException + +gen IllegalChannelGroupException " + * Unchecked exception thrown when an attempt is made to open a channel + * in a group that was not created by the same provider. " \ + -2495041211157744253L + + SUPER=IllegalStateException gen AlreadyBoundException " @@ -157,3 +172,23 @@ gen AlreadyBoundException " * network oriented channel that is already bound." \ 6796072983322737592L +gen AcceptPendingException " + * Unchecked exception thrown when an attempt is made to initiate an accept + * operation on a channel and a previous accept operation has not completed." \ + 2721339977965416421L + +gen ReadPendingException " + * Unchecked exception thrown when an attempt is made to read from an + * asynchronous socket channel and a previous read has not completed." \ + 1986315242191227217L + +gen WritePendingException " + * Unchecked exception thrown when an attempt is made to write to an + * asynchronous socket channel and a previous write has not completed." \ + 7031871839266032276L + +gen ShutdownChannelGroupException " + * Unchecked exception thrown when an attempt is made to construct a channel in + * a group that is shutdown or the completion handler for an I/O operation + * cannot be invoked because the channel group is shutdown." \ + -3903801676350154157L diff --git a/jdk/src/share/classes/java/nio/channels/package-info.java b/jdk/src/share/classes/java/nio/channels/package-info.java index e8c2a929d4b..47a1cb5f979 100644 --- a/jdk/src/share/classes/java/nio/channels/package-info.java +++ b/jdk/src/share/classes/java/nio/channels/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,10 @@ * <td>Can read/write to/from a buffer</td></tr> * <tr><td valign=top><tt>    <i>{@link java.nio.channels.SeekableByteChannel}</i></tt></td> * <td>A {@code ByteChannel} connected to an entity that contains a variable-length sequence of bytes</td></tr> + * <tr><td valign=top><tt>  <i>{@link java.nio.channels.AsynchronousChannel}</i></tt></td> + * <td>Supports asynchronous I/O operations.</td></tr> + * <tr><td valign=top><tt>    <i>{@link java.nio.channels.AsynchronousByteChannel}</i></tt></td> + * <td>Can read and write bytes asynchronously</td></tr> * <tr><td valign=top><tt>  <i>{@link java.nio.channels.NetworkChannel}</i></tt></td> * <td>A channel to a network socket</td></tr> * <tr><td valign=top><tt>    <i>{@link java.nio.channels.MulticastChannel}</i></tt></td> @@ -218,12 +222,70 @@ * directly; custom channel classes should extend the appropriate {@link * java.nio.channels.SelectableChannel} subclasses defined in this package. * + * <a name="async"></a> + * + * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists asynchronous channels and their descriptions"> + * <tr><th><p align="left">Asynchronous I/O</p></th><th><p align="left">Description</p></th></tr> + * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousFileChannel}</tt></td> + * <td>An asynchronous channel for reading, writing, and manipulating a file</td></tr> + * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousSocketChannel}</tt></td> + * <td>An asynchronous channel to a stream-oriented connecting socket</td></tr> + * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousServerSocketChannel}  </tt></td> + * <td>An asynchronous channel to a stream-oriented listening socket</td></tr> + * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousDatagramChannel}</tt></td> + * <td>An asynchronous channel to a datagram-oriented socket</td></tr> + * <tr><td valign=top><tt>{@link java.nio.channels.CompletionHandler}</tt></td> + * <td>A handler for consuming the result of an asynchronous operation</td></tr> + * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousChannelGroup}</tt></td> + * <td>A grouping of asynchronous channels for the purpose of resource sharing</td></tr> + * </table></blockquote> + * + * <p> {@link java.nio.channels.AsynchronousChannel Asynchronous channels} are a + * special type of channel capable of asynchronous I/O operations. Asynchronous + * channels are non-blocking and define methods to initiate asynchronous + * operations, returning a {@link java.util.concurrent.Future} representing the + * pending result of each operation. The {@code Future} can be used to poll or + * wait for the result of the operation. Asynchronous I/O operations can also + * specify a {@link java.nio.channels.CompletionHandler} to invoke when the + * operation completes. A completion handler is user provided code that is executed + * to consume the result of I/O operation. + * + * <p> This package defines asynchronous-channel classes that are connected to + * a stream-oriented connecting or listening socket, or a datagram-oriented socket. + * It also defines the {@link java.nio.channels.AsynchronousFileChannel} class + * for asynchronous reading, writing, and manipulating a file. As with the {@link + * java.nio.channels.FileChannel} it supports operations to truncate the file + * to a specific size, force updates to the file to be written to the storage + * device, or acquire locks on the whole file or on a specific region of the file. + * Unlike the {@code FileChannel} it does not define methods for mapping a + * region of the file directly into memory. Where memory mapped I/O is required, + * then a {@code FileChannel} can be used. + * + * <p> Asynchronous channels are bound to an asynchronous channel group for the + * purpose of resource sharing. A group has an associated {@link + * java.util.concurrent.ExecutorService} to which tasks are submitted to handle + * I/O events and dispatch to completion handlers that consume the result of + * asynchronous operations performed on channels in the group. The group can + * optionally be specified when creating the channel or the channel can be bound + * to a <em>default group</em>. Sophisticated users may wish to create their + * own asynchronous channel groups or configure the {@code ExecutorService} + * that will be used for the default group. + * + * <p> As with selectors, the implementatin of asynchronous channels can be + * replaced by "plugging in" an alternative definition or instance of the {@link + * java.nio.channels.spi.AsynchronousChannelProvider} class defined in the + * <tt>{@link java.nio.channels.spi}</tt> package. It is not expected that many + * developers will actually make use of this facility; it is provided primarily + * so that sophisticated users can take advantage of operating-system-specific + * asynchronous I/O mechanisms when very high performance is required. + * * <hr width="80%"> * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor * or method in any class or interface in this package will cause a {@link * java.lang.NullPointerException NullPointerException} to be thrown. * * @since 1.4 + * @updated 1.7 * @author Mark Reinhold * @author JSR-51 Expert Group */ diff --git a/jdk/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java b/jdk/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java new file mode 100644 index 00000000000..941364876ed --- /dev/null +++ b/jdk/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java @@ -0,0 +1,264 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels.spi; + +import java.nio.channels.*; +import java.net.ProtocolFamily; +import java.io.IOException; +import java.util.Iterator; +import java.util.ServiceLoader; +import java.util.ServiceConfigurationError; +import java.util.concurrent.*; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Service-provider class for asynchronous channels. + * + * <p> An asynchronous channel provider is a concrete subclass of this class that + * has a zero-argument constructor and implements the abstract methods specified + * below. A given invocation of the Java virtual machine maintains a single + * system-wide default provider instance, which is returned by the {@link + * #provider() provider} method. The first invocation of that method will locate + * the default provider as specified below. + * + * <p> All of the methods in this class are safe for use by multiple concurrent + * threads. </p> + * + * @since 1.7 + */ + +public abstract class AsynchronousChannelProvider { + private static Void checkPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("asynchronousChannelProvider")); + return null; + } + private AsynchronousChannelProvider(Void ignore) { } + + /** + * Initializes a new instance of this class. + * + * @throws SecurityException + * If a security manager has been installed and it denies + * {@link RuntimePermission}<tt>("asynchronousChannelProvider")</tt> + */ + protected AsynchronousChannelProvider() { + this(checkPermission()); + } + + // lazy initialization of default provider + private static class ProviderHolder { + static final AsynchronousChannelProvider provider = load(); + + private static AsynchronousChannelProvider load() { + return AccessController + .doPrivileged(new PrivilegedAction<AsynchronousChannelProvider>() { + public AsynchronousChannelProvider run() { + AsynchronousChannelProvider p; + p = loadProviderFromProperty(); + if (p != null) + return p; + p = loadProviderAsService(); + if (p != null) + return p; + return sun.nio.ch.DefaultAsynchronousChannelProvider.create(); + }}); + } + + private static AsynchronousChannelProvider loadProviderFromProperty() { + String cn = System.getProperty("java.nio.channels.spi.AsynchronousChannelProvider"); + if (cn == null) + return null; + try { + Class<?> c = Class.forName(cn, true, + ClassLoader.getSystemClassLoader()); + return (AsynchronousChannelProvider)c.newInstance(); + } catch (ClassNotFoundException x) { + throw new ServiceConfigurationError(null, x); + } catch (IllegalAccessException x) { + throw new ServiceConfigurationError(null, x); + } catch (InstantiationException x) { + throw new ServiceConfigurationError(null, x); + } catch (SecurityException x) { + throw new ServiceConfigurationError(null, x); + } + } + + private static AsynchronousChannelProvider loadProviderAsService() { + ServiceLoader<AsynchronousChannelProvider> sl = + ServiceLoader.load(AsynchronousChannelProvider.class, + ClassLoader.getSystemClassLoader()); + Iterator<AsynchronousChannelProvider> i = sl.iterator(); + for (;;) { + try { + return (i.hasNext()) ? i.next() : null; + } catch (ServiceConfigurationError sce) { + if (sce.getCause() instanceof SecurityException) { + // Ignore the security exception, try the next provider + continue; + } + throw sce; + } + } + } + } + + /** + * Returns the system-wide default asynchronous channel provider for this + * invocation of the Java virtual machine. + * + * <p> The first invocation of this method locates the default provider + * object as follows: </p> + * + * <ol> + * + * <li><p> If the system property + * <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> is defined + * then it is taken to be the fully-qualified name of a concrete provider class. + * The class is loaded and instantiated; if this process fails then an + * unspecified error is thrown. </p></li> + * + * <li><p> If a provider class has been installed in a jar file that is + * visible to the system class loader, and that jar file contains a + * provider-configuration file named + * <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> in the resource + * directory <tt>META-INF/services</tt>, then the first class name + * specified in that file is taken. The class is loaded and + * instantiated; if this process fails then an unspecified error is + * thrown. </p></li> + * + * <li><p> Finally, if no provider has been specified by any of the above + * means then the system-default provider class is instantiated and the + * result is returned. </p></li> + * + * </ol> + * + * <p> Subsequent invocations of this method return the provider that was + * returned by the first invocation. </p> + * + * @return The system-wide default AsynchronousChannel provider + */ + public static AsynchronousChannelProvider provider() { + return ProviderHolder.provider; + } + + /** + * Constructs a new asynchronous channel group with a fixed thread pool. + * + * @param nThreads + * The number of threads in the pool + * @param threadFactory + * The factory to use when creating new threads + * + * @throws IllegalArgumentException + * If {@code nThreads <= 0} + * @throws IOException + * If an I/O error occurs + * + * @see AsynchronousChannelGroup#withFixedThreadPool + */ + public abstract AsynchronousChannelGroup + openAsynchronousChannelGroup(int nThreads, ThreadFactory threadFactory) throws IOException; + + /** + * Constructs a new asynchronous channel group with the given thread pool. + * + * @param executor + * The thread pool + * @param initialSize + * A value {@code >=0} or a negative value for implementation + * specific default + * + * @throws IOException + * If an I/O error occurs + * + * @see AsynchronousChannelGroup#withCachedThreadPool + */ + public abstract AsynchronousChannelGroup + openAsynchronousChannelGroup(ExecutorService executor, int initialSize) throws IOException; + + /** + * Opens an asynchronous server-socket channel. + * + * @param group + * The group to which the channel is bound, or {@code null} to + * bind to the default group + * + * @return The new channel + * + * @throws IllegalChannelGroupException + * If the provider that created the group differs from this provider + * @throws ShutdownChannelGroupException + * The group is shutdown + * @throws IOException + * If an I/O error occurs + */ + public abstract AsynchronousServerSocketChannel openAsynchronousServerSocketChannel + (AsynchronousChannelGroup group) throws IOException; + + /** + * Opens an asynchronous socket channel. + * + * @param group + * The group to which the channel is bound, or {@code null} to + * bind to the default group + * + * @return The new channel + * + * @throws IllegalChannelGroupException + * If the provider that created the group differs from this provider + * @throws ShutdownChannelGroupException + * The group is shutdown + * @throws IOException + * If an I/O error occurs + */ + public abstract AsynchronousSocketChannel openAsynchronousSocketChannel + (AsynchronousChannelGroup group) throws IOException; + + /** + * Opens an asynchronous datagram channel. + * + * @param family + * The protocol family, or {@code null} for the default protocol + * family + * @param group + * The group to which the channel is bound, or {@code null} to + * bind to the default group + * + * @return The new channel + * + * @throws IllegalChannelGroupException + * If the provider that created the group differs from this provider + * @throws ShutdownChannelGroupException + * The group is shutdown + * @throws IOException + * If an I/O error occurs + */ + public abstract AsynchronousDatagramChannel openAsynchronousDatagramChannel + (ProtocolFamily family, AsynchronousChannelGroup group) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java b/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java index dc61c9c270a..d03800e22f3 100644 --- a/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java +++ b/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,8 +89,8 @@ public abstract class SelectorProvider { if (cn == null) return false; try { - Class c = Class.forName(cn, true, - ClassLoader.getSystemClassLoader()); + Class<?> c = Class.forName(cn, true, + ClassLoader.getSystemClassLoader()); provider = (SelectorProvider)c.newInstance(); return true; } catch (ClassNotFoundException x) { diff --git a/jdk/src/share/classes/java/nio/channels/spi/package.html b/jdk/src/share/classes/java/nio/channels/spi/package.html index 5b3ddd299f9..5960da38e82 100644 --- a/jdk/src/share/classes/java/nio/channels/spi/package.html +++ b/jdk/src/share/classes/java/nio/channels/spi/package.html @@ -1,5 +1,5 @@ <!-- - Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. + Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,8 @@ Service-provider classes for the <tt>{@link java.nio.channels}</tt> package. -<p> Only developers who are defining new selector providers should need to make -direct use of this package. </p> +<p> Only developers who are defining new selector providers or asynchronous +channel providers should need to make direct use of this package. </p> <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor or method in any class or interface in this package will cause a {@link diff --git a/jdk/src/share/classes/java/nio/file/AccessDeniedException.java b/jdk/src/share/classes/java/nio/file/AccessDeniedException.java new file mode 100644 index 00000000000..82a4fd2d54e --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/AccessDeniedException.java @@ -0,0 +1,68 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Checked exception thrown when a file system operation is denied, typically + * due to a file permission or other access check. + * + * <p> This exception is not related to the {@link + * java.security.AccessControlException AccessControlException} or {@link + * SecurityException} thrown by access controllers or security managers when + * access to a file is denied. + * + * @since 1.7 + */ + +public class AccessDeniedException + extends FileSystemException +{ + private static final long serialVersionUID = 4943049599949219617L; + + /** + * Constructs an instance of this class. + * + * @param file + * a string identifying the file or {@code null} if not known + */ + public AccessDeniedException(String file) { + super(file); + } + + /** + * Constructs an instance of this class. + * + * @param file + * a string identifying the file or {@code null} if not known + * @param other + * a string identifying the other file or {@code null} if not known + * @param reason + * a reason message with additional information or {@code null} + */ + public AccessDeniedException(String file, String other, String reason) { + super(file, other, reason); + } +} diff --git a/jdk/src/share/classes/java/nio/file/AccessMode.java b/jdk/src/share/classes/java/nio/file/AccessMode.java new file mode 100644 index 00000000000..240837681ee --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/AccessMode.java @@ -0,0 +1,49 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Defines access modes used to test the accessibility of a file. + * + * @since 1.7 + * + * @see FileRef#checkAccess + */ + +public enum AccessMode { + /** + * Test read access. + */ + READ, + /** + * Test write access. + */ + WRITE, + /** + * Test execute access. + */ + EXECUTE; +} diff --git a/jdk/src/share/classes/java/nio/file/AtomicMoveNotSupportedException.java b/jdk/src/share/classes/java/nio/file/AtomicMoveNotSupportedException.java new file mode 100644 index 00000000000..503d24c2e91 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/AtomicMoveNotSupportedException.java @@ -0,0 +1,56 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Checked exception thrown when a file cannot be moved as an atomic file system + * operation. + * + * @since 1.7 + */ + +public class AtomicMoveNotSupportedException + extends FileSystemException +{ + static final long serialVersionUID = 5402760225333135579L; + + /** + * Constructs an instance of this class. + * + * @param source + * a string identifying the source file or {@code null} if not known + * @param target + * a string identifying the target file or {@code null} if not known + * @param reason + * a reason message with additional information + */ + public AtomicMoveNotSupportedException(String source, + String target, + String reason) + { + super(source, target, reason); + } +} diff --git a/jdk/src/share/classes/java/nio/file/ClosedDirectoryStreamException.java b/jdk/src/share/classes/java/nio/file/ClosedDirectoryStreamException.java new file mode 100644 index 00000000000..f938776d1d1 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/ClosedDirectoryStreamException.java @@ -0,0 +1,45 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Unchecked exception thrown when an attempt is made to invoke an operation on + * a directory stream that is closed. + * + * @since 1.7 + */ + +public class ClosedDirectoryStreamException + extends IllegalStateException +{ + static final long serialVersionUID = 4228386650900895400L; + + /** + * Constructs an instance of this class. + */ + public ClosedDirectoryStreamException() { + } +} diff --git a/jdk/src/share/classes/java/nio/file/ClosedFileSystemException.java b/jdk/src/share/classes/java/nio/file/ClosedFileSystemException.java new file mode 100644 index 00000000000..fcd720a860a --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/ClosedFileSystemException.java @@ -0,0 +1,43 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Unchecked exception thrown when an attempt is made to invoke an operation on + * a file and the file system is closed. + */ + +public class ClosedFileSystemException + extends IllegalStateException +{ + static final long serialVersionUID = -8158336077256193488L; + + /** + * Constructs an instance of this class. + */ + public ClosedFileSystemException() { + } +} diff --git a/jdk/src/share/classes/java/nio/file/ClosedWatchServiceException.java b/jdk/src/share/classes/java/nio/file/ClosedWatchServiceException.java new file mode 100644 index 00000000000..662d0b6aca7 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/ClosedWatchServiceException.java @@ -0,0 +1,43 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Unchecked exception thrown when an attempt is made to invoke an operation on + * a watch service that is closed. + */ + +public class ClosedWatchServiceException + extends IllegalStateException +{ + static final long serialVersionUID = 1853336266231677732L; + + /** + * Constructs an instance of this class. + */ + public ClosedWatchServiceException() { + } +} diff --git a/jdk/src/share/classes/java/nio/file/CopyOption.java b/jdk/src/share/classes/java/nio/file/CopyOption.java new file mode 100644 index 00000000000..24534741fe3 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/CopyOption.java @@ -0,0 +1,41 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * An object that configures how to copy or move a file. + * + * <p> Objects of this type may be used with the {@link Path#copyTo copyTo} and + * {@link Path#moveTo moveTo} methods to configure how a file is copied or moved. + * + * <p> The {@link StandardCopyOption} enumeration type defines the + * <i>standard</i> options. + * + * @since 1.7 + */ + +public interface CopyOption { +} diff --git a/jdk/src/share/classes/java/nio/file/DirectoryNotEmptyException.java b/jdk/src/share/classes/java/nio/file/DirectoryNotEmptyException.java new file mode 100644 index 00000000000..482b476410d --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/DirectoryNotEmptyException.java @@ -0,0 +1,49 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Checked exception thrown when a file system operation fails because a + * directory is not empty. + * + * @since 1.7 + */ + +public class DirectoryNotEmptyException + extends FileSystemException +{ + static final long serialVersionUID = 3056667871802779003L; + + /** + * Constructs an instance of this class. + * + * @param dir + * a string identifying the directory or {@code null} if not known + */ + public DirectoryNotEmptyException(String dir) { + super(dir); + } +} diff --git a/jdk/src/share/classes/java/nio/file/DirectoryStream.java b/jdk/src/share/classes/java/nio/file/DirectoryStream.java new file mode 100644 index 00000000000..589d7b4f5e9 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/DirectoryStream.java @@ -0,0 +1,138 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.util.Iterator; +import java.io.Closeable; + +/** + * An object to iterate over the entries in a directory. A directory stream + * allows for convenient use of the for-each construct: + * <pre> + * Path dir = ... + * DirectoryStream<Path> stream = dir.newDirectoryStream(); + * try { + * for (Path entry: stream) { + * .. + * } + * } finally { + * stream.close(); + * } + * </pre> + * + * <p><b> A {@code DirectoryStream} is not a general-purpose {@code Iterable}. + * While this interface extends {@code Iterable}, the {@code iterator} method + * may only be invoked once to obtain the iterator; a second, or subsequent, + * call to the {@code iterator} method throws {@code IllegalStateException}. </b> + * + * <p> A {@code DirectoryStream} is opened upon creation and is closed by + * invoking the {@link #close close} method. Closing the directory stream + * releases any resources associated with the stream. The {@link + * Files#withDirectory Files.withDirectory} utility method is useful for cases + * where a task is performed on entries in a directory. This method automatically + * closes the directory stream when iteration is complete (or an error occurs). + * Once a directory stream is closed, all further method invocations on the + * iterator throw {@link java.util.concurrent.ConcurrentModificationException} + * with cause {@link ClosedDirectoryStreamException}. + * + * <p> A directory stream is not required to be <i>asynchronously closeable</i>. + * If a thread is blocked on the directory stream's iterator reading from the + * directory, and another thread invokes the {@code close} method, then the + * second thread may block until the read operation is complete. + * + * <p> The {@link Iterator#hasNext() hasNext} and {@link Iterator#next() next} + * methods can encounter an I/O error when iterating over the directory in which + * case {@code ConcurrentModificationException} is thrown with cause + * {@link java.io.IOException}. The {@code hasNext} method is guaranteed to + * read-ahead by at least one element. This means that if the {@code hasNext} + * method returns {@code true} and is followed by a call to the {@code next} + * method then it is guaranteed not to fail with a {@code + * ConcurrentModificationException}. + * + * <p> The elements returned by the iterator are in no specific order. Some file + * systems maintain special links to the directory itself and the directory's + * parent directory. Entries representing these links are not returned by the + * iterator. + * + * <p> The iterator's {@link Iterator#remove() remove} method removes the + * directory entry for the last element returned by the iterator, as if by + * invoking the {@link FileRef#delete delete} method. If an I/O error or + * security exception occurs then {@code ConcurrentModificationException} is + * thrown with the cause. + * + * <p> The iterator is <i>weakly consistent</i>. It is thread safe but does not + * freeze the directory while iterating, so it may (or may not) reflect updates + * to the directory that occur after the {@code DirectoryStream} is created. + * + * @param <T> The type of element returned by the iterator + * + * @since 1.7 + * + * @see Path#newDirectoryStream + */ + +public interface DirectoryStream<T> + extends Closeable, Iterable<T> +{ + /** + * An interface that is implemented by objects that decide if a directory + * entry should be accepted or filtered. A {@code Filter} is passed as the + * parameter to the {@link Path#newDirectoryStream(DirectoryStream.Filter) + * newDirectoryStream} method when opening a directory to iterate over the + * entries in the directory. + * + * <p> The {@link DirectoryStreamFilters} class defines factory methods to + * create filters for a number of common usages and also methods to combine + * filters. + * + * @param <T> the type of the directory entry + * + * @since 1.7 + */ + public static interface Filter<T> { + /** + * Decides if the given directory entry should be accepted or filtered. + * + * @param entry + * the directory entry to be tested + * + * @return {@code true} if the directory entry should be accepted + */ + boolean accept(T entry); + } + + /** + * Returns the iterator associated with this {@code DirectoryStream}. + * + * @return the iterator associated with this {@code DirectoryStream} + * + * @throws IllegalStateException + * if this directory stream is closed or the iterator has already + * been returned + */ + @Override + Iterator<T> iterator(); +} diff --git a/jdk/src/share/classes/java/nio/file/DirectoryStreamFilters.java b/jdk/src/share/classes/java/nio/file/DirectoryStreamFilters.java new file mode 100644 index 00000000000..b582bbf93bc --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/DirectoryStreamFilters.java @@ -0,0 +1,210 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.io.IOException; +import java.io.IOError; +import sun.nio.fs.MimeType; + +/** + * This class consists exclusively of static methods that construct or combine + * filters. + * + * @since 1.7 + */ + +public final class DirectoryStreamFilters { + private DirectoryStreamFilters() { } + + /** + * Constructs a directory stream filter that filters directory entries by + * their <a href="http://www.ietf.org/rfc/rfc2045.txt">MIME</a> content + * type. The directory stream filter's {@link + * java.nio.file.DirectoryStream.Filter#accept accept} method returns {@code + * true} if the content type of the directory entry can be determined by + * invoking the {@link Files#probeContentType probeContentType} method, and + * the content type matches the given content type. + * + * <p> The {@code type} parameter is the value of a Multipurpose Internet + * Mail Extension (MIME) content type as defined by <a + * href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC 2045: Multipurpose + * Internet Mail Extensions (MIME) Part One: Format of Internet Message + * Bodies</i></a>. It is parsable according to the grammar in the RFC. Any + * space characters (<code>'\u0020'</code>) surrounding its components are + * ignored. The {@code type} parameter is parsed into its primary and subtype + * components which are used to match the primary and subtype components of + * each directory entry's content type. Parameters are not allowed. The + * primary type matches if it has value {@code '*'} or is equal to the + * primary type of the directory entry's content type without regard to + * case. The subtype matches if has the value {@code '*'} or is equal to the + * subtype of the directory entry's content type without regard to case. If + * both the primary and subtype match then the filter's {@code accept} method + * returns {@code true}. If the content type of a directory entry cannot be + * determined then the entry is filtered. + * + * <p> The {@code accept} method of the resulting directory stream filter + * throws {@link IOError} if the probing of the content type fails by + * throwing an {@link IOException}. Security exceptions are also propogated + * to the caller of the {@code accept} method. + * + * <p> <b>Usage Example:</b> + * Suppose we require to list only the HTML files in a directory. + * <pre> + * DirectoryStream.Filter<FileRef> filter = + * DirectoryStreamFilters.newContentTypeFilter("text/html"); + * </pre> + * + * @param type + * the content type + * + * @return a new directory stream filter + * + * @throws IllegalArgumentException + * if the {@code type} parameter cannot be parsed as a MIME type + * or it has parameters + */ + public static <T extends FileRef> DirectoryStream.Filter<T> + newContentTypeFilter(String type) + { + final MimeType matchType = MimeType.parse(type); + if (matchType.hasParameters()) + throw new IllegalArgumentException("Parameters not allowed"); + return new DirectoryStream.Filter<T>() { + @Override + public boolean accept(T entry) { + String fileType; + try { + fileType = Files.probeContentType(entry); + } catch (IOException x) { + throw new IOError(x); + } + if (fileType != null) { + return matchType.match(fileType); + } + return false; + } + }; + } + + /** + * Returns a directory stream filter that {@link DirectoryStream.Filter#accept + * accepts} a directory entry if the entry is accepted by all of the given + * filters. + * + * <p> This method returns a filter that invokes, in iterator order, the + * {@code accept} method of each of the filters. If {@code false} is returned + * by any of the filters then the directory entry is filtered. If the + * directory entry is not filtered then the resulting filter accepts the + * entry. If the iterator returns zero elements then the resulting filter + * accepts all directory entries. + * + * <p> <b>Usage Example:</b> + * <pre> + * List<DirectoryStream.Filter<? super Path>> filters = ... + * DirectoryStream.Filter<Path> filter = DirectoryStreamFilters.allOf(filters); + * </pre> + * + * @param filters + * the sequence of filters + * + * @return the resulting filter + */ + public static <T> DirectoryStream.Filter<T> + allOf(final Iterable<? extends DirectoryStream.Filter<? super T>> filters) + { + if (filters == null) + throw new NullPointerException("'filters' is null"); + return new DirectoryStream.Filter<T>() { + @Override + public boolean accept(T entry) { + for (DirectoryStream.Filter<? super T> filter: filters) { + if (!filter.accept(entry)) + return false; + } + return true; + } + }; + } + + /** + * Returns a directory stream filter that {@link DirectoryStream.Filter#accept + * accepts} a directory entry if the entry is accepted by one or more of + * the given filters. + * + * <p> This method returns a filter that invokes, in iteration order, the + * {@code accept} method of each of filter. If {@code true} is returned by + * any of the filters then the directory entry is accepted. If none of the + * filters accepts the directory entry then it is filtered. If the iterator + * returns zero elements then the resulting filter filters all directory + * entries. + * + * @param filters + * the sequence of filters + * + * @return the resulting filter + */ + public static <T> DirectoryStream.Filter<T> + anyOf(final Iterable<? extends DirectoryStream.Filter<? super T>> filters) + { + if (filters == null) + throw new NullPointerException("'filters' is null"); + return new DirectoryStream.Filter<T>() { + @Override + public boolean accept(T entry) { + for (DirectoryStream.Filter<? super T> filter: filters) { + if (filter.accept(entry)) + return true; + } + return false; + } + }; + } + + /** + * Returns a directory stream filter that is the <em>complement</em> of the + * given filter. The resulting filter {@link + * java.nio.file.DirectoryStream.Filter#accept accepts} a directory entry + * if filtered by the given filter, and filters any entries that are accepted + * by the given filter. + * + * @param filter + * the given filter + * + * @return the resulting filter that is the complement of the given filter + */ + public static <T> DirectoryStream.Filter<T> + complementOf(final DirectoryStream.Filter<T> filter) + { + if (filter == null) + throw new NullPointerException("'filter' is null"); + return new DirectoryStream.Filter<T>() { + @Override + public boolean accept(T entry) { + return !filter.accept(entry); + } + }; + } +} diff --git a/jdk/src/share/classes/java/nio/file/FileAction.java b/jdk/src/share/classes/java/nio/file/FileAction.java new file mode 100644 index 00000000000..58088c2f814 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileAction.java @@ -0,0 +1,64 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.io.IOException; + +/** + * An interface that is implemented by objects that operate on a file. An + * implementation of this interface is provided to the {@link Files#withDirectory + * withDirectory} utility method so that the file action is {@link #invoke + * invoked} for all accepted entries in the directory, after which, the directory + * is automatically closed. + * + * <p> <b>Usage Example:</b> + * Suppose we require to perform a task on all class files in a directory: + * <pre> + * Path dir = ... + * Files.withDirectory(dir, "*.class", new FileAction<Path>() { + * public void invoke(Path entry) { + * : + * } + * }); + * </pre> + * + * @param <T> the type of file reference + * + * @since 1.7 + */ + +public interface FileAction<T extends FileRef> { + /** + * Invoked for a file. + * + * @param file + * the file + * + * @throws IOException + * if the block terminates due an uncaught I/O exception + */ + void invoke(T file) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/FileAlreadyExistsException.java b/jdk/src/share/classes/java/nio/file/FileAlreadyExistsException.java new file mode 100644 index 00000000000..ff60e6371d1 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileAlreadyExistsException.java @@ -0,0 +1,63 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Checked exception thrown when an attempt is made to create a file or + * directory and a file of that name already exists. + * + * @since 1.7 + */ + +public class FileAlreadyExistsException + extends FileSystemException +{ + static final long serialVersionUID = 7579540934498831181L; + + /** + * Constructs an instance of this class. + * + * @param file + * a string identifying the file or {@code null} if not known + */ + public FileAlreadyExistsException(String file) { + super(file); + } + + /** + * Constructs an instance of this class. + * + * @param file + * a string identifying the file or {@code null} if not known + * @param other + * a string identifying the other file or {@code null} if not known + * @param reason + * a reason message with additional information or {@code null} + */ + public FileAlreadyExistsException(String file, String other, String reason) { + super(file, other, reason); + } +} diff --git a/jdk/src/share/classes/java/nio/file/FileRef.java b/jdk/src/share/classes/java/nio/file/FileRef.java new file mode 100644 index 00000000000..2606a879c75 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileRef.java @@ -0,0 +1,424 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.attribute.*; +import java.nio.channels.SeekableByteChannel; +import java.io.IOException; + +/** + * A reference to a file. + * + * <p> A {@code FileRef} is an object that locates a file and defines methods to + * access the file. The means by which the file is located depends on the + * implementation. In many cases, a file is located by a {@link Path} but it may + * be located by other means such as a file-system identifier. + * + * <p> This interface defines the following operations: + * <ul> + * <li><p> The {@link #newByteChannel newByteChannel} method + * may be used to open a file and obtain a byte channel for reading or + * writing. </p></li> + * <li><p> The {@link #delete delete} method may be used to delete a file. + * </p></li> + * <li><p> The {@link #checkAccess checkAccess} method may be used to check + * the existence or accessibility of a file. </p></li> + * <li><p> The {@link #isSameFile isSameFile} method may be used to test if + * two file references locate the same file. </p></li> + * <li><p> The {@link #getFileStore getFileStore} method may be used to + * obtain the {@link FileStore} representing the storage where a file is + * located. </p></li> + * </ul> + * + * <p> Access to associated metadata or file attributes requires an appropriate + * {@link FileAttributeView FileAttributeView}. The {@link + * #getFileAttributeView(Class,LinkOption[]) getFileAttributeView(Class,LinkOption[])} + * method may be used to obtain a file attribute view that defines type-safe + * methods to read or update file attributes. The {@link + * #getFileAttributeView(String,LinkOption[]) getFileAttributeView(String,LinkOption[])} + * method may be used to obtain a file attribute view where dynamic access to + * file attributes where required. + * + * <p> A {@code FileRef} is immutable and safe for use by multiple concurrent + * threads. + * + * @since 1.7 + */ + +public interface FileRef { + + /** + * Opens the file referenced by this object, returning a seekable byte + * channel to access the file. + * + * <p> The {@code options} parameter determines how the file is opened. + * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE + * WRITE} options determine if the file should be opened for reading and/or + * writing. If neither option (or the {@link StandardOpenOption#APPEND APPEND} + * option) is contained in the array then the file is opened for reading. + * By default reading or writing commences at the beginning of the file. + * + * <p> In the addition to {@code READ} and {@code WRITE}, the following + * options may be present: + * + * <table border=1 cellpadding=5 summary=""> + * <tr> <th>Option</th> <th>Description</th> </tr> + * <tr> + * <td> {@link StandardOpenOption#APPEND APPEND} </td> + * <td> If this option is present then the file is opened for writing and + * each invocation of the channel's {@code write} method first advances + * the position to the end of the file and then writes the requested + * data. Whether the advancement of the position and the writing of the + * data are done in a single atomic operation is system-dependent and + * therefore unspecified. This option may not be used in conjunction + * with the {@code READ} or {@code TRUNCATE_EXISTING} options. </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td> + * <td> If this option is present then the existing file is truncated to + * a size of 0 bytes. This option is ignored when the file is opened only + * for reading. </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#SYNC SYNC} </td> + * <td> Requires that every update to the file's content or metadata be + * written synchronously to the underlying storage device. (see <a + * href="package-summary.html#integrity"> Synchronized I/O file + * integrity</a>). </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#DSYNC DSYNC} </td> + * <td> Requires that every update to the file's content be written + * synchronously to the underlying storage device. (see <a + * href="package-summary.html#integrity"> Synchronized I/O file + * integrity</a>). </td> + * </tr> + * </table> + * + * <p> An implementation of this interface may support additional options + * defined by the {@link StandardOpenOption} enumeration type or other + * implementation specific options. + * + * <p> The {@link java.nio.channels.Channels} utility classes defines methods + * to construct input and output streams where inter-operation with the + * {@link java.io} package is required. + * + * @param options + * Options specifying how the file is opened + * + * @return a new seekable byte channel + * + * @throws IllegalArgumentException + * If an invalid combination of options is specified + * @throws UnsupportedOperationException + * If an unsupported open option is specified + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the path if the file is + * opened for reading. The {@link SecurityManager#checkWrite(String) + * checkWrite} method is invoked to check write access to the path + * if the file is opened for writing. + */ + SeekableByteChannel newByteChannel(OpenOption... options) + throws IOException; + + /** + * Returns the {@link FileStore} representing the file store where the file + * referenced by this object is stored. + * + * <p> Once a reference to the {@code FileStore} is obtained it is + * implementation specific if operations on the returned {@code FileStore}, + * or {@link FileStoreAttributeView} objects obtained from it, continue + * to depend on the existence of the file. In particular the behavior is not + * defined for the case that the file is deleted or moved to a different + * file store. + * + * @return The file store where the file is stored + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file, and in + * addition it checks {@link RuntimePermission}<tt> + * ("getFileStoreAttributes")</tt> + */ + FileStore getFileStore() throws IOException; + + /** + * Checks the existence and optionally the accessibility of the file + * referenced by this object. + * + * <p> This method checks the existence of a file and that this Java virtual + * machine has appropriate privileges that would allow it access the file + * according to all of access modes specified in the {@code modes} parameter + * as follows: + * + * <table border=1 cellpadding=5 summary=""> + * <tr> <th>Value</th> <th>Description</th> </tr> + * <tr> + * <td> {@link AccessMode#READ READ} </td> + * <td> Checks that the file exists and that the Java virtual machine has + * permission to read the file. </td> + * </tr> + * <tr> + * <td> {@link AccessMode#WRITE WRITE} </td> + * <td> Checks that the file exists and that the Java virtual machine has + * permission to write to the file, </td> + * </tr> + * <tr> + * <td> {@link AccessMode#EXECUTE EXECUTE} </td> + * <td> Checks that the file exists and that the Java virtual machine has + * permission to {@link Runtime#exec execute} the file. The semantics + * may differ when checking access to a directory. For example, on UNIX + * systems, checking for {@code EXECUTE} access checks that the Java + * virtual machine has permission to search the directory in order to + * access file or subdirectories. </td> + * </tr> + * </table> + * + * <p> If the {@code modes} parameter is of length zero, then the existence + * of the file is checked. + * + * <p> This method follows symbolic links if the file referenced by this + * object is a symbolic link. Depending on the implementation, this method + * may require to read file permissions, access control lists, or other + * file attributes in order to check the effective access to the file. To + * determine the effective access to a file may require access to several + * attributes and so in some implementations this method may not be atomic + * with respect to other file system operations. Furthermore, as the result + * of this method is immediately outdated, there is no guarantee that a + * subsequence access will succeed (or even that it will access the same + * file). Care should be taken when using this method in security sensitive + * applications. + * + * @param modes + * The access modes to check; may have zero elements + * + * @throws UnsupportedOperationException + * An implementation is required to support checking for + * {@code READ}, {@code WRITE}, and {@code EXECUTE} access. This + * exception is specified to allow for the {@code Access} enum to + * be extended in future releases. + * @throws NoSuchFileException + * If a file does not exist <i>(optional specific exception)</i> + * @throws AccessDeniedException + * The requested access would be denied or the access cannot be + * determined because the Java virtual machine has insufficient + * privileges or other reasons. <i>(optional specific exception)</i> + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * is invoked when checking read access to the file or only the + * existence of the file, the {@link SecurityManager#checkWrite(String) + * checkWrite} is invoked when checking write access to the file, + * and {@link SecurityManager#checkExec(String) checkExec} is invoked + * when checking execute access. + */ + void checkAccess(AccessMode... modes) throws IOException; + + /** + * Returns a file attribute view of a given type. + * + * <p> A file attribute view provides a read-only or updatable view of a + * set of file attributes. This method is intended to be used where the file + * attribute view defines type-safe methods to read or update the file + * attributes. The {@code type} parameter is the type of the attribute view + * required and the method returns an instance of that type if supported. + * The {@link BasicFileAttributeView} type supports access to the basic + * attributes of a file. Invoking this method to select a file attribute + * view of that type will always return an instance of that class. + * + * <p> The {@code options} array may be used to indicate how symbolic links + * are handled by the resulting file attribute view for the case that the + * file is a symbolic link. By default, symbolic links are followed. If the + * option {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} is present then + * symbolic links are not followed. This option is ignored by implementations + * that do not support symbolic links. + * + * @param type + * The {@code Class} object corresponding to the file attribute view + * @param options + * Options indicating how symbolic links are handled + * + * @return A file attribute view of the specified type, or {@code null} if + * the attribute view type is not available + * + * @throws UnsupportedOperationException + * If options contains an unsupported option. This exception is + * specified to allow the {@code LinkOption} enum be extended + * in future releases. + * + * @see Attributes#readBasicFileAttributes + */ + <V extends FileAttributeView> V getFileAttributeView(Class<V> type, LinkOption... options); + + /** + * Returns a file attribute view of the given name. + * + * <p> A file attribute view provides a read-only or updatable view of a + * set of file attributes. This method is intended to be used where + * <em>dynamic access</em> to the file attributes is required. The {@code + * name} parameter specifies the {@link FileAttributeView#name name} of the + * file attribute view and this method returns an instance of that view if + * supported. The {@link BasicFileAttributeView} type supports access to the + * basic attributes of a file and is name {@code "basic"}. Invoking this + * method to select a file attribute view named {@code "basic"} will always + * return an instance of that class. + * + * <p> The {@code options} array may be used to indicate how symbolic links + * are handled by the resulting file attribute view for the case that the + * file is a symbolic link. By default, symbolic links are followed. If the + * option {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} is present then + * symbolic links are not followed. This option is ignored by implementations + * that do not support symbolic links. + * + * @param name + * The name of the file attribute view + * @param options + * Options indicating how symbolic links are handled + * + * @return A file attribute view of the given name, or {@code null} if + * the attribute view is not available + * + * @throws UnsupportedOperationException + * If options contains an unsupported option. This exception is + * specified to allow the {@code LinkOption} enum be extended + * in future releases. + */ + FileAttributeView getFileAttributeView(String name, LinkOption... options); + + /** + * Tests if the file referenced by this object is the same file referenced + * by another object. + * + * <p> If this {@code FileRef} and the given {@code FileRef} are {@link + * #equals(Object) equal} then this method returns {@code true} without checking + * if the file exists. If the {@code FileRef} and the given {@code FileRef} + * are associated with different providers, or the given {@code FileRef} is + * {@code null} then this method returns {@code false}. Otherwise, this method + * checks if both {@code FileRefs} locate the same file, and depending on the + * implementation, may require to open or access both files. + * + * <p> If the file system and files remain static, then this method implements + * an equivalence relation for non-null {@code FileRefs}. + * <ul> + * <li>It is <i>reflexive</i>: for a non-null {@code FileRef} {@code f}, + * {@code f.isSameFile(f)} should return {@code true}. + * <li>It is <i>symmetric</i>: for two non-null {@code FileRefs} + * {@code f} and {@code g}, {@code f.isSameFile(g)} will equal + * {@code g.isSameFile(f)}. + * <li>It is <i>transitive</i>: for three {@code FileRefs} + * {@code f}, {@code g}, and {@code h}, if {@code f.isSameFile(g)} returns + * {@code true} and {@code g.isSameFile(h)} returns {@code true}, then + * {@code f.isSameFile(h)} will return return {@code true}. + * </ul> + * + * @param other + * The other file reference + * + * @return {@code true} if, and only if, this object and the given object + * locate the same file + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to both files. + * + * @see java.nio.file.attribute.BasicFileAttributes#fileKey + */ + boolean isSameFile(FileRef other) throws IOException; + + /** + * Deletes the file referenced by this object. + * + * <p> An implementation may require to examine the file to determine if the + * file is a directory. Consequently this method may not be atomic with respect + * to other file system operations. If the file is a symbolic-link then the + * link is deleted and not the final target of the link. + * + * <p> If the file is a directory then the directory must be empty. In some + * implementations a directory has entries for special files or links that + * are created when the directory is created. In such implementations a + * directory is considered empty when only the special entries exist. + * + * <p> On some operating systems it may not be possible to remove a file when + * it is open and in use by this Java virtual machine or other programs. + * + * @throws NoSuchFileException + * If the file does not exist <i>(optional specific exception)</i> + * @throws DirectoryNotEmptyException + * If the file is a directory and could not otherwise be deleted + * because the directory is not empty <i>(optional specific + * exception)</i> + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkDelete(String)} method + * is invoked to check delete access to the file + */ + void delete() throws IOException; + + /** + * Tests this object for equality with another object. + * + * <p> If the given object is not a {@code FileRef} then this method + * immediately returns {@code false}. + * + * <p> For two file references to be considered equal requires that they + * are both the same type of {@code FileRef} and encapsulate components + * to locate the same file. This method does not access the file system and + * the file may not exist. + * + * <p> This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method. </p> + * + * @param ob The object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a {@code FileRef} + * that is identical to this {@code FileRef} + * + * @see #isSameFile + */ + boolean equals(Object ob); + + /** + * Returns the hash-code value for this object. + * + * <p> This method satisfies the general contract of the + * {@link java.lang.Object#hashCode() Object.hashCode} method. + */ + int hashCode(); +} diff --git a/jdk/src/share/classes/java/nio/file/FileStore.java b/jdk/src/share/classes/java/nio/file/FileStore.java new file mode 100644 index 00000000000..3f8df103129 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileStore.java @@ -0,0 +1,169 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.attribute.*; + +/** + * Storage for files. A {@code FileStore} represents a storage pool, device, + * partition, volume, concrete file system or other implementation specific means + * of file storage. The {@code FileStore} for where a file is stored is obtained + * by invoking the {@link FileRef#getFileStore getFileStore} method, or all file + * stores can be enumerated by invoking the {@link FileSystem#getFileStores + * getFileStores} method. + * + * <p> In addition to the methods defined by this class, a file store may support + * one or more {@link FileStoreAttributeView FileStoreAttributeView} classes + * that provide a read-only or updatable view of a set of file store attributes. + * File stores associated with the default provider support the {@link + * FileStoreSpaceAttributeView} to read the space related attributes of the + * file store. + * + * @since 1.7 + */ + +public abstract class FileStore { + + /** + * Initializes a new instance of this class. + */ + protected FileStore() { + } + + /** + * Returns the name of this file store. The format of the name is highly + * implementation specific. It will typically be the name of the storage + * pool or volume. + * + * <p> The string returned by this method may differ from the string + * returned by the {@link Object#toString() toString} method. + * + * @return the name of this file store + */ + public abstract String name(); + + /** + * Returns the <em>type</em> of this file store. The format of the string + * returned by this method is highly implementation specific. It may + * indicate, for example, the format used or if the file store is local + * or remote. + * + * @return a string representing the type of this file store + */ + public abstract String type(); + + /** + * Tells whether this file store is read-only. A file store is read-only if + * it does not support write operations or other changes to files. Any + * attempt to create a file, open an existing file for writing etc. causes + * an {@code IOException} to be thrown. + * + * @return {@code true} if, and only if, this file store is read-only + */ + public abstract boolean isReadOnly(); + + /** + * Tells whether or not this file store supports the file attributes + * identified by the given file attribute view. + * + * <p> Invoking this method to test if the file store supports {@link + * BasicFileAttributeView} will always return {@code true}. In the case of + * the default provider, this method cannot guarantee to give the correct + * result when the file store is not a local storage device. The reasons for + * this are implementation specific and therefore unspecified. + * + * @param type + * the file attribute view type + * + * @return {@code true} if, and only if, the file attribute view is + * supported + */ + public abstract boolean supportsFileAttributeView(Class<? extends FileAttributeView> type); + + /** + * Tells whether or not this file store supports the file attributes + * identified by the given file attribute view. + * + * <p> Invoking this method to test if the file store supports {@link + * BasicFileAttributeView}, identified by the name "{@code basic}" will + * always return {@code true}. In the case of the default provider, this + * method cannot guarantee to give the correct result when the file store is + * not a local storage device. The reasons for this are implementation + * specific and therefore unspecified. + * + * @param name + * the {@link FileAttributeView#name name} of file attribute view + * + * @return {@code true} if, and only if, the file attribute view is + * supported + */ + public abstract boolean supportsFileAttributeView(String name); + + /** + * Returns a {@code FileStoreAttributeView} of the given type. + * + * <p> This method is intended to be used where the file store attribute + * view defines type-safe methods to read or update the file store attributes. + * The {@code type} parameter is the type of the attribute view required and + * the method returns an instance of that type if supported. + * + * <p> For {@code FileStore} objects created by the default provider, then + * the file stores support the {@link FileStoreSpaceAttributeView} that + * provides access to space attributes. In that case invoking this method + * with a parameter value of {@code FileStoreSpaceAttributeView.class} will + * always return an instance of that class. + * + * @param type + * the {@code Class} object corresponding to the attribute view + * + * @return a file store attribute view of the specified type or + * {@code null} if the attribute view is not available + */ + public abstract <V extends FileStoreAttributeView> V + getFileStoreAttributeView(Class<V> type); + + /** + * Returns a {@code FileStoreAttributeView} of the given name. + * + * <p> This method is intended to be used where <em>dynamic access</em> to + * file store attributes is required. The {@code name} parameter specifies + * the {@link FileAttributeView#name name} of the file store attribute view + * and this method returns an instance of that view if supported. + * + * <p> For {@code FileStore} objects created by the default provider, then + * the file stores support the {@link FileStoreSpaceAttributeView} that + * provides access to space attributes. In that case invoking this method + * with a parameter value of {@code "space"} will always return an instance + * of that class. + * + * @param name + * the name of the attribute view + * + * @return a file store attribute view of the given name, or {@code null} + * if the attribute view is not available + */ + public abstract FileStoreAttributeView getFileStoreAttributeView(String name); +} diff --git a/jdk/src/share/classes/java/nio/file/FileSystem.java b/jdk/src/share/classes/java/nio/file/FileSystem.java new file mode 100644 index 00000000000..b7cb063258a --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileSystem.java @@ -0,0 +1,453 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.attribute.*; +import java.nio.file.spi.FileSystemProvider; +import java.util.Set; +import java.io.Closeable; +import java.io.IOException; + +/** + * Provides an interface to a file system and is the factory for objects to + * access files and other objects in the file system. + * + * <p> The default file system, obtained by invoking the {@link FileSystems#getDefault + * FileSystems.getDefault} method, provides access to the file system that is + * accessible to the Java virtual machine. The {@link FileSystems} class defines + * methods to create file systems that provide access to other types of file + * systems. + * + * <p> A file system is the factory for several types of objects: + * + * <ul> + * <li><p> The {@link #getPath getPath} method converts a system dependent + * <em>path string</em>, returning a {@link Path} object that may be used + * to locate and access a file. </p></li> + * <li><p> The {@link #getPathMatcher getPathMatcher} method is used + * to create a {@link PathMatcher} that performs match operations on + * paths. </p></li> + * <li><p> The {@link #getFileStores getFileStores} method returns an iterator + * over the underlying {@link FileStore file-stores}. </p></li> + * <li><p> The {@link #getUserPrincipalLookupService getUserPrincipalLookupService} + * method returns the {@link UserPrincipalLookupService} to lookup users or + * groups by name. </p></li> + * <li><p> The {@link #newWatchService newWatchService} method creates a + * {@link WatchService} that may be used to watch objects for changes and + * events. </p></li> + * </ul> + * + * <p> File systems vary greatly. In some cases the file system is a single + * hierarchy of files with one top-level root directory. In other cases it may + * have several distinct file hierarchies, each with its own top-level root + * directory. The {@link #getRootDirectories getRootDirectories} method may be + * used to iterate over the root directories in the file system. A file system + * is typically composed of one or more underlying {@link FileStore file-stores} + * that provide the storage for the files. Theses file stores can also vary in + * the features they support, and the file attributes or <em>meta-data</em> that + * they associate with files. + * + * <p> A file system is open upon creation and can be closed by invoking its + * {@link #close() close} method. Once closed, any further attempt to access + * objects in the file system cause {@link ClosedFileSystemException} to be + * thrown. File systems created by the default {@link FileSystemProvider provider} + * cannot be closed. + * + * <p> A {@code FileSystem} can provide read-only or read-write access to the + * file system. Whether or not a file system provides read-only access is + * established when the {@code FileSystem} is created and can be tested by invoking + * its {@link #isReadOnly() isReadOnly} method. Attempts to write to file stores + * by means of an object associated with a read-only file system throws {@link + * ReadOnlyFileSystemException}. + * + * <p> File systems are safe for use by multiple concurrent threads. The {@link + * #close close} method may be invoked at any time to close a file system but + * whether a file system is <i>asynchronously closeable</i> is provider specific + * and therefore unspecified. In other words, if a thread is accessing an + * object in a file system, and another thread invokes the {@code close} method + * then it may require to block until the first operation is complete. Closing + * a file system causes all open channels, watch services, and other {@link + * Closeable closeable} objects associated with the file system to be closed. + * + * @since 1.7 + */ + +public abstract class FileSystem + implements Closeable +{ + /** + * Initializes a new instance of this class. + */ + protected FileSystem() { + } + + /** + * Returns the provider that created this file system. + * + * @return The provider that created this file system. + */ + public abstract FileSystemProvider provider(); + + /** + * Closes this file system. + * + * <p> After a file system is closed then all subsequent access to the file + * system, either by methods defined by this class or on objects associated + * with this file system, throw {@link ClosedFileSystemException}. If the + * file system is already closed then invoking this method has no effect. + * + * <p> Closing a file system will close all open {@link + * java.nio.channels.Channel channels}, {@link DirectoryStream directory-streams}, + * {@link WatchService watch-service}, and other closeable objects associated + * with this file system. The {@link FileSystems#getDefault default} file + * system cannot be closed. + * + * @throws IOException + * If an I/O error occurs + * @throws UnsupportedOperationException + * Thrown in the case of the default file system + */ + @Override + public abstract void close() throws IOException; + + /** + * Tells whether or not this file system is open. + * + * <p> File systems created by the default provider are always open. + * + * @return {@code true} if, and only if, this file system is open + */ + public abstract boolean isOpen(); + + /** + * Tells whether or not this file system allows only read-only access to + * its file stores. + * + * @return {@code true} if, and only if, this file system provides + * read-only access + */ + public abstract boolean isReadOnly(); + + /** + * Returns the name separator, represented as a string. + * + * <p> The name separator is used to separate names in a path string. An + * implementation may support multiple name separators in which case this + * method returns an implementation specific <em>default</em> name separator. + * This separator is used when creating path strings by invoking the {@link + * Path#toString() toString()} method. + * + * <p> In the case of the default provider, this method returns the same + * separator as {@link java.io.File#separator}. + * + * @return The name separator + */ + public abstract String getSeparator(); + + /** + * Returns an object to iterate over the paths of the root directories. + * + * <p> A file system provides access to a file store that may be composed + * of a number of distinct file hierarchies, each with its own top-level + * root directory. Unless denied by the security manager, each element in + * the returned iterator corresponds to the root directory of a distinct + * file hierarchy. The order of the elements is not defined. The file + * hierarchies may change during the lifetime of the Java virtual machine. + * For example, in some implementations, the insertion of removable media + * may result in the creation of a new file hierarchy with its own + * top-level directory. + * + * <p> When a security manager is installed, it is invoked to check access + * to the each root directory. If denied, the root directory is not returned + * by the iterator. In the case of the default provider, the {@link + * SecurityManager#checkRead(String)} method is invoked to check read access + * to each root directory. It is system dependent if the permission checks + * are done when the iterator is obtained or during iteration. + * + * @return An object to iterate over the root directories + */ + public abstract Iterable<Path> getRootDirectories(); + + /** + * Returns an object to iterate over the underlying file stores. + * + * <p> The elements of the returned iterator are the {@link + * FileStore FileStores} for this file system. The order of the elements is + * not defined and the file stores may change during the lifetime of the + * Java virtual machine. When an I/O error occurs, perhaps because a file + * store is not accessible, then it is not returned by the iterator. + * + * <p> In the case of the default provider, and a security manager is + * installed, the security manager is invoked to check {@link + * RuntimePermission}<tt>("getFileStoreAttributes")</tt>. If denied, then + * no file stores are returned by the iterator. In addition, the security + * manager's {@link SecurityManager#checkRead(String)} method is invoked to + * check read access to the file store's <em>top-most</em> directory. If + * denied, the file store is not returned by the iterator. It is system + * dependent if the permission checks are done when the iterator is obtained + * or during iteration. + * + * <p> <b>Usage Example:</b> + * Suppose we want to print the space usage for all file stores: + * <pre> + * for (FileStore store: FileSystems.getDefault().getFileStores()) { + * FileStoreSpaceAttributes attrs = Attributes.readFileStoreSpaceAttributes(store); + * long total = attrs.totalSpace() / 1024; + * long used = (attrs.totalSpace() - attrs.unallocatedSpace()) / 1024; + * long avail = attrs.usableSpace() / 1024; + * System.out.format("%-20s %12d %12d %12d%n", store, total, used, avail); + * } + * </pre> + * + * @return An object to iterate over the backing file stores + */ + public abstract Iterable<FileStore> getFileStores(); + + /** + * Returns the set of the {@link FileAttributeView#name names} of the file + * attribute views supported by this {@code FileSystem}. + * + * <p> The {@link BasicFileAttributeView} is required to be supported and + * therefore the set contains at least one element, "basic". + * + * <p> The {@link FileStore#supportsFileAttributeView(String) + * supportsFileAttributeView(String)} method may be used to test if an + * underlying {@link FileStore} supports the file attributes identified by a + * file attribute view. + * + * @return An unmodifiable set of the names of the supported file attribute + * views + */ + public abstract Set<String> supportedFileAttributeViews(); + + /** + * Converts a path string to a {@code Path}. + * + * <p> The parsing and conversion to a path object is inherently + * implementation dependent. In the simplest case, the path string is rejected, + * and {@link InvalidPathException} thrown, if the path string contains + * characters that cannot be converted to characters that are <em>legal</em> + * to the file store. For example, on UNIX systems, the NUL (\u0000) + * character is not allowed to be present in a path. An implementation may + * choose to reject path strings that contain names that are longer than those + * allowed by any file store, and where an implementation supports a complex + * path syntax, it may choose to reject path strings that are <em>badly + * formed</em>. + * + * <p> In the case of the default provider, path strings are parsed based + * on the definition of paths at the platform or virtual file system level. + * For example, an operating system may not allow specific characters to be + * present in a file name, but a specific underlying file store may impose + * different or additional restrictions on the set of legal + * characters. + * + * <p> This method throws {@link InvalidPathException} when the path string + * cannot be converted to a path. Where possible, and where applicable, + * the exception is created with an {@link InvalidPathException#getIndex + * index} value indicating the first position in the {@code path} parameter + * that caused the path string to be rejected. + * + * <p> Invoking this method with an empty path string throws + * {@code InvalidPathException}. + * + * @param path + * The path string + * + * @return A {@code Path} object + * + * @throws InvalidPathException + * If the path string cannot be converted + */ + public abstract Path getPath(String path); + + /** + * Returns a {@code PathMatcher} that performs match operations on the + * {@code String} representation of {@link Path} objects by interpreting a + * given pattern. + * + * The {@code syntaxAndPattern} parameter identifies the syntax and the + * pattern and takes the form: + * <blockquote> + * <i>syntax</i><b>:</b><i>pattern</i> + * </blockquote> + * where {@code ':'} stands for itself. + * + * <p> A {@code FileSystem} implementation supports the "{@code glob}" and + * "{@code regex}" syntaxes, and may support others. The value of the syntax + * component is compared without regard to case. + * + * <p> When the syntax is "{@code glob}" then the {@code String} + * representation of the path is matched using a limited pattern language + * that resembles regular expressions but with a simpler syntax. For example: + * + * <blockquote> + * <table border="0"> + * <tr> + * <td>{@code *.java}</td> + * <td>Matches a path that represents a file name ending in {@code .java}</td> + * </tr> + * <tr> + * <td>{@code *.*}</td> + * <td>Matches file names containing a dot</td> + * </tr> + * <tr> + * <tr> + * <td>{@code *.{java,class}}</td> + * <td>Matches file names ending with {@code .java} or {@code .class}</td> + * </tr> + * <tr> + * <td>{@code foo.?}</td> + * <td>Matches file names starting with {@code foo.} and a single + * character extension</td> + * </tr> + * <tr> + * <td><tt>/home/*/*</tt> + * <td>Matches <tt>/home/gus/data</tt> on UNIX platforms</td> + * </tr> + * <tr> + * <td><tt>/home/**</tt> + * <td>Matches <tt>/home/gus</tt> and + * <tt>/home/gus/data</tt> on UNIX platforms</td> + * </tr> + * <tr> + * <td><tt>C:\\*</tt> + * <td>Matches <tt>C:\foo</tt> and <tt>C:\bar</tt> on the Windows + * platform (note that the backslash is escaped; as a string literal in the + * Java Language the pattern would be <tt>"C:\\\\*"</tt>) </td> + * </tr> + * + * </table> + * </blockquote> + * + * <p> The following rules are used to interpret glob patterns: + * + * <p> <ul> + * <li><p> The {@code *} character matches zero or more {@link Character + * characters} of a {@link Path#getName(int) name} component without + * crossing directory boundaries. </p></li> + * + * <li><p> The {@code **} characters matches zero or more {@link Character + * characters} crossing directory boundaries. </p></li> + * + * <li><p> The {@code ?} character matches exactly one character of a + * name component.</p></li> + * + * <li><p> The backslash character ({@code \}) is used to escape characters + * that would otherwise be interpreted as special characters. The expression + * {@code \\} matches a single backslash and "\{" matches a left brace + * for example. </p></li> + * + * <li><p> The {@code [ ]} characters are a <i>bracket expression</i> that + * match a single character of a name component out of a set of characters. + * For example, {@code [abc]} matches {@code "a"}, {@code "b"}, or {@code "c"}. + * The hyphen ({@code -}) may be used to specify a range so {@code [a-z]} + * specifies a range that matches from {@code "a"} to {@code "z"} (inclusive). + * These forms can be mixed so [abce-g] matches {@code "a"}, {@code "b"}, + * {@code "c"}, {@code "e"}, {@code "f"} or {@code "g"}. If the character + * after the {@code [} is a {@code !} then it is used for negation so {@code + * [!a-c]} matches any character except {@code "a"}, {@code "b"}, or {@code + * "c"}. + * <p> Within a bracket expression the {@code *}, {@code ?} and {@code \} + * characters match themselves. The ({@code -}) character matches itself if + * it is the first character within the brackets, or the first character + * after the {@code !} if negating.</p></li> + * + * <li><p> The {@code { }} characters are a group of subpatterns, where + * the group matches if any subpattern in the group matches. The {@code ","} + * character is used to separate the subpatterns. Groups cannot be nested. + * </p></li> + * + * <li><p> All other characters match themselves in an implementation + * dependent manner. This includes characters representing any {@link + * FileSystem#getSeparator name-separators}. </p></li> + * + * <li><p> The matching of {@link Path#getRoot root} components is highly + * implementation-dependent and is not specified. </p></li> + * + * </ul> + * + * <p> When the syntax is "{@code regex}" then the pattern component is a + * regular expression as defined by the {@link java.util.regex.Pattern} + * class. + * + * <p> For both the glob and regex syntaxes, the matching details, such as + * whether the matching is case sensitive, are implementation-dependent + * and therefore not specified. + * + * @param syntaxAndPattern + * The syntax and pattern + * + * @return A path matcher that may be used to match paths against the pattern + * + * @throws IllegalArgumentException + * If the parameter does not take the form: {@code syntax:pattern} + * @throws java.util.regex.PatternSyntaxException + * If the pattern is invalid + * @throws UnsupportedOperationException + * If the pattern syntax is not known to the implementation + * + * @see Path#newDirectoryStream(String) + */ + public abstract PathMatcher getPathMatcher(String syntaxAndPattern); + + /** + * Returns the {@code UserPrincipalLookupService} for this file system + * <i>(optional operation)</i>. The resulting lookup service may be used to + * lookup user or group names. + * + * <p> <b>Usage Example:</b> + * Suppose we want to make "joe" the owner of a file: + * <pre> + * Path file = ... + * UserPrincipal joe = file.getFileSystem().getUserPrincipalLookupService() + * .lookupPrincipalByName("joe"); + * Attributes.setOwner(file, joe); + * </pre> + * + * @throws UnsupportedOperationException + * If this {@code FileSystem} does not does have a lookup service + * + * @return The {@code UserPrincipalLookupService} for this file system + */ + public abstract UserPrincipalLookupService getUserPrincipalLookupService(); + + /** + * Constructs a new {@link WatchService} <i>(optional operation)</i>. + * + * <p> This method constructs a new watch service that may be used to watch + * registered objects for changes and events. + * + * @return a new watch service + * + * @throws UnsupportedOperationException + * If this {@code FileSystem} does not support watching file system + * objects for changes and events. This exception is not thrown + * by {@code FileSystems} created by the default provider. + * @throws IOException + * If an I/O error occurs + */ + public abstract WatchService newWatchService() throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/FileSystemAlreadyExistsException.java b/jdk/src/share/classes/java/nio/file/FileSystemAlreadyExistsException.java new file mode 100644 index 00000000000..68c4e153b32 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileSystemAlreadyExistsException.java @@ -0,0 +1,53 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Runtime exception thrown when an attempt is made to create a file system that + * already exists. + */ + +public class FileSystemAlreadyExistsException + extends RuntimeException +{ + static final long serialVersionUID = -5438419127181131148L; + + /** + * Constructs an instance of this class. + */ + public FileSystemAlreadyExistsException() { + } + + /** + * Constructs an instance of this class. + * + * @param msg + * the detail message + */ + public FileSystemAlreadyExistsException(String msg) { + super(msg); + } +} diff --git a/jdk/src/share/classes/java/nio/file/FileSystemException.java b/jdk/src/share/classes/java/nio/file/FileSystemException.java new file mode 100644 index 00000000000..8735dd8795d --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileSystemException.java @@ -0,0 +1,125 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.io.IOException; + +/** + * Thrown when a file system operation fails on one or two files. This class is + * the general class for file system exceptions. + * + * @since 1.7 + */ + +public class FileSystemException + extends IOException +{ + static final long serialVersionUID = -3055425747967319812L; + + private final String file; + private final String other; + + /** + * Constructs an instance of this class. This constructor should be used + * when an operation involving one file fails and there isn't any additional + * information to explain the reason. + * + * @param file + * a string identifying the file or {@code null} if not known. + */ + public FileSystemException(String file) { + super((String)null); + this.file = file; + this.other = null; + } + + /** + * Constructs an instance of this class. This constructor should be used + * when an operation involving two files fails, or there is additional + * information to explain the reason. + * + * @param file + * a string identifying the file or {@code null} if not known. + * @param other + * a string identifying the other file or {@code null} if there + * isn't another file or if not known + * @param reason + * a reason message with additional information or {@code null} + */ + public FileSystemException(String file, String other, String reason) { + super(reason); + this.file = file; + this.other = other; + } + + /** + * Returns the file used to create this exception. + * + * @return the file (can be {@code null}) + */ + public String getFile() { + return file; + } + + /** + * Returns the other file used to create this exception. + * + * @return the other file (can be {@code null}) + */ + public String getOtherFile() { + return other; + } + + /** + * Returns the string explaining why the file system operation failed. + * + * @return the string explaining why the file system operation failed + */ + public String getReason() { + return super.getMessage(); + } + + /** + * Returns the detail message string. + */ + @Override + public String getMessage() { + if (file == null && other == null) + return getReason(); + StringBuilder sb = new StringBuilder(); + if (file != null) + sb.append(file); + if (other != null) { + sb.append(" -> "); + sb.append(other); + } + if (getReason() != null) { + sb.append(": "); + sb.append(getReason()); + } + return sb.toString(); + } +} diff --git a/jdk/src/share/classes/java/nio/file/FileSystemNotFoundException.java b/jdk/src/share/classes/java/nio/file/FileSystemNotFoundException.java new file mode 100644 index 00000000000..7cb58cada21 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileSystemNotFoundException.java @@ -0,0 +1,52 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Runtime exception thrown when a file system cannot be found. + */ + +public class FileSystemNotFoundException + extends RuntimeException +{ + static final long serialVersionUID = 7999581764446402397L; + + /** + * Constructs an instance of this class. + */ + public FileSystemNotFoundException() { + } + + /** + * Constructs an instance of this class. + * + * @param msg + * the detail message + */ + public FileSystemNotFoundException(String msg) { + super(msg); + } +} diff --git a/jdk/src/share/classes/java/nio/file/FileSystems.java b/jdk/src/share/classes/java/nio/file/FileSystems.java new file mode 100644 index 00000000000..28885f8afee --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileSystems.java @@ -0,0 +1,413 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.spi.FileSystemProvider; +import java.net.URI; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.*; +import java.lang.reflect.Constructor; + +/** + * Factory methods for file systems. This class defines the {@link #getDefault + * getDefault} method to get the default file system and factory methods to + * construct other types of file systems. + * + * <p> The first invocation of any of the methods defined by this class causes + * the default {@link FileSystemProvider provider} to be loaded. The default + * provider, identified by the URI scheme "file", creates the {@link FileSystem} + * that provides access to the file systems accessible to the Java virtual + * machine. If the process of loading or initializing the default provider fails + * then an unspecified error is thrown. + * + * <p> The first invocation of the {@link FileSystemProvider#installedProviders + * installedProviders} method, by way of invoking any of the {@code + * newFileSystem} methods defined by this class, locates and loads all + * installed file system providers. Installed providers are loaded using the + * service-provider loading facility defined by the {@link ServiceLoader} class. + * Installed providers are loaded using the system class loader. If the + * system class loader cannot be found then the extension class loader is used; + * if there is no extension class loader then the bootstrap class loader is used. + * Providers are typically installed by placing them in a JAR file on the + * application class path or in the extension directory, the JAR file contains a + * provider-configuration file named {@code java.nio.file.spi.FileSystemProvider} + * in the resource directory {@code META-INF/services}, and the file lists one or + * more fully-qualified names of concrete subclass of {@link FileSystemProvider} + * that have a zero argument constructor. + * The ordering that installed providers are located is implementation specific. + * If a provider is instantiated and its {@link FileSystemProvider#getScheme() + * getScheme} returns the same URI scheme of a provider that was previously + * instantiated then the most recently instantiated duplicate is discarded. URI + * schemes are compared without regard to case. During construction a provider + * may safely access files associated with the default provider but care needs + * to be taken to avoid circular loading of other installed providers. If + * circular loading of installed providers is detected then an unspecified error + * is thrown. + * + * <p> This class also defines factory methods that allow a {@link ClassLoader} + * to be specified when locating a provider. As with installed providers, the + * provider classes are identified by placing the provider configuration file + * in the resource directory {@code META-INF/services}. + * + * <p> If a thread initiates the loading of the installed file system providers + * and another thread invokes a method that also attempts to load the providers + * then the method will block until the loading completes. + * + * @since 1.7 + */ + +public final class FileSystems { + private FileSystems() { + } + + // lazy initialization of default file system + private static class DefaultFileSystemHolder { + static final FileSystem defaultFileSystem = defaultFileSystem(); + + // returns default file system + private static FileSystem defaultFileSystem() { + // load default provider + FileSystemProvider provider = AccessController + .doPrivileged(new PrivilegedAction<FileSystemProvider>() { + public FileSystemProvider run() { + return getDefaultProvider(); + } + }); + + // return file system + return provider.getFileSystem(URI.create("file:///")); + } + + // returns default provider + private static FileSystemProvider getDefaultProvider() { + FileSystemProvider provider = sun.nio.fs.DefaultFileSystemProvider.create(); + + // if the property java.nio.file.spi.DefaultFileSystemProvider is + // set then its value is the name of the default provider (or a list) + String propValue = System + .getProperty("java.nio.file.spi.DefaultFileSystemProvider"); + if (propValue != null) { + for (String cn: propValue.split(",")) { + try { + Class<?> c = Class + .forName(cn, true, ClassLoader.getSystemClassLoader()); + Constructor<?> ctor = c + .getDeclaredConstructor(FileSystemProvider.class); + provider = (FileSystemProvider)ctor.newInstance(provider); + + // must be "file" + if (!provider.getScheme().equals("file")) + throw new Error("Default provider must use scheme 'file'"); + + } catch (Exception x) { + throw new Error(x); + } + } + } + return provider; + } + } + + /** + * Returns the default {@code FileSystem}. The default file system creates + * objects that provide access to the file systems accessible to the Java + * virtual machine. The <em>working directory</em> of the file system is + * the current user directory, named by the system property {@code user.dir}. + * This allows for interoperability with the {@link java.io.File java.io.File} + * class. + * + * <p> The first invocation of any of the methods defined by this class + * locates the default {@link FileSystemProvider provider} object. Where the + * system property {@code java.nio.file.spi.DefaultFileSystemProvider} is + * not defined then the default provider is a system-default provider that + * is invoked to create the default file system. + * + * <p> If the system property {@code java.nio.file.spi.DefaultFileSystemProvider} + * is defined then it is taken to be a list of one or more fully-qualified + * names of concrete provider classes identified by the URI scheme + * {@code "file"}. Where the property is a list of more than one name then + * the names are separated by a comma. Each class is loaded, using the system + * class loader, and instantiated by invoking a one argument constructor + * whose formal parameter type is {@code FileSystemProvider}. The providers + * are loaded and instantiated in the order they are listed in the property. + * If this process fails or a provider's scheme is not equal to {@code "file"} + * then an unspecified error is thrown. URI schemes are normally compared + * without regard to case but for the default provider, the scheme is + * required to be {@code "file"}. The first provider class is instantiated + * by invoking it with a reference to the system-default provider. + * The second provider class is instantiated by invoking it with a reference + * to the first provider instance. The third provider class is instantiated + * by invoking it with a reference to the second instance, and so on. The + * last provider to be instantiated becomes the default provider; its {@code + * getFileSystem} method is invoked with the URI {@code "file:///"} to create + * the default file system. + * + * <p> Subsequent invocations of this method return the file system that was + * returned by the first invocation. + * + * @return the default file system + */ + public static FileSystem getDefault() { + return DefaultFileSystemHolder.defaultFileSystem; + } + + /** + * Returns a reference to an existing {@code FileSystem}. + * + * <p> This method iterates over the {@link FileSystemProvider#installedProviders() + * installed} providers to locate the provider that is identified by the URI + * {@link URI#getScheme scheme} of the given URI. URI schemes are compared + * without regard to case. The exact form of the URI is highly provider + * dependent. If found, the provider's {@link FileSystemProvider#getFileSystem + * getFileSystem} method is invoked to obtain a reference to the {@code + * FileSystem}. + * + * <p> Once a file system created by this provider is {@link FileSystem#close + * closed} it is provider-dependent if this method returns a reference to + * the closed file system or throws {@link FileSystemNotFoundException}. + * If the provider allows a new file system to be created with the same URI + * as a file system it previously created then this method throws the + * exception if invoked after the file system is closed (and before a new + * instance is created by the {@link #newFileSystem newFileSystem} method). + * + * <p> If a security manager is installed then a provider implementation + * may require to check a permission before returning a reference to an + * existing file system. In the case of the {@link FileSystems#getDefault + * default} file system, no permission check is required. + * + * @throws IllegalArgumentException + * if the pre-conditions for the {@code uri} parameter are not met + * @throws FileSystemNotFoundException + * if the file system, identified by the URI, does not exist + * @throws ProviderNotFoundException + * if a provider supporting the URI scheme is not installed + * @throws SecurityException + * if a security manager is installed and it denies an unspecified + * permission + */ + public static FileSystem getFileSystem(URI uri) { + String scheme = uri.getScheme(); + for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { + if (scheme.equalsIgnoreCase(provider.getScheme())) { + return provider.getFileSystem(uri); + } + } + throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found"); + } + + /** + * Constructs a new file system that is identified by a {@link URI} + * + * <p> This method iterates over the {@link FileSystemProvider#installedProviders() + * installed} providers to locate the provider that is identified by the URI + * {@link URI#getScheme scheme} of the given URI. URI schemes are compared + * without regard to case. The exact form of the URI is highly provider + * dependent. If found, the provider's {@link FileSystemProvider#newFileSystem(URI,Map) + * newFileSystem(URI,Map)} method is invoked to construct the new file system. + * + * <p> Once a file system is {@link FileSystem#close closed} it is + * provider-dependent if the provider allows a new file system to be created + * with the same URI as a file system it previously created. + * + * <p> <b>Usage Example:</b> + * Suppose there is a provider identified by the scheme {@code "memory"} + * installed: + * <pre> + * Map<String,String> env = new HashMap<String,String>(); + * env.put("capacity", "16G"); + * env.put("blockSize", "4k"); + * FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env); + * </pre> + * + * @param uri + * the URI identifying the file system + * @param env + * a map of provider specific properties to configure the file system; + * may be empty + * + * @return a new file system + * + * @throws IllegalArgumentException + * if the pre-conditions for the {@code uri} parameter are not met, + * or the {@code env} parameter does not contain properties required + * by the provider, or a property value is invalid + * @throws FileSystemAlreadyExistsException + * if the file system has already been created + * @throws ProviderNotFoundException + * if a provider supporting the URI scheme is not installed + * @throws IOException + * if an I/O error occurs creating the file system + * @throws SecurityException + * if a security manager is installed and it denies an unspecified + * permission required by the file system provider implementation + */ + public static FileSystem newFileSystem(URI uri, Map<String,?> env) + throws IOException + { + return newFileSystem(uri, env, null); + } + + /** + * Constructs a new file system that is identified by a {@link URI} + * + * <p> This method first attempts to locate an installed provider in exactly + * the same manner as the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)} + * method. If none of the installed providers support the URI scheme then an + * attempt is made to locate the provider using the given class loader. If a + * provider supporting the URI scheme is located then its {@link + * FileSystemProvider#newFileSystem(URI,Map) newFileSystem(URI,Map)} is + * invoked to construct the new file system. + * + * @param uri + * the URI identifying the file system + * @param env + * a map of provider specific properties to configure the file system; + * may be empty + * @param loader + * the class loader to locate the provider or {@code null} to only + * attempt to locate an installed provider + * + * @return a new file system + * + * @throws IllegalArgumentException + * if the pre-conditions for the {@code uri} parameter are not met, + * or the {@code env} parameter does not contain properties required + * by the provider, or a property value is invalid + * @throws FileSystemAlreadyExistsException + * if the URI scheme identifies an installed provider and the file + * system has already been created + * @throws ProviderNotFoundException + * if a provider supporting the URI scheme is not found + * @throws ServiceConfigurationError + * when an error occurs while loading a service provider + * @throws IOException + * an I/O error occurs creating the file system + * @throws SecurityException + * if a security manager is installed and it denies an unspecified + * permission required by the file system provider implementation + */ + public static FileSystem newFileSystem(URI uri, Map<String,?> env, ClassLoader loader) + throws IOException + { + String scheme = uri.getScheme(); + + // check installed providers + for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { + if (scheme.equalsIgnoreCase(provider.getScheme())) { + return provider.newFileSystem(uri, env); + } + } + + // if not found, use service-provider loading facility + if (loader != null) { + ServiceLoader<FileSystemProvider> sl = ServiceLoader + .load(FileSystemProvider.class, loader); + for (FileSystemProvider provider: sl) { + if (scheme.equalsIgnoreCase(provider.getScheme())) { + return provider.newFileSystem(uri, env); + } + } + } + + throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found"); + } + + /** + * Constructs a new {@code FileSystem} to access the contents of a file as a + * file system. + * + * <p> This method makes use of specialized providers that create pseudo file + * systems where the contents of one or more files is treated as a file + * system. The {@code file} parameter is a reference to an existing file + * and the {@code env} parameter is a map of provider specific properties to + * configure the file system. + * + * <p> This method iterates over the {@link FileSystemProvider#installedProviders() + * installed} providers. It invokes, in turn, each provider's {@link + * FileSystemProvider#newFileSystem(FileRef,Map) newFileSystem(FileRef,Map)} method. + * If a provider returns a file system then the iteration terminates + * and the file system is returned. If none of the installed providers return + * a {@code FileSystem} then an attempt is made to locate the provider using + * the given class loader. If a provider returns a file system then the lookup + * terminates and the file system is returned. + * + * @param file + * a reference to a file + * @param env + * a map of provider specific properties to configure the file system; + * may be empty + * @param loader + * the class loader to locate the provider or {@code null} to only + * attempt to locate an installed provider + * + * @return a new file system + * + * @throws IllegalArgumentException + * if the {@code env} parameter does not contain properties required + * by the provider, or a property value is invalid + * @throws ProviderNotFoundException + * if a provider supporting this file type cannot be located + * @throws ServiceConfigurationError + * when an error occurs while loading a service provider + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * if a security manager is installed and it denies an unspecified + * permission + */ + public static FileSystem newFileSystem(FileRef file, + Map<String,?> env, + ClassLoader loader) + throws IOException + { + if (file == null) + throw new NullPointerException(); + + // check installed providers + for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { + try { + return provider.newFileSystem(file, env); + } catch (UnsupportedOperationException uoe) { + } + } + + // if not found, use service-provider loading facility + if (loader != null) { + ServiceLoader<FileSystemProvider> sl = ServiceLoader + .load(FileSystemProvider.class, loader); + for (FileSystemProvider provider: sl) { + try { + return provider.newFileSystem(file, env); + } catch (UnsupportedOperationException uoe) { + } + } + } + + throw new ProviderNotFoundException("Provider not found"); + } +} diff --git a/jdk/src/share/classes/java/nio/file/FileTreeWalker.java b/jdk/src/share/classes/java/nio/file/FileTreeWalker.java new file mode 100644 index 00000000000..95148a5b50d --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileTreeWalker.java @@ -0,0 +1,255 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; +import sun.nio.fs.BasicFileAttributesHolder; + +/** + * Simple file tree walker that works in a similar manner to nftw(3C). + * + * @see Files#walkFileTree + */ + +class FileTreeWalker { + private final boolean followLinks; + private final boolean detectCycles; + private final LinkOption[] linkOptions; + private final FileVisitor<? super Path> visitor; + + FileTreeWalker(Set<FileVisitOption> options, FileVisitor<? super Path> visitor) { + boolean fl = false; + boolean dc = false; + for (FileVisitOption option: options) { + switch (option) { + case FOLLOW_LINKS : fl = true; break; + case DETECT_CYCLES : dc = true; break; + default: + if (option == null) + throw new NullPointerException("Visit options contains 'null'"); + throw new AssertionError("Should not get here"); + } + } + this.followLinks = fl; + this.detectCycles = fl | dc; + this.linkOptions = (fl) ? new LinkOption[0] : + new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; + this.visitor = visitor; + } + + /** + * Walk file tree starting at the given file + */ + void walk(Path start, int maxDepth) { + // don't use attributes of starting file as they may be stale + if (start instanceof BasicFileAttributesHolder) { + ((BasicFileAttributesHolder)start).invalidate(); + } + FileVisitResult result = walk(start, + maxDepth, + new ArrayList<AncestorDirectory>()); + if (result == null) { + throw new NullPointerException("Visitor returned 'null'"); + } + } + + /** + * @param file + * the directory to visit + * @param depth + * depth remaining + * @param ancestors + * use when cycle detection is enabled + */ + private FileVisitResult walk(Path file, + int depth, + List<AncestorDirectory> ancestors) + { + // depth check + if (depth-- < 0) + return FileVisitResult.CONTINUE; + + // if attributes are cached then use them if possible + BasicFileAttributes attrs = null; + if (file instanceof BasicFileAttributesHolder) { + BasicFileAttributes cached = ((BasicFileAttributesHolder)file).get(); + if (!followLinks || !cached.isSymbolicLink()) + attrs = cached; + } + IOException exc = null; + + // attempt to get attributes of file. If fails and we are following + // links then a link target might not exist so get attributes of link + if (attrs == null) { + try { + try { + attrs = Attributes.readBasicFileAttributes(file, linkOptions); + } catch (IOException x1) { + if (followLinks) { + try { + attrs = Attributes + .readBasicFileAttributes(file, LinkOption.NOFOLLOW_LINKS); + } catch (IOException x2) { + exc = x2; + } + } else { + exc = x1; + } + } + } catch (SecurityException x) { + return FileVisitResult.CONTINUE; + } + } + + // unable to get attributes of file + if (exc != null) { + return visitor.visitFileFailed(file, exc); + } + + // file is not a directory so invoke visitFile method + if (!attrs.isDirectory()) { + return visitor.visitFile(file, attrs); + } + + // check for cycles + if (detectCycles) { + Object key = attrs.fileKey(); + + // if this directory and ancestor has a file key then we compare + // them; otherwise we use less efficient isSameFile test. + for (AncestorDirectory ancestor: ancestors) { + Object ancestorKey = ancestor.fileKey(); + if (key != null && ancestorKey != null) { + if (key.equals(ancestorKey)) { + // cycle detected + return visitor.visitFile(file, attrs); + } + } else { + try { + if (file.isSameFile(ancestor.file())) { + // cycle detected + return visitor.visitFile(file, attrs); + } + } catch (IOException x) { + // ignore + } catch (SecurityException x) { + // ignore + } + } + } + + ancestors.add(new AncestorDirectory(file, key)); + } + + // visit directory + try { + DirectoryStream<Path> stream = null; + FileVisitResult result; + + // open the directory + try { + stream = file.newDirectoryStream(); + } catch (IOException x) { + return visitor.preVisitDirectoryFailed(file, x); + } catch (SecurityException x) { + // ignore, as per spec + return FileVisitResult.CONTINUE; + } + + // the exception notified to the postVisitDirectory method + IOException ioe = null; + + // invoke preVisitDirectory and then visit each entry + try { + result = visitor.preVisitDirectory(file); + if (result != FileVisitResult.CONTINUE) { + return result; + } + + // if an I/O occurs during iteration then a CME is thrown. We + // need to distinguish this from a CME thrown by the visitor. + boolean inAction = false; + + try { + for (Path entry: stream) { + inAction = true; + result = walk(entry, depth, ancestors); + inAction = false; + + // returning null will cause NPE to be thrown + if (result == null || result == FileVisitResult.TERMINATE) + return result; + + // skip remaining siblings in this directory + if (result == FileVisitResult.SKIP_SIBLINGS) + break; + } + } catch (ConcurrentModificationException x) { + // if CME thrown because the iteration failed then remember + // the IOException so that it is notified to postVisitDirectory + if (!inAction) { + // iteration failed + Throwable t = x.getCause(); + if (t instanceof IOException) + ioe = (IOException)t; + } + if (ioe == null) + throw x; + } + } finally { + try { + stream.close(); + } catch (IOException x) { } + } + + // invoke postVisitDirectory last + return visitor.postVisitDirectory(file, ioe); + + } finally { + // remove key from trail if doing cycle detection + if (detectCycles) { + ancestors.remove(ancestors.size()-1); + } + } + } + + private static class AncestorDirectory { + private final FileRef dir; + private final Object key; + AncestorDirectory(FileRef dir, Object key) { + this.dir = dir; + this.key = key; + } + FileRef file() { + return dir; + } + Object fileKey() { + return key; + } + } +} diff --git a/jdk/src/share/classes/java/nio/file/FileVisitOption.java b/jdk/src/share/classes/java/nio/file/FileVisitOption.java new file mode 100644 index 00000000000..c02e3e2d106 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileVisitOption.java @@ -0,0 +1,45 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Defines the file tree traversal options. + * + * @since 1.7 + * + * @see Files#walkFileTree + */ + +public enum FileVisitOption { + /** + * Follow symbolic links. + */ + FOLLOW_LINKS, + /** + * Detect cycles in the file tree. + */ + DETECT_CYCLES; +} diff --git a/jdk/src/share/classes/java/nio/file/FileVisitResult.java b/jdk/src/share/classes/java/nio/file/FileVisitResult.java new file mode 100644 index 00000000000..28e628bc85b --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileVisitResult.java @@ -0,0 +1,62 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * The result type of a {@link FileVisitor FileVisitor}. + * + * @since 1.7 + * + * @see Files#walkFileTree + */ + +public enum FileVisitResult { + /** + * Continue. When returned from a {@link FileVisitor#preVisitDirectory + * preVisitDirectory} method then the entries in the directory should also + * be visited. + */ + CONTINUE, + /** + * Terminate. + */ + TERMINATE, + /** + * Continue without visiting the entries in this directory. This result + * is only meaningful when returned from the {@link + * FileVisitor#preVisitDirectory preVisitDirectory} method; otherwise + * this result type is the same as returning {@link #CONTINUE}. + */ + SKIP_SUBTREE, + /** + * Continue without visiting the <em>siblings</em> of this file or directory. + * If returned from the {@link FileVisitor#preVisitDirectory + * preVisitDirectory} method then the entries in the directory are also + * skipped and the {@link FileVisitor#postVisitDirectory postVisitDirectory} + * method is not invoked. + */ + SKIP_SIBLINGS; +} diff --git a/jdk/src/share/classes/java/nio/file/FileVisitor.java b/jdk/src/share/classes/java/nio/file/FileVisitor.java new file mode 100644 index 00000000000..6d65eba27a9 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/FileVisitor.java @@ -0,0 +1,175 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.attribute.BasicFileAttributes; +import java.io.IOException; + +/** + * A visitor of files. An implementation of this interface is provided to the + * {@link Files#walkFileTree walkFileTree} utility method to visit each file + * in a tree. + * + * <p> <b>Usage Examples:</b> + * Suppose we want to delete a file tree. In that case, each directory should + * be deleted after the entries in the directory are deleted. + * <pre> + * Path start = ... + * Files.walkFileTree(start, new SimpleFileVisitor<Path>() { + * @Override + * public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + * try { + * file.delete(false); + * } catch (IOException exc) { + * // failed to delete + * } + * return FileVisitResult.CONTINUE; + * } + * @Override + * public FileVisitResult postVisitDirectory(Path dir, IOException e) { + * if (e == null) { + * try { + * dir.delete(false); + * } catch (IOException exc) { + * // failed to delete + * } + * } else { + * // directory iteration failed + * } + * return FileVisitResult.CONTINUE; + * } + * }); + * </pre> + * <p> Furthermore, suppose we want to copy a file tree rooted at a source + * directory to a target location. In that case, symbolic links should be + * followed and the target directory should be created before the entries in + * the directory are copied. + * <pre> + * final Path source = ... + * final Path target = ... + * + * Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, + * new SimpleFileVisitor<Path>() { + * @Override + * public FileVisitResult preVisitDirectory(Path dir) { + * try { + * dir.copyTo(target.resolve(source.relativize(dir))); + * } catch (FileAlreadyExistsException e) { + * // ignore + * } catch (IOException e) { + * // copy failed, skip rest of directory and descendants + * return SKIP_SUBTREE; + * } + * return CONTINUE; + * } + * @Override + * public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + * try { + * file.copyTo(target.resolve(source.relativize(file))); + * } catch (IOException e) { + * // copy failed + * } + * return CONTINUE; + * } + * }); + * </pre> + * + * @since 1.7 + */ + +public interface FileVisitor<T extends FileRef> { + + /** + * Invoked for a directory before entries in the directory are visited. + * + * <p> If this method returns {@link FileVisitResult#CONTINUE CONTINUE}, + * then entries in the directory are visited. If this method returns {@link + * FileVisitResult#SKIP_SUBTREE SKIP_SUBTREE} or {@link + * FileVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS} then entries in the + * directory (and any descendants) will not be visited. + * + * @param dir + * a reference to the directory + * + * @return the visit result + */ + FileVisitResult preVisitDirectory(T dir); + + /** + * Invoked for a directory that could not be opened. + * + * @param dir + * a reference to the directory + * @param exc + * the I/O exception thrown from the attempt to open the directory + * + * @return the visit result + */ + FileVisitResult preVisitDirectoryFailed(T dir, IOException exc); + + /** + * Invoked for a file in a directory. + * + * @param file + * a reference to the file + * @param attrs + * the file's basic attributes + * + * @return the visit result + */ + FileVisitResult visitFile(T file, BasicFileAttributes attrs); + + /** + * Invoked for a file when its basic file attributes could not be read. + * + * @param file + * a reference to the file + * @param exc + * the I/O exception thrown from the attempt to read the file + * attributes + * + * @return the visit result + */ + FileVisitResult visitFileFailed(T file, IOException exc); + + /** + * Invoked for a directory after entries in the directory, and all of their + * descendants, have been visited. This method is also invoked when iteration + * of the directory completes prematurely (by a {@link #visitFile visitFile} + * method returning {@link FileVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS}, + * or an I/O error when iterating over the directory). + * + * @param dir + * a reference to the directory + * @param exc + * {@code null} if the iteration of the directory completes without + * an error; otherwise the I/O exception that caused the iteration + * of the directory to complete prematurely + * + * @return the visit result + */ + FileVisitResult postVisitDirectory(T dir, IOException exc); +} diff --git a/jdk/src/share/classes/java/nio/file/Files.java b/jdk/src/share/classes/java/nio/file/Files.java new file mode 100644 index 00000000000..42fdad823b3 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/Files.java @@ -0,0 +1,406 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.spi.FileTypeDetector; +import java.io.IOException; +import java.util.*; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Utility methods for files and directories. + * + * @since 1.7 + */ + +public final class Files { + private Files() { } + + // lazy loading of default and installed file type detectors + private static class DefaultFileTypeDetectorHolder { + static final FileTypeDetector defaultFileTypeDetector = + sun.nio.fs.DefaultFileTypeDetector.create(); + static final List<FileTypeDetector> installeDetectors = + loadInstalledDetectors(); + + // loads all installed file type detectors + private static List<FileTypeDetector> loadInstalledDetectors() { + return AccessController + .doPrivileged(new PrivilegedAction<List<FileTypeDetector>>() { + @Override public List<FileTypeDetector> run() { + List<FileTypeDetector> list = new ArrayList<FileTypeDetector>(); + ServiceLoader<FileTypeDetector> loader = ServiceLoader + .load(FileTypeDetector.class, ClassLoader.getSystemClassLoader()); + for (FileTypeDetector detector: loader) { + list.add(detector); + } + return list; + }}); + } + } + + /** + * Probes the content type of a file. + * + * <p> This method uses the installed {@link FileTypeDetector} implementations + * to probe the given file to determine its content type. Each file type + * detector's {@link FileTypeDetector#probeContentType probeContentType} is + * invoked, in turn, to probe the file type. If the file is recognized then + * the content type is returned. If the file is not recognized by any of the + * installed file type detectors then a system-default file type detector is + * invoked to guess the content type. + * + * <p> A given invocation of the Java virtual machine maintains a system-wide + * list of file type detectors. Installed file type detectors are loaded + * using the service-provider loading facility defined by the {@link ServiceLoader} + * class. Installed file type detectors are loaded using the system class + * loader. If the system class loader cannot be found then the extension class + * loader is used; If the extension class loader cannot be found then the + * bootstrap class loader is used. File type detectors are typically installed + * by placing them in a JAR file on the application class path or in the + * extension directory, the JAR file contains a provider-configuration file + * named {@code java.nio.file.spi.FileTypeDetector} in the resource directory + * {@code META-INF/services}, and the file lists one or more fully-qualified + * names of concrete subclass of {@code FileTypeDetector } that have a zero + * argument constructor. If the process of locating or instantiating the + * installed file type detectors fails then an unspecified error is thrown. + * The ordering that installed providers are located is implementation + * specific. + * + * <p> The return value of this method is the string form of the value of a + * Multipurpose Internet Mail Extension (MIME) content type as + * defined by <a href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC 2045: + * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet + * Message Bodies</i></a>. The string is guaranteed to be parsable according + * to the grammar in the RFC. + * + * @param file + * The file reference + * + * @return The content type of the file, or {@code null} if the content + * type cannot be determined + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * If a security manager is installed and it denies an unspecified + * permission required by a file type detector implementation. + * + * @see DirectoryStreamFilters#newContentTypeFilter + */ + public static String probeContentType(FileRef file) + throws IOException + { + // try installed file type detectors + for (FileTypeDetector detector: DefaultFileTypeDetectorHolder.installeDetectors) { + String result = detector.probeContentType(file); + if (result != null) + return result; + } + + // fallback to default + return DefaultFileTypeDetectorHolder.defaultFileTypeDetector + .probeContentType(file); + } + + /** + * Invokes a {@link FileAction} for each entry in a directory accepted + * by a given {@link java.nio.file.DirectoryStream.Filter filter}. + * + * <p> This method opens the given directory and invokes the file action's + * {@link FileAction#invoke invoke} method for each entry accepted by the + * filter. When iteration is completed then the directory is closed. If the + * {@link DirectoryStream#close close} method throws an {@code IOException} + * then it is silently ignored. + * + * <p> If the {@code FileAction}'s {@code invoke} method terminates due + * to an uncaught {@link IOException}, {@code Error} or {@code RuntimeException} + * then the exception is propagated by this method after closing the + * directory. + * + * @param dir + * The directory + * @param filter + * The filter + * @param action + * The {@code FileAction} to invoke for each accepted entry + * + * @throws NotDirectoryException + * If the {@code dir} parameter is not a directory <i>(optional + * specific exception)</i> + * @throws IOException + * If an I/O error occurs or the {@code invoke} method terminates + * due to an uncaught {@code IOException} + * @throws SecurityException + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to the directory. + */ + public static void withDirectory(Path dir, + DirectoryStream.Filter<? super Path> filter, + FileAction<? super Path> action) + throws IOException + { + // explicit null check required in case directory is empty + if (action == null) + throw new NullPointerException(); + + DirectoryStream<Path> stream = dir.newDirectoryStream(filter); + try { + // set to true when invoking the action so as to distinguish a + // CME thrown by the iteration from a CME thrown by the invoke + boolean inAction = false; + try { + for (Path entry: stream) { + inAction = true; + action.invoke(entry); + inAction = false; + } + } catch (ConcurrentModificationException cme) { + if (!inAction) { + Throwable cause = cme.getCause(); + if (cause instanceof IOException) + throw (IOException)cause; + } + throw cme; + } + } finally { + try { + stream.close(); + } catch (IOException x) { } + } + } + + /** + * Invokes a {@link FileAction} for each entry in a directory with a + * file name that matches a given pattern. + * + * <p> This method opens the given directory and invokes the file action's + * {@link FileAction#invoke invoke} method for each entry that matches the + * given pattern. When iteration is completed then the directory is closed. + * If the {@link DirectoryStream#close close} method throws an {@code + * IOException} then it is silently ignored. + * + * <p> If the {@code FileAction}'s {@code invoke} method terminates due + * to an uncaught {@link IOException}, {@code Error} or {@code RuntimeException} + * then the exception is propagated by this method after closing the + * directory. + * + * <p> The globbing pattern language supported by this method is as + * specified by the {@link FileSystem#getPathMatcher getPathMatcher} method. + * + * @param dir + * The directory + * @param glob + * The globbing pattern + * @param action + * The {@code FileAction} to invoke for each entry + * + * @throws NotDirectoryException + * If the {@code dir} parameter is not a directory <i>(optional + * specific exception)</i> + * @throws IOException + * If an I/O error occurs or the {@code invoke} method terminates + * due to an uncaught {@code IOException} + * @throws SecurityException + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to the directory. + */ + public static void withDirectory(Path dir, + String glob, + FileAction<? super Path> action) + throws IOException + { + if (glob == null) + throw new NullPointerException("'glob' is null"); + final PathMatcher matcher = dir.getFileSystem().getPathMatcher("glob:" + glob); + DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() { + @Override + public boolean accept(Path entry) { + return matcher.matches(entry.getName()); + } + }; + withDirectory(dir, filter, action); + } + + /** + * Invokes a {@link FileAction} for all entries in a directory. + * + * <p> This method works as if invoking it were equivalent to evaluating the + * expression: + * <blockquote><pre> + * withDirectory(dir, "*", action) + * </pre></blockquote> + * + * @param dir + * The directory + * @param action + * The {@code FileAction} to invoke for each entry + * + * @throws NotDirectoryException + * If the {@code dir} parameter is not a directory <i>(optional + * specific exception)</i> + * @throws IOException + * If an I/O error occurs or the {@code invoke} method terminates + * due to an uncaught {@code IOException} + * @throws SecurityException + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to the directory. + */ + public static void withDirectory(Path dir, FileAction<? super Path> action) + throws IOException + { + withDirectory(dir, "*", action); + } + + /** + * Walks a file tree. + * + * <p> This method walks a file tree rooted at a given starting file. The + * file tree traversal is <em>depth-first</em> with the given {@link + * FileVisitor} invoked for each file encountered. File tree traversal + * completes when all accessible files in the tree have been visited, a + * visitor returns a result of {@link FileVisitResult#TERMINATE TERMINATE}, + * or the visitor terminates due to an uncaught {@code Error} or {@code + * RuntimeException}. + * + * <p> For each file encountered this method attempts to gets its {@link + * java.nio.file.attribute.BasicFileAttributes}. If the file is not a + * directory then the {@link FileVisitor#visitFile visitFile} method is + * invoked with the file attributes. If the file attributes cannot be read, + * due to an I/O exception, then the {@link FileVisitor#visitFileFailed + * visitFileFailed} method is invoked with the I/O exception. + * + * <p> Where the file is a directory, this method attempts to open it by + * invoking its {@link Path#newDirectoryStream newDirectoryStream} method. + * Where the directory could not be opened, due to an {@code IOException}, + * then the {@link FileVisitor#preVisitDirectoryFailed preVisitDirectoryFailed} + * method is invoked with the I/O exception, after which, the file tree walk + * continues, by default, at the next <em>sibling</em> of the directory. + * + * <p> Where the directory is opened successfully, then the entries in the + * directory, and their <em>descendants</em> are visited. When all entries + * have been visited, or an I/O error occurs during iteration of the + * directory, then the directory is closed and the visitor's {@link + * FileVisitor#postVisitDirectory postVisitDirectory} method is invoked. + * The file tree walk then continues, by default, at the next <em>sibling</em> + * of the directory. + * + * <p> By default, symbolic links are not automatically followed by this + * method. If the {@code options} parameter contains the {@link + * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are + * followed. When following links, and the attributes of the target cannot + * be read, then this method attempts to get the {@code BasicFileAttributes} + * of the link. If they can be read then the {@code visitFile} method is + * invoked with the attributes of the link (otherwise the {@code visitFileFailed} + * method is invoked as specified above). + * + * <p> If the {@code options} parameter contains the {@link + * FileVisitOption#DETECT_CYCLES DETECT_CYCLES} or {@link + * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} options then this method keeps + * track of directories visited so that cycles can be detected. A cycle + * arises when there is an entry in a directory that is an ancestor of the + * directory. Cycle detection is done by recording the {@link + * java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories, + * or if file keys are not available, by invoking the {@link FileRef#isSameFile + * isSameFile} method to test if a directory is the same file as an + * ancestor. When a cycle is detected the {@link FileVisitor#visitFile + * visitFile} is invoked with the attributes of the directory. The {@link + * java.nio.file.attribute.BasicFileAttributes#isDirectory isDirectory} + * method may be used to test if the file is a directory and that a cycle is + * detected. The {@code preVisitDirectory} and {@code postVisitDirectory} + * methods are not invoked. + * + * <p> The {@code maxDepth} parameter is the maximum number of levels of + * directories to visit. A value of {@code 0} means that only the starting + * file is visited, unless denied by the security manager. A value of + * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all + * levels should be visited. + * + * <p> If a visitor returns a result of {@code null} then {@code + * NullPointerException} is thrown. + * + * <p> When a security manager is installed and it denies access to a file + * (or directory), then it is ignored and the visitor is not invoked for + * that file (or directory). + * + * @param start + * The starting file + * @param options + * Options to configure the traversal + * @param maxDepth + * The maximum number of directory levels to visit + * @param visitor + * The file visitor to invoke for each file + * + * @throws IllegalArgumentException + * If the {@code maxDepth} parameter is negative + * @throws SecurityException + * If the security manager denies access to the starting file. + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to the directory. + */ + public static void walkFileTree(Path start, + Set<FileVisitOption> options, + int maxDepth, + FileVisitor<? super Path> visitor) + { + if (maxDepth < 0) + throw new IllegalArgumentException("'maxDepth' is negative"); + new FileTreeWalker(options, visitor).walk(start, maxDepth); + } + + /** + * Walks a file tree. + * + * <p> This method works as if invoking it were equivalent to evaluating the + * expression: + * <blockquote><pre> + * walkFileTree(start, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE, visitor) + * </pre></blockquote> + * + * @param start + * The starting file + * @param visitor + * The file visitor to invoke for each file + * + * @throws SecurityException + * If the security manager denies access to the starting file. + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to the directory. + */ + public static void walkFileTree(Path start, FileVisitor<? super Path> visitor) { + walkFileTree(start, + EnumSet.noneOf(FileVisitOption.class), + Integer.MAX_VALUE, + visitor); + } +} diff --git a/jdk/src/share/classes/java/nio/file/InvalidPathException.java b/jdk/src/share/classes/java/nio/file/InvalidPathException.java new file mode 100644 index 00000000000..37f23202c63 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/InvalidPathException.java @@ -0,0 +1,130 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Unchecked exception thrown when path string cannot be converted into a + * {@link Path} because the path string contains invalid characters, or + * the path string is invalid for other file system specific reasons. + */ + +public class InvalidPathException + extends IllegalArgumentException +{ + static final long serialVersionUID = 4355821422286746137L; + + private String input; + private int index; + + /** + * Constructs an instance from the given input string, reason, and error + * index. + * + * @param input the input string + * @param reason a string explaining why the input was rejected + * @param index the index at which the error occurred, + * or <tt>-1</tt> if the index is not known + * + * @throws NullPointerException + * if either the input or reason strings are <tt>null</tt> + * + * @throws IllegalArgumentException + * if the error index is less than <tt>-1</tt> + */ + public InvalidPathException(String input, String reason, int index) { + super(reason); + if ((input == null) || (reason == null)) + throw new NullPointerException(); + if (index < -1) + throw new IllegalArgumentException(); + this.input = input; + this.index = index; + } + + /** + * Constructs an instance from the given input string and reason. The + * resulting object will have an error index of <tt>-1</tt>. + * + * @param input the input string + * @param reason a string explaining why the input was rejected + * + * @throws NullPointerException + * if either the input or reason strings are <tt>null</tt> + */ + public InvalidPathException(String input, String reason) { + this(input, reason, -1); + } + + /** + * Returns the input string. + * + * @return the input string + */ + public String getInput() { + return input; + } + + /** + * Returns a string explaining why the input string was rejected. + * + * @return the reason string + */ + public String getReason() { + return super.getMessage(); + } + + /** + * Returns an index into the input string of the position at which the + * error occurred, or <tt>-1</tt> if this position is not known. + * + * @return the error index + */ + public int getIndex() { + return index; + } + + /** + * Returns a string describing the error. The resulting string + * consists of the reason string followed by a colon character + * (<tt>':'</tt>), a space, and the input string. If the error index is + * defined then the string <tt>" at index "</tt> followed by the index, in + * decimal, is inserted after the reason string and before the colon + * character. + * + * @return a string describing the error + */ + public String getMessage() { + StringBuffer sb = new StringBuffer(); + sb.append(getReason()); + if (index > -1) { + sb.append(" at index "); + sb.append(index); + } + sb.append(": "); + sb.append(input); + return sb.toString(); + } +} diff --git a/jdk/src/share/classes/java/nio/file/LinkOption.java b/jdk/src/share/classes/java/nio/file/LinkOption.java new file mode 100644 index 00000000000..08e5c1e1d72 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/LinkOption.java @@ -0,0 +1,43 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Defines the options as to how symbolic links are handled. + * + * @since 1.7 + */ + +public enum LinkOption implements OpenOption, CopyOption { + /** + * Do not follow symbolic links. + * + * @see FileRef#getFileAttributeView(Class,LinkOption[]) + * @see Path#copyTo + * @see SecureDirectoryStream#newByteChannel + */ + NOFOLLOW_LINKS; +} diff --git a/jdk/src/share/classes/java/nio/file/LinkPermission.java b/jdk/src/share/classes/java/nio/file/LinkPermission.java new file mode 100644 index 00000000000..d17788fd029 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/LinkPermission.java @@ -0,0 +1,107 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.security.BasicPermission; + +/** + * The {@code Permission} class for link creation operations. + * + * <p> The following table provides a summary description of what the permission + * allows, and discusses the risks of granting code the permission. + * + * <table border=1 cellpadding=5 + * summary="Table shows permission target name, what the permission allows, and associated risks"> + * <tr> + * <th>Permission Target Name</th> + * <th>What the Permission Allows</th> + * <th>Risks of Allowing this Permission</th> + * </tr> + * <tr> + * <td>hard</td> + * <td> Ability to add an existing file to a directory. This is sometimes + * known as creating a link, or hard link. </td> + * <td> Extreme care should be taken when granting this permission. It allows + * linking to any file or directory in the file system thus allowing the + * attacker to access to all files. </td> + * </tr> + * <tr> + * <td>symbolic</td> + * <td> Ability to create symbolic links. </td> + * <td> Extreme care should be taken when granting this permission. It allows + * linking to any file or directory in the file system thus allowing the + * attacker to access to all files. </td> + * </tr> + * </table> + * + * @since 1.7 + * + * @see Path#createLink + * @see Path#createSymbolicLink + */ +public final class LinkPermission extends BasicPermission { + static final long serialVersionUID = -1441492453772213220L; + + private void checkName(String name) { + if (!name.equals("hard") && !name.equals("symbolic")) { + throw new IllegalArgumentException("name: " + name); + } + } + + /** + * Constructs a {@code LinkPermission} with the specified name. + * + * @param name + * the name of the permission. It must be "hard" or "symbolic". + * + * @throws IllegalArgumentException + * if name is empty or invalid + */ + public LinkPermission(String name) { + super(name); + checkName(name); + } + + /** + * Constructs a {@code LinkPermission} with the specified name. + * + * @param name + * the name of the permission; must be "hard" or "symbolic". + * @param actions + * the actions for the permission; must be the empty string or + * {@code null} + * + * @throws IllegalArgumentException + * if name is empty or invalid + */ + public LinkPermission(String name, String actions) { + super(name); + checkName(name); + if (actions != null && actions.length() > 0) { + throw new IllegalArgumentException("actions: " + actions); + } + } +} diff --git a/jdk/src/share/classes/java/nio/file/NoSuchFileException.java b/jdk/src/share/classes/java/nio/file/NoSuchFileException.java new file mode 100644 index 00000000000..ccde9ae95e7 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/NoSuchFileException.java @@ -0,0 +1,63 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Checked exception thrown when an attempt is made to access a file that does + * not exist. + * + * @since 1.7 + */ + +public class NoSuchFileException + extends FileSystemException +{ + static final long serialVersionUID = -1390291775875351931L; + + /** + * Constructs an instance of this class. + * + * @param file + * a string identifying the file or {@code null} if not known. + */ + public NoSuchFileException(String file) { + super(file); + } + + /** + * Constructs an instance of this class. + * + * @param file + * a string identifying the file or {@code null} if not known. + * @param other + * a string identifying the other file or {@code null} if not known. + * @param reason + * a reason message with additional information or {@code null} + */ + public NoSuchFileException(String file, String other, String reason) { + super(file, other, reason); + } +} diff --git a/jdk/src/share/classes/java/nio/file/NotDirectoryException.java b/jdk/src/share/classes/java/nio/file/NotDirectoryException.java new file mode 100644 index 00000000000..684bd2df44e --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/NotDirectoryException.java @@ -0,0 +1,49 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Checked exception thrown when a file system operation, intended for a + * directory, fails because the file is not a directory. + * + * @since 1.7 + */ + +public class NotDirectoryException + extends FileSystemException +{ + private static final long serialVersionUID = -9011457427178200199L; + + /** + * Constructs an instance of this class. + * + * @param file + * a string identifying the file or {@code null} if not known + */ + public NotDirectoryException(String file) { + super(file); + } +} diff --git a/jdk/src/share/classes/java/nio/file/NotLinkException.java b/jdk/src/share/classes/java/nio/file/NotLinkException.java new file mode 100644 index 00000000000..bdc1fc354ad --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/NotLinkException.java @@ -0,0 +1,63 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Checked exception thrown when a file system operation fails because a file + * is not a link. + * + * @since 1.7 + */ + +public class NotLinkException + extends FileSystemException +{ + static final long serialVersionUID = -388655596416518021L; + + /** + * Constructs an instance of this class. + * + * @param file + * a string identifying the file or {@code null} if not known + */ + public NotLinkException(String file) { + super(file); + } + + /** + * Constructs an instance of this class. + * + * @param file + * a string identifying the file or {@code null} if not known + * @param other + * a string identifying the other file or {@code null} if not known + * @param reason + * a reason message with additional information or {@code null} + */ + public NotLinkException(String file, String other, String reason) { + super(file, other, reason); + } +} diff --git a/jdk/src/share/classes/java/nio/file/OpenOption.java b/jdk/src/share/classes/java/nio/file/OpenOption.java new file mode 100644 index 00000000000..c525307e7dc --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/OpenOption.java @@ -0,0 +1,45 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * An object that configures how to open or create a file. + * + * <p> Objects of this type are used by methods such as {@link + * Path#newOutputStream(OpenOption[]) newOutputStream}, {@link + * FileRef#newByteChannel newByteChannel}, {@link + * java.nio.channels.FileChannel#open FileChannel.open}, and {@link + * java.nio.channels.AsynchronousFileChannel#open AsynchronousFileChannel.open} + * when opening or creating a file. + * + * <p> The {@link StandardOpenOption} enumeration type defines the + * <i>standard</i> options. + * + * @since 1.7 + */ + +public interface OpenOption { +} diff --git a/jdk/src/share/classes/java/nio/file/Path.java b/jdk/src/share/classes/java/nio/file/Path.java new file mode 100644 index 00000000000..55bf8fd2675 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/Path.java @@ -0,0 +1,1613 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.attribute.*; +import java.nio.channels.*; +import java.io.*; +import java.net.URI; +import java.util.*; + +/** + * A file reference that locates a file using a system dependent path. The file + * is not required to exist. + * + * <p> On many platforms a <em>path</em> is the means to locate and access files + * in a file system. A path is hierarchical and composed of a sequence of + * directory and file name elements separated by a special separator or + * delimiter. + * + * <h4>Path operations</h4> + * + * <p> A system dependent path represented by this class is conceptually a + * sequence of name elements and optionally a <em>root component</em>. The name + * that is <em>farthest</em> from the root of the directory hierarchy is the + * name of a file or directory. The other elements are directory names. The root + * component typically identifies a file system hierarchy. A {@code Path} can + * represent a root, a root and a sequence of names, or simply one or more name + * elements. It defines the {@link #getName() getName}, {@link #getParent + * getParent}, {@link #getRoot getRoot}, and {@link #subpath subpath} methods + * to access the components or a subsequence of its name elements. + * + * <p> In addition to accessing the components of a path, a {@code Path} also + * defines {@link #resolve(Path) resolve} and {@link #relativize relativize} + * operations. Paths can also be {@link #compareTo compared}, and tested + * against each other using using the {@link #startsWith startsWith} and {@link + * #endsWith endWith} methods. + * + * <h4>File operations</h4> + * + * <p> A {@code Path} is either <em>absolute</em> or <em>relative</em>. An + * absolute path is complete in that does not need to be combined with another + * path in order to locate a file. All operations on relative paths are first + * resolved against a file system's default directory as if by invoking the + * {@link #toAbsolutePath toAbsolutePath} method. + * + * <p> In addition to the operations defined by the {@link FileRef} interface, + * this class defines the following operations: + * + * <ul> + * <li><p> Files may be {@link #createFile(FileAttribute[]) created}, or + * directories may be {@link #createDirectory(FileAttribute[]) created}. + * </p></li> + * <li><p> Directories can be {@link #newDirectoryStream opened} so as to + * iterate over the entries in the directory. </p></li> + * <li><p> Files can be {@link #copyTo(Path,CopyOption[]) copied} or + * {@link #moveTo(Path,CopyOption[]) moved}. </p></li> + * <li><p> Symbolic-links may be {@link #createSymbolicLink created}, or the + * target of a link may be {@link #readSymbolicLink read}. </p></li> + * <li><p> {@link #newInputStream InputStream} or {@link #newOutputStream + * OutputStream} streams can be created to allow for interoperation with the + * <a href="../../../java/io/package-summary.html">{@code java.io}</a> package + * where required. </li></p> + * <li><p> The {@link #toRealPath real} path of an existing file may be + * obtained. </li></p> + * </ul> + * + * <p> This class implements {@link Watchable} interface so that a directory + * located by a path can be {@link #register registered} with a {@link WatchService}. + * and entries in the directory watched. + * + * <h4>File attributes</h4> + * + * The <a href="attribute/package-summary.html">{@code java.nio.file.attribute}</a> + * package provides access to file attributes or <em>meta-data</em> associated + * with files. The {@link Attributes Attributes} class defines methods that + * operate on or return file attributes. For example, the file type, size, + * timestamps, and other <em>basic</em> meta-data are obtained, in bulk, by + * invoking the {@link Attributes#readBasicFileAttributes + * Attributes.readBasicFileAttributes} method: + * <pre> + * Path file = ... + * BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file); + * </pre> + * + * <a name="interop"><h4>Interoperability</h4></a> + * + * <p> Paths created by file systems associated with the default {@link + * java.nio.file.spi.FileSystemProvider provider} are generally interoperable + * with the {@link java.io.File java.io.File} class. Paths created by other + * providers are unlikely to be interoperable with the abstract path names + * represented by {@code java.io.File}. The {@link java.io.File#toPath + * File.toPath} method may be used to obtain a {@code Path} from the abstract + * path name represented by a {@code java.io.File java.io.File} object. The + * resulting {@code Path} can be used to operate on the same file as the {@code + * java.io.File} object. + * + * <p> Path objects created by file systems associated with the default + * provider are interoperable with objects created by other file systems created + * by the same provider. Path objects created by file systems associated with + * other providers may not be interoperable with other file systems created by + * the same provider. The reasons for this are provider specific. + * + * <h4>Concurrency</h4></a> + * + * <p> Instances of this class are immutable and safe for use by multiple concurrent + * threads. + * + * @since 1.7 + */ + +public abstract class Path + implements FileRef, Comparable<Path>, Iterable<Path>, Watchable +{ + /** + * Initializes a new instance of this class. + */ + protected Path() { } + + /** + * Returns the file system that created this object. + * + * @return the file system that created this object + */ + public abstract FileSystem getFileSystem(); + + /** + * Tells whether or not this path is absolute. + * + * <p> An absolute path is complete in that it doesn't need to be + * combined with other path information in order to locate a file. + * + * @return {@code true} if, and only if, this path is absolute + */ + public abstract boolean isAbsolute(); + + /** + * Returns the root component of this path as a {@code Path} object, + * or {@code null} if this path does not have a root component. + * + * @return a path representing the root component of this path, + * or {@code null} + */ + public abstract Path getRoot(); + + /** + * Returns the name of the file or directory denoted by this path. The + * file name is the <em>farthest</em> element from the root in the directory + * hierarchy. + * + * @return a path representing the name of the file or directory, or + * {@code null} if this path has zero elements + */ + public abstract Path getName(); + + /** + * Returns the <em>parent path</em>, or {@code null} if this path does not + * have a parent. + * + * <p> The parent of this path object consists of this path's root + * component, if any, and each element in the path except for the + * <em>farthest</em> from the root in the directory hierarchy. This method + * does not access the file system; the path or its parent may not exist. + * Furthermore, this method does not eliminate special names such as "." + * and ".." that may be used in some implementations. On UNIX for example, + * the parent of "{@code /a/b/c}" is "{@code /a/b}", and the parent of + * {@code "x/y/.}" is "{@code x/y}". This method may be used with the {@link + * #normalize normalize} method, to eliminate redundant names, for cases where + * <em>shell-like</em> navigation is required. + * + * <p> If this path has one or more elements, and no root component, then + * this method is equivalent to evaluating the expression: + * <blockquote><pre> + * subpath(0, getNameCount()-1); + * </pre></blockquote> + * + * @return a path representing the path's parent + */ + public abstract Path getParent(); + + /** + * Returns the number of name elements in the path. + * + * @return the number of elements in the path, or {@code 0} if this path + * only represents a root component + */ + public abstract int getNameCount(); + + /** + * Returns a name element of this path. + * + * <p> The {@code index} parameter is the index of the name element to return. + * The element that is <em>closest</em> to the root in the directory hierarchy + * has index {@code 0}. The element that is <em>farthest</em> from the root + * has index {@link #getNameCount count}{@code -1}. + * + * @param index + * the index of the element + * + * @return the name element + * + * @throws IllegalArgumentException + * if {@code index} is negative, {@code index} is greater than or + * equal to the number of elements, or this path has zero name + * elements + */ + public abstract Path getName(int index); + + /** + * Returns a relative {@code Path} that is a subsequence of the name + * elements of this path. + * + * <p> The {@code beginIndex} and {@code endIndex} parameters specify the + * subsequence of name elements. The name that is <em>closest</em> to the root + * in the directory hierarchy has index {@code 0}. The name that is + * <em>farthest</em> from the root has index {@link #getNameCount + * count}{@code -1}. The returned {@code Path} object has the name elements + * that begin at {@code beginIndex} and extend to the element at index {@code + * endIndex-1}. + * + * @param beginIndex + * the index of the first element, inclusive + * @param endIndex + * the index of the last element, exclusive + * + * @return a new {@code Path} object that is a subsequence of the name + * elements in this {@code Path} + * + * @throws IllegalArgumentException + * if {@code beginIndex} is negative, or greater than or equal to + * the number of elements. If {@code endIndex} is less than or + * equal to {@code beginIndex}, or larger than the number of elements. + */ + public abstract Path subpath(int beginIndex, int endIndex); + + /** + * Tests if this path starts with the given path. + * + * <p> This path <em>starts</em> with the given path if this path's root + * component <em>starts</em> with the root component of the given path, + * and this path starts with the same name elements as the given path. + * If the given path has more name elements than this path then {@code false} + * is returned. + * + * <p> Whether or not the root component of this path starts with the root + * component of the given path is file system specific. If this path does + * not have a root component and the given path has a root component then + * this path does not start with the given path. + * + * @param other + * the given path + * + * @return {@code true} if this path starts with the given path; otherwise + * {@code false} + */ + public abstract boolean startsWith(Path other); + + /** + * Tests if this path ends with the given path. + * + * <p> If the given path has <em>N</em> elements, and no root component, + * and this path has <em>N</em> or more elements, then this path ends with + * the given path if the last <em>N</em> elements of each path, starting at + * the element farthest from the root, are equal. + * + * <p> If the given path has a root component then this path ends with the + * given path if the root component of this path <em>ends with</em> the root + * component of the given path, and the corresponding elements of both paths + * are equal. Whether or not the root component of this path ends with the + * root component of the given path is file system specific. If this path + * does not have a root component and the given path has a root component + * then this path does not end with the given path. + * + * @param other + * the given path + * + * @return {@code true} if this path ends with the given path; otherwise + * {@code false} + */ + public abstract boolean endsWith(Path other); + + /** + * Returns a path that is this path with redundant name elements eliminated. + * + * <p> The precise definition of this method is implementation dependent but + * in general it derives from this path, a path that does not contain + * <em>redundant</em> name elements. In many file systems, the "{@code .}" + * and "{@code ..}" are special names used to indicate the current directory + * and parent directory. In such file systems all occurrences of "{@code .}" + * are considered redundant. If a "{@code ..}" is preceded by a + * non-"{@code ..}" name then both names are considered redundant (the + * process to identify such names is repeated until is it no longer + * applicable). + * + * <p> This method does not access the file system; the path may not locate + * a file that exists. Eliminating "{@code ..}" and a preceding name from a + * path may result in the path that locates a different file than the original + * path. This can arise when the preceding name is a symbolic link. + * + * @return the resulting path, or this path if it does not contain + * redundant name elements, or {@code null} if this path does not + * have a root component and all name elements are redundant + * + * @see #getParent + * @see #toRealPath + */ + public abstract Path normalize(); + + // -- resolution and relativization -- + + /** + * Resolve the given path against this path. + * + * <p> If the {@code other} parameter is an {@link #isAbsolute() absolute} + * path then this method trivially returns {@code other}. If {@code other} + * is {@code null} then this path is returned. Otherwise this method + * considers this path to be a directory and resolves the given path + * against this path. In the simplest case, the given path does not have + * a {@link #getRoot root} component, in which case this method <em>joins</em> + * the given path to this path and returns a resulting path that {@link + * #endsWith ends} with the given path. Where the given path has a root + * component then resolution is highly implementation dependent and therefore + * unspecified. + * + * @param other + * the path to resolve against this path; can be {@code null} + * + * @return the resulting path + * + * @see #relativize + */ + public abstract Path resolve(Path other); + + /** + * Converts a given path string to a {@code Path} and resolves it against + * this {@code Path} in exactly the manner specified by the {@link + * #resolve(Path) resolve} method. + * + * @param other + * the path string to resolve against this path + * + * @return the resulting path + * + * @throws InvalidPathException + * If the path string cannot be converted to a Path. + * + * @see FileSystem#getPath + */ + public abstract Path resolve(String other); + + /** + * Constructs a relative path between this path and a given path. + * + * <p> Relativization is the inverse of {@link #resolve(Path) resolution}. + * This method attempts to construct a {@link #isAbsolute relative} path + * that when {@link #resolve(Path) resolved} against this path, yields a + * path that locates the same file as the given path. For example, on UNIX, + * if this path is {@code "/a/b"} and the given path is {@code "/a/b/c/d"} + * then the resulting relative path would be {@code "c/d"}. Where this + * path and the given path do not have a {@link #getRoot root} component, + * then a relative path can be constructed. A relative path cannot be + * constructed if only one of the paths have a root component. Where both + * paths have a root component then it is implementation dependent if a + * relative path can be constructed. If this path and the given path are + * {@link #equals equal} then {@code null} is returned. + * + * <p> For any two paths <i>p</i> and <i>q</i>, where <i>q</i> does not have + * a root component, + * <blockquote> + * <i>p</i><tt>.relativize(</tt><i>p</i><tt>.resolve(</tt><i>q</i><tt>)).equals(</tt><i>q</i><tt>)</tt> + * </blockquote> + * + * <p> When symbolic-links are supported, then whether the resulting path, + * when resolved against this path, yields a path that can be used to locate + * the {@link #isSameFile same} file as {@code other} is implementation + * dependent. For example, if this path is {@code "/a/b"} and the given + * path is {@code "/a/x"} then the resulting relative path may be {@code + * "../x"}. If {@code "b"} is a symbolic-link then is implementation + * dependent if {@code "a/b/../x"} would locate the same file as {@code "/a/x"}. + * + * @param other + * the resulting path + * + * @return the resulting relative path, or {@code null} if both paths are + * equal + * + * @throws IllegalArgumentException + * if {@code other} is not a {@code Path} that can be relativized + * against this path + */ + public abstract Path relativize(Path other); + + // -- file operations -- + + /** + * Deletes the file located by this path. + * + * <p> The {@code failIfNotExists} parameter determines how the method + * behaves when the file does not exist. When {@code true}, and the file + * does not exist, then the method fails. When {@code false} then the method + * does not fail. + * + * <p> As with the {@link FileRef#delete delete()} method, an implementation + * may require to examine the file to determine if the file is a directory. + * Consequently this method may not be atomic with respect to other file + * system operations. If the file is a symbolic-link then the link is + * deleted and not the final target of the link. + * + * <p> If the file is a directory then the directory must be empty. In some + * implementations a directory has entries for special files or links that + * are created when the directory is created. In such implementations a + * directory is considered empty when only the special entries exist. + * + * <p> On some operating systems it may not be possible to remove a file when + * it is open and in use by this Java virtual machine or other programs. + * + * @param failIfNotExists + * {@code true} if the method should fail when the file does not + * exist + * + * @throws NoSuchFileException + * if the value of the {@code failIfNotExists} is {@code true} and + * the file does not exist <i>(optional specific exception)</i> + * @throws DirectoryNotEmptyException + * if the file is a directory and could not otherwise be deleted + * because the directory is not empty <i>(optional specific + * exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkDelete(String)} method + * is invoked to check delete access to the file. + */ + public abstract void delete(boolean failIfNotExists) throws IOException; + + /** + * Creates a symbolic link to a target <i>(optional operation)</i>. + * + * <p> The {@code target} parameter is the target of the link. It may be an + * {@link Path#isAbsolute absolute} or relative path and may not exist. When + * the target is a relative path then file system operations on the resulting + * link are relative to the path of the link. + * + * <p> The {@code attrs} parameter is an optional array of {@link FileAttribute + * attributes} to set atomically when creating the link. Each attribute is + * identified by its {@link FileAttribute#name name}. If more than one attribute + * of the same name is included in the array then all but the last occurrence + * is ignored. + * + * <p> Where symbolic links are supported, but the underlying {@link FileStore} + * does not support symbolic links, then this may fail with an {@link + * IOException}. Additionally, some operating systems may require that the + * Java virtual machine be started with implementation specific privileges to + * create symbolic links, in which case this method may throw {@code IOException}. + * + * @param target + * the target of the link + * @param attrs + * the array of attributes to set atomically when creating the + * symbolic link + * + * @return this path + * + * @throws UnsupportedOperationException + * if the implementation does not support symbolic links or the + * array contains an attribute that cannot be set atomically when + * creating the symbolic link + * @throws FileAlreadyExistsException + * if a file with the name already exists <i>(optional specific + * exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the the default provider, and a security manager + * is installed, it denies {@link LinkPermission}<tt>("symbolic")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the path of the symbolic link. + */ + public abstract Path createSymbolicLink(Path target, FileAttribute<?>... attrs) + throws IOException; + + /** + * Creates a new link (directory entry) for an existing file <i>(optional + * operation)</i>. + * + * <p> This path locates the directory entry to create. The {@code existing} + * parameter is the path to an existing file. This method creates a new + * directory entry for the file so that it can be accessed using this path. + * On some file systems this is known as creating a "hard link". Whether the + * file attributes are maintained for the file or for each directory entry + * is file system specific and therefore not specified. Typically, a file + * system requires that all links (directory entries) for a file be on the + * same file system. Furthermore, on some platforms, the Java virtual machine + * may require to be started with implementation specific privileges to + * create hard links or to create links to directories. + * + * @param existing + * a reference to an existing file + * + * @return this path + * + * @throws UnsupportedOperationException + * if the implementation does not support adding an existing file + * to a directory + * @throws FileAlreadyExistsException + * if the entry could not otherwise be created because a file of + * that name already exists <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the the default provider, and a security manager + * is installed, it denies {@link LinkPermission}<tt>("hard")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to both this path and the path of the + * existing file. + * + * @see BasicFileAttributes#linkCount + */ + public abstract Path createLink(Path existing) throws IOException; + + /** + * Reads the target of a symbolic link <i>(optional operation)</i>. + * + * <p> If the file system supports <a href="package-summary.html#links">symbolic + * links</a> then this method is used read the target of the link, failing + * if the file is not a link. The target of the link need not exist. The + * returned {@code Path} object will be associated with the same file + * system as this {@code Path}. + * + * @return a {@code Path} object representing the target of the link + * + * @throws UnsupportedOperationException + * if the implementation does not support symbolic links + * @throws NotLinkException + * if the target could otherwise not be read because the file + * is not a link <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the the default provider, and a security manager + * is installed, it checks that {@code FilePermission} has been + * granted with the "{@code readlink}" action to read the link. + */ + public abstract Path readSymbolicLink() throws IOException; + + /** + * Returns a URI to represent this path. + * + * <p> This method constructs a hierarchical {@link URI} that is absolute + * with a non-empty path component. Its {@link URI#getScheme() scheme} is + * equal to the URI scheme that identifies the provider. The exact form of + * the other URI components is highly provider dependent. In particular, it + * is implementation dependent if its query, fragment, and authority + * components are defined or undefined. + * + * <p> For the default provider the {@link URI#getPath() path} component + * will represent the {@link #toAbsolutePath absolute} path; the query, + * fragment components are undefined. Whether the authority component is + * defined or not is implementation dependent. There is no guarantee that + * the {@code URI} may be used to construct a {@link java.io.File java.io.File}. + * In particular, if this path represents a Universal Naming Convention (UNC) + * path, then the UNC server name may be encoded in the authority component + * of the resulting URI. In the case of the default provider, and the file + * exists, and it can be determined that the file is a directory, then the + * resulting {@code URI} will end with a slash. + * + * <p> The default provider provides a similar <em>round-trip</em> guarantee + * to the {@link java.io.File} class. For a given {@code Path} <i>p</i> it + * is guaranteed that + * <blockquote><tt> + * {@link Paths#get(URI) Paths.get}(</tt><i>p</i><tt>.toUri()).equals(</tt><i>p</i> + * <tt>.{@link #toAbsolutePath() toAbsolutePath}())</tt> + * </blockquote> + * so long as the original {@code Path}, the {@code URI}, and the new {@code + * Path} are all created in (possibly different invocations of) the same + * Java virtual machine. Whether other providers make any guarantees is + * provider specific and therefore unspecified. + * + * <p> When a file system is constructed to access the contents of a file + * as a file system then it is highly implementation specific if the returned + * URI represents the given path in the file system or it represents a + * <em>compound</em> URI that encodes the URI of the enclosing file system. + * A format for compound URIs is not defined in this release; such a scheme + * may be added in a future release. + * + * @return an absolute, hierarchical URI with a non-empty path component + * + * @throws IOError + * if an I/O error occurs obtaining the absolute path, or where a + * file system is constructed to access the contents of a file as + * a file system, and the URI of the enclosing file system cannot be + * obtained + * + * @throws SecurityException + * In the case of the the default provider, and a security manager + * is installed, the {@link #toAbsolutePath toAbsolutePath} method + * throws a security exception. + */ + public abstract URI toUri(); + + /** + * Returns a {@code Path} object representing the absolute path of this + * path. + * + * <p> If this path is already {@link Path#isAbsolute absolute} then this + * method simply returns this path. Otherwise, this method resolves the path + * in an implementation dependent manner, typically by resolving the path + * against a file system default directory. Depending on the implementation, + * this method may throw an I/O error if the file system is not accessible. + * + * @return a {@code Path} object representing the absolute path + * + * @throws IOError + * if an I/O error occurs + * @throws SecurityException + * In the case of the the default provider, and a security manager + * is installed, its {@link SecurityManager#checkPropertyAccess(String) + * checkPropertyAccess} method is invoked to check access to the + * system property {@code user.dir} + */ + public abstract Path toAbsolutePath(); + + /** + * Returns the <em>real</em> path of an existing file. + * + * <p> The precise definition of this method is implementation dependent but + * in general it derives from this path, an {@link #isAbsolute absolute} + * path that locates the {@link #isSameFile same} file as this path, but + * with name elements that represent the actual name of the directories + * and the file. For example, where filename comparisons on a file system + * are case insensitive then the name elements represent the names in their + * actual case. Additionally, the resulting path has redundant name + * elements removed. + * + * <p> If this path is relative then its absolute path is first obtained, + * as if by invoking the {@link #toAbsolutePath toAbsolutePath} method. + * + * <p> The {@code resolveLinks} parameter specifies if symbolic links + * should be resolved. This parameter is ignored when symbolic links are + * not supported. Where supported, and the parameter has the value {@code + * true} then symbolic links are resolved to their final target. Where the + * parameter has the value {@code false} then this method does not resolve + * symbolic links. Some implementations allow special names such as + * "{@code ..}" to refer to the parent directory. When deriving the <em>real + * path</em>, and a "{@code ..}" (or equivalent) is preceded by a + * non-"{@code ..}" name then an implementation will typically causes both + * names to be removed. When not resolving symbolic links and the preceding + * name is a symbolic link then the names are only removed if it guaranteed + * that the resulting path will locate the same file as this path. + * + * @return an absolute path represent the <em>real</em> path of the file + * located by this object + * + * @throws IOException + * if the file does not exist or an I/O error occurs + * @throws SecurityException + * In the case of the the default provider, and a security manager + * is installed, its {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file, and where + * this path is not absolute, its {@link SecurityManager#checkPropertyAccess(String) + * checkPropertyAccess} method is invoked to check access to the + * system property {@code user.dir} + */ + public abstract Path toRealPath(boolean resolveLinks) throws IOException; + + /** + * Copy the file located by this path to a target location. + * + * <p> This method copies the file located by this {@code Path} to the + * target location with the {@code options} parameter specifying how the + * copy is performed. By default, the copy fails if the target file already + * exists, except if the source and target are the {@link #isSameFile same} + * file, in which case this method has no effect. File attributes are not + * required to be copied to the target file. If symbolic links are supported, + * and the file is a link, then the final target of the link is copied. If + * the file is a directory then it creates an empty directory in the target + * location (entries in the directory are not copied). This method can be + * used with the {@link Files#walkFileTree Files.walkFileTree} utility + * method to copy a directory and all entries in the directory, or an entire + * <i>file-tree</i> where required. + * + * <p> The {@code options} parameter is an array of options and may contain + * any of the following: + * + * <table border=1 cellpadding=5 summary=""> + * <tr> <th>Option</th> <th>Description</th> </tr> + * <tr> + * <td> {@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} </td> + * <td> If the target file exists, then the target file is replaced if it + * is not a non-empty directory. If the target file exists and is a + * symbolic-link then the symbolic-link is replaced (not the target of + * the link. </td> + * </tr> + * <tr> + * <td> {@link StandardCopyOption#COPY_ATTRIBUTES COPY_ATTRIBUTES} </td> + * <td> Attempts to copy the file attributes associated with this file to + * the target file. The exact file attributes that are copied is platform + * and file system dependent and therefore unspecified. Minimally, the + * {@link BasicFileAttributes#lastModifiedTime last-modified-time} is + * copied to the target file. </td> + * </tr> + * <tr> + * <td> {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} </td> + * <td> Symbolic-links are not followed. If the file, located by this path, + * is a symbolic-link then the link is copied rather than the target of + * the link. It is implementation specific if file attributes can be + * copied to the new link. In other words, the {@code COPY_ATTRIBUTES} + * option may be ignored when copying a link. </td> + * </tr> + * </table> + * + * <p> An implementation of this interface may support additional + * implementation specific options. + * + * <p> Copying a file is not an atomic operation. If an {@link IOException} + * is thrown then it possible that the target file is incomplete or some of + * its file attributes have not been copied from the source file. When the + * {@code REPLACE_EXISTING} option is specified and the target file exists, + * then the target file is replaced. The check for the existence of the file + * and the creation of the new file may not be atomic with respect to other + * file system activities. + * + * @param target + * the target location + * @param options + * options specifying how the copy should be done + * + * @return the target + * + * @throws UnsupportedOperationException + * if the array contains a copy option that is not supported + * @throws FileAlreadyExistsException + * if the target file exists and cannot be replaced because the + * {@code REPLACE_EXISTING} option is not specified, or the target + * file is a non-empty directory <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the source file, the + * {@link SecurityManager#checkWrite(String) checkWrite} is invoked + * to check write access to the target file. If a symbolic link is + * copied the security manager is invoked to check {@link + * LinkPermission}{@code ("symbolic")}. + */ + public abstract Path copyTo(Path target, CopyOption... options) + throws IOException; + + /** + * Move or rename the file located by this path to a target location. + * + * <p> By default, this method attempts to move the file to the target + * location, failing if the target file exists except if the source and + * target are the {@link #isSameFile same} file, in which case this method + * has no effect. If the file is a symbolic link then the link is moved and + * not the target of the link. This method may be invoked to move an empty + * directory. In some implementations a directory has entries for special + * files or links that are created when the directory is created. In such + * implementations a directory is considered empty when only the special + * entries exist. When invoked to move a directory that is not empty then the + * directory is moved if it does not require moving the entries in the directory. + * For example, renaming a directory on the same {@link FileStore} will usually + * not require moving the entries in the directory. When moving a directory + * requires that its entries be moved then this method fails (by throwing + * an {@code IOException}). To move a <i>file tree</i> may involve copying + * rather than moving directories and this can be done using the {@link + * #copyTo copyTo} method in conjunction with the {@link + * Files#walkFileTree Files.walkFileTree} utility method. + * + * <p> The {@code options} parameter is an array of options and may contain + * any of the following: + * + * <table border=1 cellpadding=5 summary=""> + * <tr> <th>Option</th> <th>Description</th> </tr> + * <tr> + * <td> {@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} </td> + * <td> If the target file exists, then the target file is replaced if it + * is not a non-empty directory. If the target file exists and is a + * symbolic-link then the symbolic-link is replaced and not the target of + * the link. </td> + * </tr> + * <tr> + * <td> {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} </td> + * <td> The move is performed as an atomic file system operation and all + * other options are ignored. If the target file exists then it is + * implementation specific if the existing file is replaced or this method + * fails by throwing an {@link IOException}. If the move cannot be + * performed as an atomic file system operation then {@link + * AtomicMoveNotSupportedException} is thrown. This can arise, for + * example, when the target location is on a different {@code FileStore} + * and would require that the file be copied, or target location is + * associated with a different provider to this object. </td> + * </table> + * + * <p> An implementation of this interface may support additional + * implementation specific options. + * + * <p> Where the move requires that the file be copied then the {@link + * BasicFileAttributes#lastModifiedTime last-modified-time} is copied to the + * new file. An implementation may also attempt to copy other file + * attributes but is not required to fail if the file attributes cannot be + * copied. When the move is performed as a non-atomic operation, and a {@code + * IOException} is thrown, then the state of the files is not defined. The + * original file and the target file may both exist, the target file may be + * incomplete or some of its file attributes may not been copied from the + * original file. + * + * @param target + * the target location + * @param options + * options specifying how the move should be done + * + * @return the target + * + * @throws UnsupportedOperationException + * if the array contains a copy option that is not supported + * @throws FileAlreadyExistsException + * if the target file exists and cannot be replaced because the + * {@code REPLACE_EXISTING} option is not specified, or the target + * file is a non-empty directory + * @throws AtomicMoveNotSupportedException + * if the options array contains the {@code ATOMIC_MOVE} option but + * the file cannot be moved as an atomic file system operation. + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to both the source and + * target file. + */ + public abstract Path moveTo(Path target, CopyOption... options) + throws IOException; + + /** + * Opens the directory referenced by this object, returning a {@code + * DirectoryStream} to iterate over all entries in the directory. The + * elements returned by the directory stream's {@link DirectoryStream#iterator + * iterator} are of type {@code Path}, each one representing an entry in the + * directory. The {@code Path} objects are obtained as if by {@link + * #resolve(Path) resolving} the name of the directory entry against this + * path. + * + * <p> The directory stream's {@code close} method should be invoked after + * iteration is completed so as to free any resources held for the open + * directory. The {@link Files#withDirectory Files.withDirectory} utility + * method is useful for cases where a task is performed on each accepted + * entry in a directory. This method closes the directory when iteration is + * complete (or an error occurs). + * + * <p> When an implementation supports operations on entries in the + * directory that execute in a race-free manner then the returned directory + * stream is a {@link SecureDirectoryStream}. + * + * @return a new and open {@code DirectoryStream} object + * + * @throws NotDirectoryException + * if the file could not otherwise be opened because it is not + * a directory <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the directory. + */ + public abstract DirectoryStream<Path> newDirectoryStream() + throws IOException; + + /** + * Opens the directory referenced by this object, returning a {@code + * DirectoryStream} to iterate over the entries in the directory. The + * elements returned by the directory stream's {@link DirectoryStream#iterator + * iterator} are of type {@code Path}, each one representing an entry in the + * directory. The {@code Path} objects are obtained as if by {@link + * #resolve(Path) resolving} the name of the directory entry against this + * path. The entries returned by the iterator are filtered by matching the + * {@code String} representation of their file names against the given + * <em>globbing</em> pattern. + * + * <p> For example, suppose we want to iterate over the files ending with + * ".java" in a directory: + * <pre> + * Path dir = ... + * DirectoryStream<Path> stream = dir.newDirectoryStream("*.java"); + * </pre> + * + * <p> The globbing pattern is specified by the {@link + * FileSystem#getPathMatcher getPathMatcher} method. + * + * <p> The directory stream's {@code close} method should be invoked after + * iteration is completed so as to free any resources held for the open + * directory. + * + * <p> When an implementation supports operations on entries in the + * directory that execute in a race-free manner then the returned directory + * stream is a {@link SecureDirectoryStream}. + * + * @param glob + * the glob pattern + * + * @return a new and open {@code DirectoryStream} object + * + * @throws java.util.regex.PatternSyntaxException + * if the pattern is invalid + * @throws UnsupportedOperationException + * if the pattern syntax is not known to the implementation + * @throws NotDirectoryException + * if the file could not otherwise be opened because it is not + * a directory <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the directory. + */ + public abstract DirectoryStream<Path> newDirectoryStream(String glob) + throws IOException; + + /** + * Opens the directory referenced by this object, returning a {@code + * DirectoryStream} to iterate over the entries in the directory. The + * elements returned by the directory stream's {@link DirectoryStream#iterator + * iterator} are of type {@code Path}, each one representing an entry in the + * directory. The {@code Path} objects are obtained as if by {@link + * #resolve(Path) resolving} the name of the directory entry against this + * path. The entries returned by the iterator are filtered by the given + * {@link DirectoryStream.Filter filter}. The {@link DirectoryStreamFilters} + * class defines factory methods that create useful filters. + * + * <p> The directory stream's {@code close} method should be invoked after + * iteration is completed so as to free any resources held for the open + * directory. The {@link Files#withDirectory Files.withDirectory} utility + * method is useful for cases where a task is performed on each accepted + * entry in a directory. This method closes the directory when iteration is + * complete (or an error occurs). + * + * <p> Where the filter terminates due to an uncaught error or runtime + * exception then it propogated to the caller of the iterator's {@link + * Iterator#hasNext() hasNext} or {@link Iterator#next() next} methods. + * + * <p> When an implementation supports operations on entries in the + * directory that execute in a race-free manner then the returned directory + * stream is a {@link SecureDirectoryStream}. + * + * <p> <b>Usage Example:</b> + * Suppose we want to iterate over the files in a directory that are + * larger than 8K. + * <pre> + * DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() { + * public boolean accept(Path file) { + * try { + * long size = Attributes.readBasicFileAttributes(file).size(); + * return (size > 8192L); + * } catch (IOException e) { + * // failed to get size + * return false; + * } + * } + * }; + * Path dir = ... + * DirectoryStream<Path> stream = dir.newDirectoryStream(filter); + * </pre> + * @param filter + * the directory stream filter + * + * @return a new and open {@code DirectoryStream} object + * + * @throws NotDirectoryException + * if the file could not otherwise be opened because it is not + * a directory <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the directory. + */ + public abstract DirectoryStream<Path> newDirectoryStream(DirectoryStream.Filter<? super Path> filter) + throws IOException; + + /** + * Creates a new and empty file, failing if the file already exists. + * + * <p> This {@code Path} locates the file to create. The check for the + * existence of the file and the creation of the new file if it does not + * exist are a single operation that is atomic with respect to all other + * filesystem activities that might affect the directory. + * + * <p> The {@code attrs} parameter is an optional array of {@link FileAttribute + * file-attributes} to set atomically when creating the file. Each attribute + * is identified by its {@link FileAttribute#name name}. If more than one + * attribute of the same name is included in the array then all but the last + * occurrence is ignored. + * + * @param attrs + * an optional list of file attributes to set atomically when + * creating the file + * + * @return this path + * + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the file + * @throws FileAlreadyExistsException + * if a file of that name already exists + * <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the new file. + */ + public abstract Path createFile(FileAttribute<?>... attrs) throws IOException; + + /** + * Creates a new directory. + * + * <p> This {@code Path} locates the directory to create. The check for the + * existence of the file and the creation of the directory if it does not + * exist are a single operation that is atomic with respect to all other + * filesystem activities that might affect the directory. + * + * <p> The {@code attrs} parameter is an optional array of {@link FileAttribute + * file-attributes} to set atomically when creating the directory. Each + * file attribute is identified by its {@link FileAttribute#name name}. If + * more than one attribute of the same name is included in the array then all + * but the last occurrence is ignored. + * + * @param attrs + * an optional list of file attributes to set atomically when + * creating the directory + * + * @return this path + * + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the directory + * @throws FileAlreadyExistsException + * if a directory could not otherwise be created because a file of + * that name already exists <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the new directory. + */ + public abstract Path createDirectory(FileAttribute<?>... attrs) + throws IOException; + + /** + * Opens or creates a file, returning a seekable byte channel to access the + * file. + * + * <p> The {@code options} parameter determines how the file is opened. + * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE WRITE} + * options determine if the file should be opened for reading and/or writing. + * If neither option (or the {@link StandardOpenOption#APPEND APPEND} + * option) is contained in the array then the file is opened for reading. + * By default reading or writing commences at the beginning of the file. + * + * <p> In the addition to {@code READ} and {@code WRITE}, the following + * options may be present: + * + * <table border=1 cellpadding=5 summary=""> + * <tr> <th>Option</th> <th>Description</th> </tr> + * <tr> + * <td> {@link StandardOpenOption#APPEND APPEND} </td> + * <td> If this option is present then the file is opened for writing and + * each invocation of the channel's {@code write} method first advances + * the position to the end of the file and then writes the requested + * data. Whether the advancement of the position and the writing of the + * data are done in a single atomic operation is system-dependent and + * therefore unspecified. This option may not be used in conjunction + * with the {@code READ} or {@code TRUNCATE_EXISTING} options. </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td> + * <td> If this option is present then the existing file is truncated to + * a size of 0 bytes. This option is ignored when the file is opened only + * for reading. </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td> + * <td> If this option is present then a new file is created, failing if + * the file already exists or is a symbolic link. When creating a file the + * check for the existence of the file and the creation of the file if it + * does not exist is atomic with respect to other file system operations. + * This option is ignored when the file is opened only for reading. </td> + * </tr> + * <tr> + * <td > {@link StandardOpenOption#CREATE CREATE} </td> + * <td> If this option is present then an existing file is opened if it + * exists, otherwise a new file is created. This option is ignored if the + * {@code CREATE_NEW} option is also present or the file is opened only + * for reading. </td> + * </tr> + * <tr> + * <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td> + * <td> When this option is present then the implementation makes a + * <em>best effort</em> attempt to delete the file when closed by the + * {@link SeekableByteChannel#close close} method. If the {@code close} + * method is not invoked then a <em>best effort</em> attempt is made to + * delete the file when the Java virtual machine terminates. </td> + * </tr> + * <tr> + * <td>{@link StandardOpenOption#SPARSE SPARSE} </td> + * <td> When creating a new file this option is a <em>hint</em> that the + * new file will be sparse. This option is ignored when not creating + * a new file. </td> + * </tr> + * <tr> + * <td> {@link StandardOpenOption#SYNC SYNC} </td> + * <td> Requires that every update to the file's content or metadata be + * written synchronously to the underlying storage device. (see <a + * href="package-summary.html#integrity"> Synchronized I/O file + * integrity</a>). </td> + * <tr> + * <tr> + * <td> {@link StandardOpenOption#DSYNC DSYNC} </td> + * <td> Requires that every update to the file's content be written + * synchronously to the underlying storage device. (see <a + * href="package-summary.html#integrity"> Synchronized I/O file + * integrity</a>). </td> + * </tr> + * </table> + * + * <p> An implementation may also support additional implementation specific + * options. + * + * <p> The {@code attrs} parameter is an optional array of file {@link + * FileAttribute file-attributes} to set atomically when a new file is created. + * + * <p> In the case of the default provider, the returned seekable byte channel + * is a {@link FileChannel}. + * + * <p> <b>Usage Examples:</b> + * <pre> + * Path file = ... + * + * // open file for reading + * ReadableByteChannel rbc = file.newByteChannel(EnumSet.of(READ))); + * + * // open file for writing to the end of an existing file, creating + * // the file if it doesn't already exist + * WritableByteChannel wbc = file.newByteChannel(EnumSet.of(CREATE,APPEND)); + * + * // create file with initial permissions, opening it for both reading and writing + * FileAttribute<Set<PosixFilePermission>> perms = ... + * SeekableByteChannel sbc = file.newByteChannel(EnumSet.of(CREATE_NEW,READ,WRITE), perms); + * </pre> + * + * @param options + * Options specifying how the file is opened + * @param attrs + * An optional list of file attributes to set atomically when + * creating the file + * + * @return a new seekable byte channel + * + * @throws IllegalArgumentException + * if the set contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported open option is specified or the array contains + * attributes that cannot be set atomically when creating the file + * @throws FileAlreadyExistsException + * if a file of that name already exists and the {@link + * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified + * <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the path if the file is + * opened for reading. The {@link SecurityManager#checkWrite(String) + * checkWrite} method is invoked to check write access to the path + * if the file is opened for writing. + */ + public abstract SeekableByteChannel newByteChannel(Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException; + + /** + * Opens or creates a file, returning a seekable byte channel to access the + * file. + * + * <p> This method extends the options defined by the {@code FileRef} + * interface and to the options specified by the {@link + * #newByteChannel(Set,FileAttribute[]) newByteChannel} method + * except that the options are specified by an array. In the case of the + * default provider, the returned seekable byte channel is a {@link + * FileChannel}. + * + * @param options + * options specifying how the file is opened + * + * @return a new seekable byte channel + * + * @throws IllegalArgumentException + * if the set contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported open option is specified + * @throws FileAlreadyExistsException + * if a file of that name already exists and the {@link + * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified + * <i>(optional specific exception)</i> + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public abstract SeekableByteChannel newByteChannel(OpenOption... options) + throws IOException; + + /** + * Opens the file located by this path for reading, returning an input + * stream to read bytes from the file. The stream will not be buffered, and + * is not required to support the {@link InputStream#mark mark} or {@link + * InputStream#reset reset} methods. The stream will be safe for access by + * multiple concurrent threads. Reading commences at the beginning of the file. + * + * @return an input stream to read bytes from the file + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + public abstract InputStream newInputStream() throws IOException; + + /** + * Opens or creates the file located by this path for writing, returning an + * output stream to write bytes to the file. + * + * <p> This method opens or creates a file in exactly the manner specified + * by the {@link Path#newByteChannel(Set,FileAttribute[]) newByteChannel} + * method except that the {@link StandardOpenOption#READ READ} option may not + * be present in the array of open options. If no open options are present + * then this method creates a new file for writing or truncates an existing + * file. + * + * <p> The resulting stream will not be buffered. The stream will be safe + * for access by multiple concurrent threads. + * + * <p> <b>Usage Example:</b> + * Suppose we wish to open a log file for writing so that we append to the + * file if it already exists, or create it when it doesn't exist. + * <pre> + * Path logfile = ... + * OutputStream out = new BufferedOutputStream(logfile.newOutputStream(CREATE, APPEND)); + * </pre> + * + * @param options + * options specifying how the file is opened + * + * @return a new seekable byte channel + * + * @throws IllegalArgumentException + * if {@code options} contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported open option is specified + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. + */ + public abstract OutputStream newOutputStream(OpenOption... options) + throws IOException; + + /** + * Opens or creates the file located by this path for writing, returning an + * output stream to write bytes to the file. + * + * <p> This method opens or creates a file in exactly the manner specified + * by the {@link Path#newByteChannel(Set,FileAttribute[]) newByteChannel} + * method except that {@code options} parameter may not contain the {@link + * StandardOpenOption#READ READ} option. If no open options are present + * then this method creates a new file for writing or truncates an existing + * file. + * + * <p> The resulting stream will not be buffered. The stream will be safe + * for access by multiple concurrent threads. + * + * @param options + * options specifying how the file is opened + * @param attrs + * an optional list of file attributes to set atomically when + * creating the file + * + * @return a new output stream + * + * @throws IllegalArgumentException + * if the set contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported open option is specified or the array contains + * attributes that cannot be set atomically when creating the file + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. + */ + public abstract OutputStream newOutputStream(Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException; + + /** + * Tells whether or not the file located by this object is considered + * <em>hidden</em>. The exact definition of hidden is platform or provider + * dependent. On UNIX for example a file is considered to be hidden if its + * name begins with a period character ('.'). On Windows a file is + * considered hidden if it isn't a directory and the DOS {@link + * DosFileAttributes#isHidden hidden} attribute is set. + * + * <p> Depending on the implementation this method may require to access + * the file system to determine if the file is considered hidden. + * + * @return {@code true} if the file is considered hidden + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + public abstract boolean isHidden() throws IOException; + + /** + * Tests whether the file located by this path exists. + * + * <p> This convenience method is intended for cases where it is required to + * take action when it can be confirmed that a file exists. This method simply + * invokes the {@link #checkAccess checkAccess} method to check if the file + * exists. If the {@code checkAccess} method succeeds then this method returns + * {@code true}, otherwise if an {@code IOException} is thrown (because the + * file doesn't exist or cannot be accessed by this Java virtual machine) + * then {@code false} is returned. + * + * <p> Note that the result of this method is immediately outdated. If this + * method indicates the file exists then there is no guarantee that a + * subsequence access will succeed. Care should be taken when using this + * method in security sensitive applications. + * + * @return {@code true} if the file exists; {@code false} if the file does + * not exist or its existence cannot be determined. + * + * @throws SecurityException + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String)} is invoked to check + * read access to the file. + * + * @see #notExists + */ + public abstract boolean exists(); + + /** + * Tests whether the file located by this path does not exist. + * + * <p> This convenience method is intended for cases where it is required to + * take action when it can be confirmed that a file does not exist. This + * method invokes the {@link #checkAccess checkAccess} method to check if the + * file exists. If the file does not exist then {@code true} is returned, + * otherwise the file exists or cannot be accessed by this Java virtual + * machine and {@code false} is returned. + * + * <p> Note that this method is not the complement of the {@link #exists + * exists} method. Where it is not possible to determine if a file exists + * or not then both methods return {@code false}. As with the {@code exists} + * method, the result of this method is immediately outdated. If this + * method indicates the file does exist then there is no guarantee that a + * subsequence attempt to create the file will succeed. Care should be taken + * when using this method in security sensitive applications. + * + * @return {@code true} if the file does not exist; {@code false} if the + * file exists or its existence cannot be determined. + * + * @throws SecurityException + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String)} is invoked to check + * read access to the file. + */ + public abstract boolean notExists(); + + // -- watchable -- + + /** + * Registers the file located by this path with a watch service. + * + * <p> In this release, this path locates a directory that exists. The + * directory is registered with the watch service so that entries in the + * directory can be watched. The {@code events} parameter is an array of + * events to register and may contain the following events: + * <ul> + * <li>{@link StandardWatchEventKind#ENTRY_CREATE ENTRY_CREATE} - + * entry created or moved into the directory</li> + * <li>{@link StandardWatchEventKind#ENTRY_DELETE ENTRY_DELETE} - + * entry deleted or moved out of the directory</li> + * <li>{@link StandardWatchEventKind#ENTRY_MODIFY ENTRY_MODIFY} - + * entry in directory was modified</li> + * </ul> + * + * <p> The {@link WatchEvent#context context} for these events is the + * relative path between the directory located by this path, and the path + * that locates the directory entry that is created, deleted, or modified. + * + * <p> The set of events may include additional implementation specific + * event that are not defined by the enum {@link StandardWatchEventKind} + * + * <p> The {@code modifiers} parameter is an array of <em>modifiers</em> + * that qualify how the directory is registered. This release does not + * define any <em>standard</em> modifiers. The array may contain + * implementation specific modifiers. + * + * <p> Where a file is registered with a watch service by means of a symbolic + * link then it is implementation specific if the watch continues to depend + * on the existence of the link after it is registered. + * + * @param watcher + * the watch service to which this object is to be registered + * @param events + * the events for which this object should be registered + * @param modifiers + * the modifiers, if any, that modify how the object is registered + * + * @return a key representing the registration of this object with the + * given watch service + * + * @throws UnsupportedOperationException + * if unsupported events or modifiers are specified + * @throws IllegalArgumentException + * if an invalid combination of events or modifiers is specified + * @throws ClosedWatchServiceException + * if the watch service is closed + * @throws NotDirectoryException + * if the file is registered to watch the entries in a directory + * and the file is not a directory <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + @Override + public abstract WatchKey register(WatchService watcher, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) + throws IOException; + + /** + * Registers the file located by this path with a watch service. + * + * <p> An invocation of this method behaves in exactly the same way as the + * invocation + * <pre> + * watchable.{@link #register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier[]) register}(watcher, events, new WatchEvent.Modifier[0]); + * </pre> + * + * <p> <b>Usage Example:</b> + * Suppose we wish to register a directory for entry create, delete, and modify + * events: + * <pre> + * Path dir = ... + * WatchService watcher = ... + * + * WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + * </pre> + * @param watcher + * The watch service to which this object is to be registered + * @param events + * The events for which this object should be registered + * + * @return A key representing the registration of this object with the + * given watch service + * + * @throws UnsupportedOperationException + * If unsupported events are specified + * @throws IllegalArgumentException + * If an invalid combination of events is specified + * @throws ClosedWatchServiceException + * If the watch service is closed + * @throws NotDirectoryException + * If the file is registered to watch the entries in a directory + * and the file is not a directory <i>(optional specific exception)</i> + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + @Override + public abstract WatchKey register(WatchService watcher, + WatchEvent.Kind<?>... events) + throws IOException; + + // -- Iterable -- + + /** + * Returns an iterator over the name elements of this path. + * + * <p> The first element returned by the iterator represents the name + * element that is closest to the root in the directory hierarchy, the + * second element is the next closest, and so on. The last element returned + * is the name of the file or directory denoted by this path. The {@link + * #getRoot root} component, if present, is not returned by the iterator. + * + * @return an iterator over the name elements of this path. + */ + @Override + public abstract Iterator<Path> iterator(); + + // -- compareTo/equals/hashCode -- + + /** + * Compares two abstract paths lexicographically. The ordering defined by + * this method is provider specific, and in the case of the default + * provider, platform specific. This method does not access the file system + * and neither file is required to exist. + * + * @param other the path compared to this path. + * + * @return zero if the argument is {@link #equals equal} to this path, a + * value less than zero if this path is lexicographically less than + * the argument, or a value greater than zero if this path is + * lexicographically greater than the argument + */ + @Override + public abstract int compareTo(Path other); + + /** + * Tests this path for equality with the given object. + * + * <p> If the given object is not a Path, or is a Path associated with a + * different provider, then this method immediately returns {@code false}. + * + * <p> Whether or not two path are equal depends on the file system + * implementation. In some cases the paths are compared without regard + * to case, and others are case sensitive. This method does not access the + * file system and the file is not required to exist. + * + * <p> This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method. </p> + * + * @param other + * the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a {@code Path} + * that is identical to this {@code Path} + */ + @Override + public abstract boolean equals(Object other); + + /** + * Computes a hash code for this path. + * + * <p> The hash code is based upon the components of the path, and + * satisfies the general contract of the {@link Object#hashCode + * Object.hashCode} method. + * + * @return the hash-code value for this path + */ + @Override + public abstract int hashCode(); + + /** + * Returns the string representation of this path. + * + * <p> If this path was created by converting a path string using the + * {@link FileSystem#getPath getPath} method then the path string returned + * by this method may differ from the original String used to create the path. + * + * <p> The returned path string uses the default name {@link + * FileSystem#getSeparator separator} to separate names in the path. + * + * @return the string representation of this path + */ + @Override + public abstract String toString(); +} diff --git a/jdk/src/share/classes/java/nio/file/PathMatcher.java b/jdk/src/share/classes/java/nio/file/PathMatcher.java new file mode 100644 index 00000000000..5a1cfee88e6 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/PathMatcher.java @@ -0,0 +1,49 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * An interface that is implemented by objects that perform match operations on + * paths. + * + * @since 1.7 + * + * @see FileSystem#getPathMatcher + * @see Path#newDirectoryStream(String) + */ + +public interface PathMatcher { + /** + * Tells if given path matches this matcher's pattern. + * + * @param path + * the path to match + * + * @return {@code true} if, and only if, the path matches this + * matcher's pattern + */ + boolean matches(Path path); +} diff --git a/jdk/src/share/classes/java/nio/file/Paths.java b/jdk/src/share/classes/java/nio/file/Paths.java new file mode 100644 index 00000000000..2cd7a091213 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/Paths.java @@ -0,0 +1,133 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.spi.FileSystemProvider; +import java.net.URI; + +/** + * This class consists exclusively of static methods that return a {@link Path} + * by converting a path string or {@link URI}. + * + * @since 1.7 + */ + +public class Paths { + private Paths() { } + + /** + * Constructs a {@code Path} by converting the given path string. + * + * <p> The {@code Path} is obtained by invoking the {@link FileSystem#getPath + * getPath} method of the {@link FileSystems#getDefault default} {@link + * FileSystem}. + * + * <p> Note that while this method is very convenient, using it will + * imply an assumed reference to the default FileSystem and limit the + * utility of the calling code. Hence it should not be used in library code + * intended for flexible reuse. A more flexible alternative is to use an + * existing {@code Path} instance as an anchor, such as: + * <pre> + * Path dir = ... + * Path path = dir.resolve("file"); + * </pre> + * + * @param path + * the path string to convert + * + * @return the resulting {@code Path} + * + * @throws InvalidPathException + * if the path string cannot be converted to a {@code Path} + * + * @see FileSystem#getPath + */ + public static Path get(String path) { + return FileSystems.getDefault().getPath(path); + } + + /** + * Converts the given URI to a {@link Path} object. + * + * <p> This method iterates over the {@link FileSystemProvider#installedProviders() + * installed} providers to locate the provider that is identified by the + * URI {@link URI#getScheme scheme} of the given URI. URI schemes are + * compared without regard to case. If the provider is found then its {@link + * FileSystemProvider#getPath getPath} method is invoked to convert the + * URI. + * + * <p> In the case of the default provider, identified by the URI scheme + * "file", the given URI has a non-empty path component, and undefined query + * and fragment components. Whether the authority component may be present + * is platform specific. The returned {@code Path} is associated with the + * {@link FileSystems#getDefault default} file system. + * + * <p> The default provider provides a similar <em>round-trip</em> guarantee + * to the {@link java.io.File} class. For a given {@code Path} <i>p</i> it + * is guaranteed that + * <blockquote><tt> + * Paths.get(</tt><i>p</i><tt>.{@link Path#toUri() toUri}()).equals(</tt> + * <i>p</i><tt>.{@link Path#toAbsolutePath() toAbsolutePath}())</tt> + * </blockquote> + * so long as the original {@code Path}, the {@code URI}, and the new {@code + * Path} are all created in (possibly different invocations of) the same + * Java virtual machine. Whether other providers make any guarantees is + * provider specific and therefore unspecified. + * + * @param uri + * the URI to convert + * + * @return the resulting {@code Path} + * + * @throws IllegalArgumentException + * if preconditions on the {@code uri} parameter do not hold. The + * format of the URI is provider specific. + * @throws FileSystemNotFoundException + * if the file system identified by the URI does not exist or the + * provider identified by the URI's scheme component is not installed + * @throws SecurityException + * if a security manager is installed and it denies an unspecified + * permission to access the file system + */ + public static Path get(URI uri) { + String scheme = uri.getScheme(); + if (scheme == null) + throw new IllegalArgumentException("Missing scheme"); + + // check for default provider to avoid loading of installed providers + if (scheme.equalsIgnoreCase("file")) + return FileSystems.getDefault().provider().getPath(uri); + + // try to find provider + for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { + if (provider.getScheme().equalsIgnoreCase(scheme)) { + return provider.getPath(uri); + } + } + + throw new FileSystemNotFoundException("Provider \"" + scheme + "\" not installed"); + } +} diff --git a/jdk/src/share/classes/java/nio/file/ProviderMismatchException.java b/jdk/src/share/classes/java/nio/file/ProviderMismatchException.java new file mode 100644 index 00000000000..7c1bbc09762 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/ProviderMismatchException.java @@ -0,0 +1,53 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Unchecked exception thrown when an attempt is made to invoke a method on an + * object created by one file system provider with a parameter created by a + * different file system provider. + */ +public class ProviderMismatchException + extends java.lang.IllegalArgumentException +{ + static final long serialVersionUID = 4990847485741612530L; + + /** + * Constructs an instance of this class. + */ + public ProviderMismatchException() { + } + + /** + * Constructs an instance of this class. + * + * @param msg + * the detail message + */ + public ProviderMismatchException(String msg) { + super(msg); + } +} diff --git a/jdk/src/share/classes/java/nio/file/ProviderNotFoundException.java b/jdk/src/share/classes/java/nio/file/ProviderNotFoundException.java new file mode 100644 index 00000000000..dd1fee82dab --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/ProviderNotFoundException.java @@ -0,0 +1,52 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Runtime exception thrown when a provider of the required type cannot be found. + */ + +public class ProviderNotFoundException + extends RuntimeException +{ + static final long serialVersionUID = -1880012509822920354L; + + /** + * Constructs an instance of this class. + */ + public ProviderNotFoundException() { + } + + /** + * Constructs an instance of this class. + * + * @param msg + * the detail message + */ + public ProviderNotFoundException(String msg) { + super(msg); + } +} diff --git a/jdk/src/share/classes/java/nio/file/ReadOnlyFileSystemException.java b/jdk/src/share/classes/java/nio/file/ReadOnlyFileSystemException.java new file mode 100644 index 00000000000..4e92efba089 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/ReadOnlyFileSystemException.java @@ -0,0 +1,43 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Unchecked exception thrown when an attempt is made to update an object + * associated with a {@link FileSystem#isReadOnly() read-only} {@code FileSystem}. + */ + +public class ReadOnlyFileSystemException + extends UnsupportedOperationException +{ + static final long serialVersionUID = -6822409595617487197L; + + /** + * Constructs an instance of this class. + */ + public ReadOnlyFileSystemException() { + } +} diff --git a/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java b/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java new file mode 100644 index 00000000000..b2555c14185 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java @@ -0,0 +1,324 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package java.nio.file; + +import java.nio.file.attribute.*; +import java.nio.channels.SeekableByteChannel; +import java.util.Set; +import java.io.IOException; + +/** + * A {@code DirectoryStream} that defines operations on files that are located + * relative to an open directory. A {@code SecureDirectoryStream} is intended + * for use by sophisticated or security sensitive applications requiring to + * traverse file trees or otherwise operate on directories in a race-free manner. + * Race conditions can arise when a sequence of file operations cannot be + * carried out in isolation. Each of the file operations defined by this + * interface specify a relative {@link Path}. All access to the file is relative + * to the open directory irrespective of if the directory is moved or replaced + * by an attacker while the directory is open. A {@code SecureDirectoryStream} + * may also be used as a virtual <em>working directory</em>. + * + * <p> A {@code SecureDirectoryStream} requires corresponding support from the + * underlying operating system. Where an implementation supports this features + * then the {@code DirectoryStream} returned by the {@link Path#newDirectoryStream + * newDirectoryStream} method will be a {@code SecureDirectoryStream} and must + * be cast to that type in order to invoke the methods defined by this interface. + * + * <p> As specified by {@code DirectoryStream}, the iterator's {@link + * java.util.Iterator#remove() remove} method removes the directory entry for + * the last element returned by the iterator. In the case of a {@code + * SecureDirectoryStream} the {@code remove} method behaves as if by invoking + * the {@link #deleteFile deleteFile} or {@link #deleteDirectory deleteDirectory} + * methods defined by this interface. The {@code remove} may require to examine + * the file to determine if the file is a directory, and consequently, it may + * not be atomic with respect to other file system operations. + * + * <p> In the case of the default {@link java.nio.file.spi.FileSystemProvider + * provider}, and a security manager is set, then the permission checks are + * performed using the path obtained by resolving the given relative path + * against the <i>original path</i> of the directory (irrespective of if the + * directory is moved since it was opened). + * + * @since 1.7 + */ + +public abstract class SecureDirectoryStream + implements DirectoryStream<Path> +{ + /** + * Initialize a new instance of this class. + */ + protected SecureDirectoryStream() { } + + /** + * Opens the directory identified by the given path, returning a {@code + * SecureDirectoryStream} to iterate over the entries in the directory. + * + * <p> This method works in exactly the manner specified by the {@link + * Path#newDirectoryStream newDirectoryStream} method for the case that + * the {@code path} parameter is an {@link Path#isAbsolute absolute} path. + * When the parameter is a relative path then the directory to open is + * relative to this open directory. The {@code followLinks} parameter + * determines if links should be followed. If this parameter is {@code + * false} and the file is a symbolic link then this method fails (by + * throwing an I/O exception). + * + * <p> The new directory stream, once created, is not dependent upon the + * directory stream used to create it. Closing this directory stream has no + * effect upon newly created directory stream. + * + * @param path + * the path to the directory to open + * @param followLinks + * {@code true} if the links should be followed + * @param filter + * the directory stream filter or {@code null}. + * + * @return a new and open {@code SecureDirectoryStream} object + * + * @throws ClosedDirectoryStreamException + * if the directory stream is closed + * @throws NotDirectoryException + * if the file could not otherwise be opened because it is not + * a directory <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the directory. + */ + public abstract SecureDirectoryStream newDirectoryStream(Path path, + boolean followLinks, + DirectoryStream.Filter<? super Path> filter) + throws IOException; + + /** + * Opens or creates a file in this directory, returning a seekable byte + * channel to access the file. + * + * <p> This method works in exactly the manner specified by the {@link + * Path#newByteChannel Path.newByteChannel} method for the + * case that the {@code path} parameter is an {@link Path#isAbsolute absolute} + * path. When the parameter is a relative path then the file to open or + * create is relative to this open directory. In addition to the options + * defined by the {@code Path.newByteChannel} method, the {@link + * LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} option may be used to + * ensure that this method fails if the file is a symbolic link. + * + * <p> The channel, once created, is not dependent upon the directory stream + * used to create it. Closing this directory stream has no effect upon the + * channel. + * + * @param path + * the path of the file to open open or create + * @param options + * options specifying how the file is opened + * @param attrs + * an optional list of attributes to set atomically when creating + * the file + * + * @throws ClosedDirectoryStreamException + * if the directory stream is closed + * @throws IllegalArgumentException + * if the set contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported open option is specified or the array contains + * attributes that cannot be set atomically when creating the file + * @throws FileAlreadyExistsException + * if a file of that name already exists and the {@link + * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified + * <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the path if the file + * is opened for reading. The {@link SecurityManager#checkWrite(String) + * checkWrite} method is invoked to check write access to the path + * if the file is opened for writing. + */ + public abstract SeekableByteChannel newByteChannel(Path path, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException; + + /** + * Deletes a file. + * + * <p> Unlike the {@link FileRef#delete delete()} method, this method + * does not first examine the file to determine if the file is a directory. + * Whether a directory is deleted by this method is system dependent and + * therefore not specified. If the file is a symbolic-link then the link is + * deleted (not the final target of the link). When the parameter is a + * relative path then the file to delete is relative to this open directory. + * + * @param path + * the path of the file to delete + * + * @throws ClosedDirectoryStreamException + * if the directory stream is closed + * @throws NoSuchFileException + * if the file does not exist <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkDelete(String) checkDelete} + * method is invoked to check delete access to the file + */ + public abstract void deleteFile(Path path) throws IOException; + + /** + * Deletes a directory. + * + * <p> Unlike the {@link FileRef#delete delete()} method, this method + * does not first examine the file to determine if the file is a directory. + * Whether non-directories are deleted by this method is system dependent and + * therefore not specified. When the parameter is a relative path then the + * directory to delete is relative to this open directory. + * + * @param path + * the path of the directory to delete + * + * @throws ClosedDirectoryStreamException + * if the directory stream is closed + * @throws NoSuchFileException + * if the the directory does not exist <i>(optional specific exception)</i> + * @throws DirectoryNotEmptyException + * if the directory could not otherwise be deleted because it is + * not empty <i>(optional specific exception)</i> + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkDelete(String) checkDelete} + * method is invoked to check delete access to the directory + */ + public abstract void deleteDirectory(Path path) throws IOException; + + /** + * Move a file from this directory to another directory. + * + * <p> This method works in a similar manner to {@link Path#moveTo moveTo} + * method when the {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} option + * is specified. That is, this method moves a file as an atomic file system + * operation. If the {@code srcpath} parameter is an {@link Path#isAbsolute + * absolute} path then it locates the source file. If the parameter is a + * relative path then it is located relative to this open directory. If + * the {@code targetpath} parameter is absolute then it locates the target + * file (the {@code targetdir} parameter is ignored). If the parameter is + * a relative path it is located relative to the open directory identified + * by the {@code targetdir} parameter. In all cases, if the target file + * exists then it is implementation specific if it is replaced or this + * method fails. + * + * @param srcpath + * the name of the file to move + * @param targetdir + * the destination directory + * @param targetpath + * the name to give the file in the destination directory + * + * @throws ClosedDirectoryStreamException + * if this or the target directory stream is closed + * @throws FileAlreadyExistsException + * if the file already exists in the target directory and cannot + * be replaced <i>(optional specific exception)</i> + * @throws AtomicMoveNotSupportedException + * if the file cannot be moved as an atomic file system operation + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to both the source and + * target file. + */ + public abstract void move(Path srcpath, SecureDirectoryStream targetdir, Path targetpath) + throws IOException; + + /** + * Returns a new file attribute view to access the file attributes of this + * directory. + * + * <p> The resulting file attribute view can be used to read or update the + * attributes of this (open) directory. The {@code type} parameter specifies + * the type of the attribute view and the method returns an instance of that + * type if supported. Invoking this method to obtain a {@link + * BasicFileAttributeView} always returns an instance of that class that is + * bound to this open directory. + * + * <p> The state of resulting file attribute view is intimately connected + * to this directory stream. Once the directory stream is {@link #close closed}, + * then all methods to read or update attributes will throw {@link + * ClosedDirectoryStreamException ClosedDirectoryStreamException}. + * + * @param type + * the {@code Class} object corresponding to the file attribute view + * + * @return a new file attribute view of the specified type bound to + * this directory stream, or {@code null} if the attribute view + * type is not available + */ + public abstract <V extends FileAttributeView> V getFileAttributeView(Class<V> type); + + /** + * Returns a new file attribute view to access the file attributes of a file + * in this directory. + * + * <p> The resulting file attribute view can be used to read or update the + * attributes of file in this directory. The {@code type} parameter specifies + * the type of the attribute view and the method returns an instance of that + * type if supported. Invoking this method to obtain a {@link + * BasicFileAttributeView} always returns an instance of that class that is + * bound to the file in the directory. + * + * <p> The state of resulting file attribute view is intimately connected + * to this directory stream. Once the directory stream {@link #close closed}, + * then all methods to read or update attributes will throw {@link + * ClosedDirectoryStreamException ClosedDirectoryStreamException}. The + * file is not required to exist at the time that the file attribute view + * is created but methods to read or update attributes of the file will + * fail when invoked and the file does not exist. + * + * @param path + * the path of the file + * @param type + * the {@code Class} object corresponding to the file attribute view + * @param options + * options indicating how symbolic links are handled + * + * @return a new file attribute view of the specified type bound to a + * this directory stream, or {@code null} if the attribute view + * type is not available + * + */ + public abstract <V extends FileAttributeView> V getFileAttributeView(Path path, + Class<V> type, + LinkOption... options); +} diff --git a/jdk/src/share/classes/java/nio/file/SimpleFileVisitor.java b/jdk/src/share/classes/java/nio/file/SimpleFileVisitor.java new file mode 100644 index 00000000000..d9557d024a4 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/SimpleFileVisitor.java @@ -0,0 +1,121 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.nio.file.attribute.BasicFileAttributes; +import java.io.IOException; +import java.io.IOError; + +/** + * A simple visitor of files with default behavior to visit all files and to + * re-throw I/O errors. + * + * <p> Methods in this class may be overridden subject to their general contract. + * + * @param <T> The type of reference to the files + * + * @since 1.7 + */ + +public class SimpleFileVisitor<T extends FileRef> implements FileVisitor<T> { + /** + * Initializes a new instance of this class. + */ + protected SimpleFileVisitor() { + } + + /** + * Invoked for a directory before entries in the directory are visited. + * + * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE + * CONTINUE}. + */ + @Override + public FileVisitResult preVisitDirectory(T dir) { + return FileVisitResult.CONTINUE; + } + + /** + * Invoked for a directory that could not be opened. + * + * <p> Unless overridden, this method throws {@link IOError} with the I/O + * exception as cause. + * + * @throws IOError + * with the I/O exception thrown when the attempt to open the + * directory failed + */ + @Override + public FileVisitResult preVisitDirectoryFailed(T dir, IOException exc) { + throw new IOError(exc); + } + + /** + * Invoked for a file in a directory. + * + * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE + * CONTINUE}. + */ + @Override + public FileVisitResult visitFile(T file, BasicFileAttributes attrs) { + return FileVisitResult.CONTINUE; + } + + /** + * Invoked for a file when its basic file attributes could not be read. + * + * <p> Unless overridden, this method throws {@link IOError} with the I/O + * exception as cause. + * + * @throws IOError + * with the I/O exception thrown when the attempt to read the file + * attributes failed + */ + @Override + public FileVisitResult visitFileFailed(T file, IOException exc) { + throw new IOError(exc); + } + + /** + * Invoked for a directory after entries in the directory, and all of their + * descendants, have been visited. + * + * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE + * CONTINUE} if the directory iteration completes without an I/O exception; + * otherwise this method throws {@link IOError} with the I/O exception as + * cause. + * + * @throws IOError + * if iteration of the directory completed prematurely due to an + * I/O error + */ + @Override + public FileVisitResult postVisitDirectory(T dir, IOException exc) { + if (exc != null) + throw new IOError(exc); + return FileVisitResult.CONTINUE; + } +} diff --git a/jdk/src/share/classes/java/nio/file/StandardCopyOption.java b/jdk/src/share/classes/java/nio/file/StandardCopyOption.java new file mode 100644 index 00000000000..32572c1ef18 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/StandardCopyOption.java @@ -0,0 +1,47 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Defines the standard copy options. + * + * @since 1.7 + */ + +public enum StandardCopyOption implements CopyOption { + /** + * Replace an existing file if it exists. + */ + REPLACE_EXISTING, + /** + * Copy attributes to the new file. + */ + COPY_ATTRIBUTES, + /** + * Move the file as an atomic file system operation. + */ + ATOMIC_MOVE; +} diff --git a/jdk/src/share/classes/java/nio/file/StandardOpenOption.java b/jdk/src/share/classes/java/nio/file/StandardOpenOption.java new file mode 100644 index 00000000000..d01763c6a63 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/StandardOpenOption.java @@ -0,0 +1,125 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Defines the standard open options. + * + * @since 1.7 + */ + +public enum StandardOpenOption implements OpenOption { + /** + * Open for read access. + */ + READ, + + /** + * Open for write access. + */ + WRITE, + + /** + * If the file is opened for {@link #WRITE} access then bytes will be written + * to the end of the file rather than the beginning. + * + * <p> If the file is opened for write access by other programs, then it + * is file system specific if writing to the end of the file is atomic. + */ + APPEND, + + /** + * If the file already exists and it is opened for {@link #WRITE} + * access, then its length is truncated to 0. This option is ignored + * if the file is opened only for {@link #READ} access. + */ + TRUNCATE_EXISTING, + + /** + * Create a new file if it does not exist. + * This option is ignored if the {@link #CREATE_NEW} option is also set. + * The check for the existence of the file and the creation of the file + * if it does not exist is atomic with respect to other file system + * operations. + */ + CREATE, + + /** + * Create a new file, failing if the file already exists. + * The check for the existence of the file and the creation of the file + * if it does not exist is atomic with respect to other file system + * operations. + */ + CREATE_NEW, + + /** + * Delete on close. When this option is present then the implementation + * makes a <em>best effort</em> attempt to delete the file when closed + * by the appropriate {@code close} method. If the {@code close} method is + * not invoked then a <em>best effort</em> attempt is made to delete the + * file when the Java virtual machine terminates (either normally, as + * defined by the Java Language Specification, or where possible, abnormally). + * This option is primarily intended for use with <em>work files</em> that + * are used solely by a single instance of the Java virtual machine. This + * option is not recommended for use when opening files that are open + * concurrently by other entities. Many of the details as to when and how + * the file is deleted are implementation specific and therefore not + * specified. In particular, an implementation may be unable to guarantee + * that it deletes the expected file when replaced by an attacker while the + * file is open. Consequently, security sensitive applications should take + * care when using this option. + * + * <p> For security reasons, this option may imply the {@link + * LinkOption#NOFOLLOW_LINKS} option. In other words, if the option is present + * when opening an existing file that is a symbolic link then it may fail + * (by throwing {@link java.io.IOException}). + */ + DELETE_ON_CLOSE, + + /** + * Sparse file. When used with the {@link #CREATE_NEW} option then this + * option provides a <em>hint</em> that the new file will be sparse. The + * option is ignored when the file system does not support the creation of + * sparse files. + */ + SPARSE, + + /** + * Requires that every update to the file's content or metadata be written + * synchronously to the underlying storage device. + * + * @see <a href="package-summary.html#integrity">Synchronized I/O file integrity</a> + */ + SYNC, + + /** + * Requires that every update to the file's content be written + * synchronously to the underlying storage device. + * + * @see <a href="package-summary.html#integrity">Synchronized I/O file integrity</a> + */ + DSYNC; +} diff --git a/jdk/src/share/classes/java/nio/file/StandardWatchEventKind.java b/jdk/src/share/classes/java/nio/file/StandardWatchEventKind.java new file mode 100644 index 00000000000..6cc937e9943 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/StandardWatchEventKind.java @@ -0,0 +1,94 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * Defines the <em>standard</em> event kinds. + * + * @since 1.7 + */ + +public class StandardWatchEventKind { + private StandardWatchEventKind() { } + + /** + * A special event to indicate that events may have been lost or + * discarded. + * + * <p> The {@link WatchEvent#context context} for this event is + * implementation specific and may be {@code null}. The event {@link + * WatchEvent#count count} may be greater than {@code 1}. + * + * @see WatchService + */ + public static final WatchEvent.Kind<Void> OVERFLOW = + new StdWatchEventKind<Void>("OVERFLOW", Void.class); + + /** + * Directory entry created. + * + * <p> When a directory is registered for this event then the {@link WatchKey} + * is queued when it is observed that an entry is created in the directory + * or renamed into the directory. The event {@link WatchEvent#count count} + * for this event is always {@code 1}. + */ + public static final WatchEvent.Kind<Path> ENTRY_CREATE = + new StdWatchEventKind<Path>("ENTRY_CREATE", Path.class); + + /** + * Directory entry deleted. + * + * <p> When a directory is registered for this event then the {@link WatchKey} + * is queued when it is observed that an entry is deleted or renamed out of + * the directory. The event {@link WatchEvent#count count} for this event + * is always {@code 1}. + */ + public static final WatchEvent.Kind<Path> ENTRY_DELETE = + new StdWatchEventKind<Path>("ENTRY_DELETE", Path.class); + + /** + * Directory entry modified. + * + * <p> When a directory is registered for this event then the {@link WatchKey} + * is queued when it is observed that an entry in the directory has been + * modified. The event {@link WatchEvent#count count} for this event is + * {@code 1} or greater. + */ + public static final WatchEvent.Kind<Path> ENTRY_MODIFY = + new StdWatchEventKind<Path>("ENTRY_MODIFY", Path.class); + + private static class StdWatchEventKind<T> implements WatchEvent.Kind<T> { + private final String name; + private final Class<T> type; + StdWatchEventKind(String name, Class<T> type) { + this.name = name; + this.type = type; + } + @Override public String name() { return name; } + @Override public Class<T> type() { return type; } + @Override public String toString() { return name; } + } +} diff --git a/jdk/src/share/classes/java/nio/file/WatchEvent.java b/jdk/src/share/classes/java/nio/file/WatchEvent.java new file mode 100644 index 00000000000..296efd44377 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/WatchEvent.java @@ -0,0 +1,116 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +/** + * An event or a repeated event for an object that is registered with a {@link + * WatchService}. + * + * <p> An event is classified by its {@link #kind() kind} and has a {@link + * #count() count} to indicate the number of times that the event has been + * observed. This allows for efficient representation of repeated events. The + * {@link #context() context} method returns any context associated with + * the event. In the case of a repeated event then the context is the same for + * all events. + * + * <p> Watch events are immutable and safe for use by multiple concurrent + * threads. + * + * @param <T> The type of the context object associated with the event + * + * @since 1.7 + */ + +public abstract class WatchEvent<T> { + + /** + * An event kind, for the purposes of identification. + * + * @since 1.7 + * @see StandardWatchEventKind + */ + public static interface Kind<T> { + /** + * Returns the name of the event kind. + */ + String name(); + + /** + * Returns the type of the {@link WatchEvent#context context} value. + */ + Class<T> type(); + } + + /** + * Initializes a new instance of this class. + */ + protected WatchEvent() { } + + /** + * An event modifier that qualifies how a {@link Watchable} is registered + * with a {@link WatchService}. + * + * <p> This release does not define any <em>standard</em> modifiers. + * + * @since 1.7 + * @see Watchable#register + */ + public static interface Modifier { + /** + * Returns the name of the modifier. + */ + String name(); + } + + /** + * Returns the event kind. + * + * @return the event kind + */ + public abstract Kind<T> kind(); + + /** + * Returns the event count. If the event count is greater than {@code 1} + * then this is a repeated event. + * + * @return the event count + */ + public abstract int count(); + + /** + * Returns the context for the event. + * + * <p> In the case of {@link StandardWatchEventKind#ENTRY_CREATE ENTRY_CREATE}, + * {@link StandardWatchEventKind#ENTRY_DELETE ENTRY_DELETE}, and {@link + * StandardWatchEventKind#ENTRY_MODIFY ENTRY_MODIFY} events the context is + * a {@code Path} that is the {@link Path#relativize relative} path between + * the directory registered with the watch service, and the entry that is + * created, deleted, or modified. + * + * @return the event context; may be {@code null} + */ + public abstract T context(); +} diff --git a/jdk/src/share/classes/java/nio/file/WatchKey.java b/jdk/src/share/classes/java/nio/file/WatchKey.java new file mode 100644 index 00000000000..d065585d87d --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/WatchKey.java @@ -0,0 +1,138 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.util.List; + +/** + * A token representing the registration of a {@link Watchable watchable} object + * with a {@link WatchService}. + * + * <p> A watch key is created when a watchable object is registered with a watch + * service. The key remains {@link #isValid valid} until: + * <ol> + * <li> It is cancelled, explicitly, by invoking its {@link #cancel cancel} + * method, or</li> + * <li> Cancelled implicitly, because the object is no longer accessible, + * or </li> + * <li> By {@link WatchService#close closing} the watch service. </li> + * </ol> + * + * <p> A watch key has a state. When initially created the key is said to be + * <em>ready</em>. When an event is detected then the key is <em>signalled</em> + * and queued so that it can be retrieved by invoking the watch service's {@link + * WatchService#poll() poll} or {@link WatchService#take() take} methods. Once + * signalled, a key remains in this state until its {@link #reset reset} method + * is invoked to return the key to the ready state. Events detected while the + * key is in the signalled state are queued but do not cause the key to be + * re-queued for retrieval from the watch service. Events are retrieved by + * invoking the key's {@link #pollEvents pollEvents} method. This method + * retrieves and removes all events accumulated for the object. When initially + * created, a watch key has no pending events. Typically events are retrieved + * when the key is in the signalled state leading to the following idiom: + * + * <pre> + * for (;;) { + * // retrieve key + * WatchKey key = watcher.take(); + * + * // process events + * for (WatchEvent<?> event: key.pollEvents()) { + * : + * } + * + * // reset the key + * boolean valid = key.reset(); + * if (!valid) { + * // object no longer registered + * } + * } + * </pre> + * + * <p> Watch keys are safe for use by multiple concurrent threads. Where there + * are several threads retrieving signalled keys from a watch service then care + * should be taken to ensure that the {@code reset} method is only invoked after + * the events for the object have been processed. This ensures that one thread + * is processing the events for an object at any time. + * + * @since 1.7 + */ + +public abstract class WatchKey { + /** + * Initializes a new instance of this class. + */ + protected WatchKey() { } + + /** + * Tells whether or not this watch key is valid. + * + * <p> A watch key is valid upon creation and remains until it is cancelled, + * or its watch service is closed. + * + * @return {@code true} if, and only if, this watch key is valid + */ + public abstract boolean isValid(); + + /** + * Retrieves and removes all pending events for this watch key, returning + * a {@code List} of the events that were retrieved. + * + * <p> Note that this method does not wait if there are no events pending. + * + * @return the list of the events retrieved + */ + public abstract List<WatchEvent<?>> pollEvents(); + + /** + * Resets this watch key. + * + * <p> If this watch key has been cancelled or this watch key is already in + * the ready state then invoking this method has no effect. Otherwise + * if there are pending events for the object then this watch key is + * immediately re-queued to the watch service. If there are no pending + * events then the watch key is put into the ready state and will remain in + * that state until an event is detected or the watch key is cancelled. + * + * @return {@code true} if the watch key is valid and has been reset, and + * {@code false} if the watch key could not be reset because it is + * no longer {@link #isValid valid} + */ + public abstract boolean reset(); + + /** + * Cancels the registration with the watch service. Upon return the watch key + * will be invalid. If the watch key is enqueued, waiting to be retrieved + * from the watch service, then it will remain in the queue until it is + * removed. Pending events, if any, remain pending and may be retrieved by + * invoking the {@link #pollEvents pollEvents} method event after the key is + * cancelled. + * + * <p> If this watch key has already been cancelled then invoking this + * method has no effect. Once cancelled, a watch key remains forever invalid. + */ + public abstract void cancel(); +} diff --git a/jdk/src/share/classes/java/nio/file/WatchService.java b/jdk/src/share/classes/java/nio/file/WatchService.java new file mode 100644 index 00000000000..52678df79b6 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/WatchService.java @@ -0,0 +1,178 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * A watch service that <em>watches</em> registered objects for changes and + * events. For example a file manager may use a watch service to monitor a + * directory for changes so that it can update its display of the list of files + * when files are created or deleted. + * + * <p> A {@link Watchable} object is registered with a watch service by invoking + * its {@link Watchable#register register} method, returning a {@link WatchKey} + * to represent the registration. When an event for an object is detected the + * key is <em>signalled</em>, and if not currently signalled, it is queued to + * the watch service so that it can be retrieved by consumers that invoke the + * {@link #poll() poll} or {@link #take() take} methods to retrieve keys + * and process events. Once the events have been processed the consumer + * invokes the key's {@link WatchKey#reset reset} method to reset the key which + * allows the key to be signalled and re-queued with further events. + * + * <p> Registration with a watch service is cancelled by invoking the key's + * {@link WatchKey#cancel cancel} method. A key that is queued at the time that + * it is cancelled remains in the queue until it is retrieved. Depending on the + * object, a key may be cancelled automatically. For example, suppose a + * directory is watched and the watch service detects that it has been deleted + * or its file system is no longer accessible. When a key is cancelled in this + * manner it is signalled and queued, if not currently signalled. To ensure + * that the consumer is notified the return value from the {@code reset} + * method indicates if the key is valid. + * + * <p> A watch service is safe for use by multiple concurrent consumers. To + * ensure that only one consumer processes the events for a particular object at + * any time then care should be taken to ensure that the key's {@code reset} + * method is only invoked after its events have been processed. The {@link + * #close close} method may be invoked at any time to close the service causing + * any threads waiting to retrieve keys, to throw {@code + * ClosedWatchServiceException}. + * + * <p> File systems may report events faster than they can be retrieved or + * processed and an implementation may impose an unspecified limit on the number + * of events that it may accumulate. Where an implementation <em>knowingly</em> + * discards events then it arranges for the key's {@link WatchKey#pollEvents + * pollEvents} method to return an element with an event type of {@link + * StandardWatchEventKind#OVERFLOW OVERFLOW}. This event can be used by the + * consumer as a trigger to re-examine the state of the object. + * + * <p> When an event is reported to indicate that a file in a watched directory + * has been modified then there is no guarantee that the program (or programs) + * that have modified the file have completed. Care should be taken to coordinate + * access with other programs that may be updating the file. + * The {@link java.nio.channels.FileChannel FileChannel} class defines methods + * to lock regions of a file against access by other programs. + * + * <h4>Platform dependencies</h4> + * + * <p> The implementation that observes events from the file system is intended + * to map directly on to the native file event notification facility where + * available, or to use a primitive mechanism, such as polling, when a native + * facility is not available. Consequently, many of the details on how events + * are detected, their timeliness, and whether their ordering is preserved are + * highly implementation specific. For example, when a file in a watched + * directory is modified then it may result in a single {@link + * StandardWatchEventKind#ENTRY_MODIFY ENTRY_MODIFY} event in some + * implementations but several events in other implementations. Short-lived + * files (meaning files that are deleted very quickly after they are created) + * may not be detected by primitive implementations that periodically poll the + * file system to detect changes. + * + * <p> If a watched file is not located on a local storage device then it is + * implementation specific if changes to the file can be detected. In particular, + * it is not required that changes to files carried out on remote systems be + * detected. + * + * @since 1.7 + * + * @see FileSystem#newWatchService + */ + +public abstract class WatchService + implements Closeable +{ + /** + * Initializes a new instance of this class. + */ + protected WatchService() { } + + /** + * Closes this watch service. + * + * <p> If a thread is currently blocked in the {@link #take take} or {@link + * #poll(long,TimeUnit) poll} methods waiting for a key to be queued then + * it immediately receives a {@link ClosedWatchServiceException}. Any + * valid keys associated with this watch service are {@link WatchKey#isValid + * invalidated}. + * + * <p> After a watch service is closed, any further attempt to invoke + * operations upon it will throw {@link ClosedWatchServiceException}. + * If this watch service is already closed then invoking this method + * has no effect. + * + * @throws IOException + * if an I/O error occurs + */ + @Override + public abstract void close() throws IOException; + + /** + * Retrieves and removes the next watch key, or {@code null} if none are + * present. + * + * @return the next watch key, or {@code null} + * + * @throws ClosedWatchServiceException + * if this watch service is closed + */ + public abstract WatchKey poll(); + + /** + * Retrieves and removes the next watch key, waiting if necessary up to the + * specified wait time if none are yet present. + * + * @param timeout + * how to wait before giving up, in units of unit + * @param unit + * a {@code TimeUnit} determining how to interpret the timeout + * parameter + * + * @return the next watch key, or {@code null} + * + * @throws ClosedWatchServiceException + * if this watch service is closed, or it is closed while waiting + * for the next key + * @throws InterruptedException + * if interrupted while waiting + */ + public abstract WatchKey poll(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes next watch key, waiting if none are yet present. + * + * @return the next watch key + * + * @throws ClosedWatchServiceException + * if this watch service is closed, or it is closed while waiting + * for the next key + * @throws InterruptedException + * if interrupted while waiting + */ + public abstract WatchKey take() throws InterruptedException; +} diff --git a/jdk/src/share/classes/java/nio/file/Watchable.java b/jdk/src/share/classes/java/nio/file/Watchable.java new file mode 100644 index 00000000000..9bfa627f7bc --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/Watchable.java @@ -0,0 +1,127 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file; + +import java.io.IOException; + +/** + * An object that may be registered with a watch service so that it can be + * <em>watched</em> for changes and events. + * + * <p> This interface defines the {@link #register register} method to register + * the object with a {@link WatchService} returning a {@link WatchKey} to + * represent the registration. An object may be registered with more than one + * watch service. Registration with a watch service is cancelled by invoking the + * key's {@link WatchKey#cancel cancel} method. + * + * @since 1.7 + * + * @see Path#register + */ + +public interface Watchable { + + /** + * Registers an object with a watch service. + * + * <p> If the file system object identified by this object is currently + * registered with the watch service then the watch key, representing that + * registration, is returned after changing the event set or modifiers to + * those specified by the {@code events} and {@code modifiers} parameters. + * Changing the event set does not cause pending events for the object to be + * discarded. Objects are automatically registered for the {@link + * StandardWatchEventKind#OVERFLOW OVERFLOW} event. This event is not + * required to be present in the array of events. + * + * <p> Otherwise the file system object has not yet been registered with the + * given watch service, so it is registered and the resulting new key is + * returned. + * + * <p> Implementations of this interface should specify the events they + * support. + * + * @param watcher + * the watch service to which this object is to be registered + * @param events + * the events for which this object should be registered + * @param modifiers + * the modifiers, if any, that modify how the object is registered + * + * @return a key representing the registration of this object with the + * given watch service + * + * @throws UnsupportedOperationException + * if unsupported events or modifiers are specified + * @throws IllegalArgumentException + * if an invalid of combination of events are modifiers are specified + * @throws ClosedWatchServiceException + * if the watch service is closed + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * if a security manager is installed and it denies an unspecified + * permission required to monitor this object. Implementations of + * this interface should specify the permission checks. + */ + WatchKey register(WatchService watcher, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) + throws IOException; + + + /** + * Registers an object with a watch service. + * + * <p> An invocation of this method behaves in exactly the same way as the + * invocation + * <pre> + * watchable.{@link #register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier[]) register}(watcher, events, new WatchEvent.Modifier[0]); + * </pre> + * + * @param watcher + * the watch service to which this object is to be registered + * @param events + * the events for which this object should be registered + * + * @return a key representing the registration of this object with the + * given watch service + * + * @throws UnsupportedOperationException + * if unsupported events are specified + * @throws IllegalArgumentException + * if an invalid of combination of events are specified + * @throws ClosedWatchServiceException + * if the watch service is closed + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * if a security manager is installed and it denies an unspecified + * permission required to monitor this object. Implementations of + * this interface should specify the permission checks. + */ + WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) + throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/AclEntry.java b/jdk/src/share/classes/java/nio/file/attribute/AclEntry.java new file mode 100644 index 00000000000..817e1b04742 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/AclEntry.java @@ -0,0 +1,394 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.util.*; + +/** + * An entry in an access control list (ACL). + * + * <p> The ACL entry represented by this class is based on the ACL model + * specified in <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC 3530: + * Network File System (NFS) version 4 Protocol</i></a>. Each entry has four + * components as follows: + * + * <ol> + * <li><p> The {@link #type() type} component determines if the entry + * grants or denies access. </p></li> + * + * <li><p> The {@link #principal() principal} component, sometimes called the + * "who" component, is a {@link UserPrincipal} corresponding to the identity + * that the entry grants or denies access + * </p></li> + * + * <li><p> The {@link #permissions permissions} component is a set of + * {@link AclEntryPermission permissions} + * </p></li> + * + * <li><p> The {@link #flags flags} component is a set of {@link AclEntryFlag + * flags} to indicate how entries are inherited and propagated </p></li> + * </ol> + * + * <p> ACL entries are created using an associated {@link Builder} object by + * invoking its {@link Builder#build build} method. + * + * <p> ACL entries are immutable and are safe for use by multiple concurrent + * threads. + * + * @since 1.7 + */ + +public final class AclEntry { + + private final AclEntryType type; + private final UserPrincipal who; + private final Set<AclEntryPermission> perms; + private final Set<AclEntryFlag> flags; + + // cached hash code + private volatile int hash; + + // private constructor + private AclEntry(AclEntryType type, + UserPrincipal who, + Set<AclEntryPermission> perms, + Set<AclEntryFlag> flags) + { + this.type = type; + this.who = who; + this.perms = perms; + this.flags = flags; + } + + /** + * A builder of {@link AclEntry} objects. + * + * <p> A {@code Builder} object is obtained by invoking one of the {@link + * AclEntry#newBuilder newBuilder} methods defined by the {@code AclEntry} + * class. + * + * <p> Builder objects are mutable and are not safe for use by multiple + * concurrent threads without appropriate synchronization. + * + * @since 1.7 + */ + public static final class Builder { + private AclEntryType type; + private UserPrincipal who; + private Set<AclEntryPermission> perms; + private Set<AclEntryFlag> flags; + + private Builder(AclEntryType type, + UserPrincipal who, + Set<AclEntryPermission> perms, + Set<AclEntryFlag> flags) + { + assert perms != null && flags != null; + this.type = type; + this.who = who; + this.perms = perms; + this.flags = flags; + } + + /** + * Constructs an {@link AclEntry} from the components of this builder. + * The type and who components are required to have been set in order + * to construct an {@code AclEntry}. + * + * @return a new ACL entry + * + * @throws IllegalStateException + * if the type or who component have not been set + */ + public AclEntry build() { + if (type == null) + throw new IllegalStateException("Missing type component"); + if (who == null) + throw new IllegalStateException("Missing who component"); + return new AclEntry(type, who, perms, flags); + } + + /** + * Sets the type component of this builder. + * + * @return this builder + */ + public Builder setType(AclEntryType type) { + if (type == null) + throw new NullPointerException(); + this.type = type; + return this; + } + + /** + * Sets the principal component of this builder. + * + * @return this builder + */ + public Builder setPrincipal(UserPrincipal who) { + if (who == null) + throw new NullPointerException(); + this.who = who; + return this; + } + + // check set only contains elements of the given type + private static void checkSet(Set<?> set, Class<?> type) { + for (Object e: set) { + if (e == null) + throw new NullPointerException(); + type.cast(e); + } + } + + /** + * Sets the permissions component of this builder. On return, the + * permissions component of this builder is a copy of the given set. + * + * @return this builder + * + * @throws ClassCastException + * if the set contains elements that are not of type {@code + * AclEntryPermission} + */ + public Builder setPermissions(Set<AclEntryPermission> perms) { + // copy and check for erroneous elements + perms = new HashSet<AclEntryPermission>(perms); + checkSet(perms, AclEntryPermission.class); + this.perms = perms; + return this; + } + + /** + * Sets the permissions component of this builder. On return, the + * permissions component of this builder is a copy of the permissions in + * the given array. + * + * @return this builder + */ + public Builder setPermissions(AclEntryPermission... perms) { + Set<AclEntryPermission> set = + new HashSet<AclEntryPermission>(perms.length); + // copy and check for null elements + for (AclEntryPermission p: perms) { + if (p == null) + throw new NullPointerException(); + set.add(p); + } + this.perms = set; + return this; + } + + /** + * Sets the flags component of this builder. On return, the flags + * component of this builder is a copy of the given set. + * + * @return this builder + * + * @throws ClassCastException + * if the set contains elements that are not of type {@code + * AclEntryFlag} + */ + public Builder setFlags(Set<AclEntryFlag> flags) { + // copy and check for erroneous elements + flags = new HashSet<AclEntryFlag>(flags); + checkSet(flags, AclEntryFlag.class); + this.flags = flags; + return this; + } + + /** + * Sets the flags component of this builder. On return, the flags + * component of this builder is a copy of the flags in the given + * array. + * + * @return this builder + */ + public Builder setFlags(AclEntryFlag... flags) { + Set<AclEntryFlag> set = new HashSet<AclEntryFlag>(flags.length); + // copy and check for null elements + for (AclEntryFlag f: flags) { + if (f == null) + throw new NullPointerException(); + set.add(f); + } + this.flags = set; + return this; + } + } + + /** + * Constructs a new builder. The initial value of the type and who + * components is {@code null}. The initial value of the permissions and + * flags components is the empty set. + * + * @return a new builder + */ + public static Builder newBuilder() { + Set<AclEntryPermission> perms = Collections.emptySet(); + Set<AclEntryFlag> flags = Collections.emptySet(); + return new Builder(null, null, perms, flags); + } + + /** + * Constructs a new builder with the components of an existing ACL entry. + * + * @param entry + * an ACL entry + * + * @return a new builder + */ + public static Builder newBuilder(AclEntry entry) { + return new Builder(entry.type, entry.who, entry.perms, entry.flags); + } + + /** + * Returns the ACL entry type. + */ + public AclEntryType type() { + return type; + } + + /** + * Returns the principal component. + */ + public UserPrincipal principal() { + return who; + } + + /** + * Returns a copy of the permissions component. + * + * <p> The returned set is a modifiable copy of the permissions. + */ + public Set<AclEntryPermission> permissions() { + return new HashSet<AclEntryPermission>(perms); + } + + /** + * Returns a copy of the flags component. + * + * <p> The returned set is a modifiable copy of the flags. + */ + public Set<AclEntryFlag> flags() { + return new HashSet<AclEntryFlag>(flags); + } + + /** + * Compares the specified object with this ACL entry for equality. + * + * <p> If the given object is not an {@code AclEntry} then this method + * immediately returns {@code false}. + * + * <p> For two ACL entries to be considered equals requires that they are + * both the same type, their who components are equal, their permissions + * components are equal, and their flags components are equal. + * + * <p> This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method. </p> + * + * @param ob the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is an AclEntry that + * is identical to this AclEntry + */ + @Override + public boolean equals(Object ob) { + if (ob == this) + return true; + if (ob == null || !(ob instanceof AclEntry)) + return false; + AclEntry other = (AclEntry)ob; + if (this.type != other.type) + return false; + if (!this.who.equals(other.who)) + return false; + if (!this.perms.equals(other.perms)) + return false; + if (!this.flags.equals(other.flags)) + return false; + return true; + } + + private static int hash(int h, Object o) { + return h * 127 + o.hashCode(); + } + + /** + * Returns the hash-code value for this ACL entry. + * + * <p> This method satisfies the general contract of the {@link + * Object#hashCode} method. + */ + @Override + public int hashCode() { + // return cached hash if available + if (hash != 0) + return hash; + int h = type.hashCode(); + h = hash(h, who); + h = hash(h, perms); + h = hash(h, flags); + hash = h; + return hash; + } + + /** + * Returns the string representation of this ACL entry. + * + * @return the string representation of this entry + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + // who + sb.append(who.getName()); + sb.append(':'); + + // permissions + for (AclEntryPermission perm: perms) { + sb.append(perm.name()); + sb.append('/'); + } + sb.setLength(sb.length()-1); // drop final slash + sb.append(':'); + + // flags + if (!flags.isEmpty()) { + for (AclEntryFlag flag: flags) { + sb.append(flag.name()); + sb.append('/'); + } + sb.setLength(sb.length()-1); // drop final slash + sb.append(':'); + } + + // type + sb.append(type.name()); + return sb.toString(); + } +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/AclEntryFlag.java b/jdk/src/share/classes/java/nio/file/attribute/AclEntryFlag.java new file mode 100644 index 00000000000..8cad24d1923 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/AclEntryFlag.java @@ -0,0 +1,65 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +/** + * Defines the flags for used by the flags component of an ACL {@link AclEntry + * entry}. + * + * <p> In this release, this class does not define flags related to {@link + * AclEntryType#AUDIT} and {@link AclEntryType#ALARM} entry types. + * + * @since 1.7 + */ + +public enum AclEntryFlag { + + /** + * Can be placed on a directory and indicates that the ACL entry should be + * added to each new non-directory file created. + */ + FILE_INHERIT, + + /** + * Can be placed on a directory and indicates that the ACL entry should be + * added to each new directory created. + */ + DIRECTORY_INHERIT, + + /** + * Can be placed on a directory to indicate that the ACL entry should not + * be placed on the newly created directory which is inheritable by + * subdirectories of the created directory. + */ + NO_PROPAGATE_INHERIT, + + /** + * Can be placed on a directory but does not apply to the directory, + * only to newly created files/directories as specified by the + * {@link #FILE_INHERIT} and {@link #DIRECTORY_INHERIT} flags. + */ + INHERIT_ONLY; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/AclEntryPermission.java b/jdk/src/share/classes/java/nio/file/attribute/AclEntryPermission.java new file mode 100644 index 00000000000..b88431c04c4 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/AclEntryPermission.java @@ -0,0 +1,130 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +/** + * Defines the permissions for use with the permissions component of an ACL + * {@link AclEntry entry}. + * + * @since 1.7 + */ + +public enum AclEntryPermission { + + /** + * Permission to read the data of the file. + */ + READ_DATA, + + /** + * Permission to modify the file's data. + */ + WRITE_DATA, + + /** + * Permission to append data to a file. + */ + APPEND_DATA, + + /** + * Permission to read the named attributes of a file. + * + * <p> <a href="http://www.ietf.org/rfc/rfc3530.txt">RFC 3530: Network + * File System (NFS) version 4 Protocol</a> defines <em>named attributes</em> + * as opaque files associated with a file in the file system. + */ + READ_NAMED_ATTRS, + + /** + * Permission to write the named attributes of a file. + * + * <p> <a href="http://www.ietf.org/rfc/rfc3530.txt">RFC 3530: Network + * File System (NFS) version 4 Protocol</a> defines <em>named attributes</em> + * as opaque files associated with a file in the file system. + */ + WRITE_NAMED_ATTRS, + + /** + * Permission to execute a file. + */ + EXECUTE, + + /** + * Permission to delete a file or directory within a directory. + */ + DELETE_CHILD, + + /** + * The ability to read (non-acl) file attributes. + */ + READ_ATTRIBUTES, + + /** + * The ability to write (non-acl) file attributes. + */ + WRITE_ATTRIBUTES, + + /** + * Permission to delete the file. + */ + DELETE, + + /** + * Permission to read the ACL attribute. + */ + READ_ACL, + + /** + * Permission to write the ACL attribute. + */ + WRITE_ACL, + + /** + * Permission to change the owner. + */ + WRITE_OWNER, + + /** + * Permission to access file locally at the server with synchronous reads + * and writes. + */ + SYNCHRONIZE; + + /** + * Permission to list the entries of a directory (equal to {@link #READ_DATA}) + */ + public static final AclEntryPermission LIST_DIRECTORY = READ_DATA; + + /** + * Permission to add a new file to a directory (equal to {@link #WRITE_DATA}) + */ + public static final AclEntryPermission ADD_FILE = WRITE_DATA; + + /** + * Permission to create a subdirectory to a directory (equal to {@link #APPEND_DATA}) + */ + public static final AclEntryPermission ADD_SUBDIRECTORY = APPEND_DATA; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/AclEntryType.java b/jdk/src/share/classes/java/nio/file/attribute/AclEntryType.java new file mode 100644 index 00000000000..c0051c0e83e --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/AclEntryType.java @@ -0,0 +1,56 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +/** + * A typesafe enumeration of the access control entry types. + * + * @since 1.7 + */ + +public enum AclEntryType { + /** + * Explicitly grants access to a file or directory. + */ + ALLOW, + + /** + * Explicitly denies access to a file or directory. + */ + DENY, + + /** + * Log, in a system dependent way, the access specified in the + * permissions component of the ACL entry. + */ + AUDIT, + + /** + * Generate an alarm, in a system dependent way, the access specified in the + * permissions component of the ACL entry. + */ + ALARM +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java new file mode 100644 index 00000000000..c3d28c914a7 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java @@ -0,0 +1,211 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.nio.file.*; +import java.util.List; +import java.io.IOException; + +/** + * A file attribute view that supports reading or updating a file's Access + * Control Lists (ACL) or file owner attributes. + * + * <p> ACLs are used to specify access rights to file system objects. An ACL is + * an ordered list of {@link AclEntry access-control-entries}, each specifying a + * {@link UserPrincipal} and the level of access for that user principal. This + * file attribute view defines the {@link #getAcl() getAcl}, and {@link + * #setAcl(List) setAcl} methods to read and write ACLs based on the ACL + * model specified in <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC 3530: + * Network File System (NFS) version 4 Protocol</i></a>. This file attribute view + * is intended for file system implementations that support the NFSv4 ACL model + * or have a <em>well-defined</em> mapping between the NFSv4 ACL model and the ACL + * model used by the file system. The details of such mapping are implementation + * dependent and are therefore unspecified. + * + * <p> This class also extends {@code FileOwnerAttributeView} so as to define + * methods to get and set the file owner. + * + * <p> When a file system provides access to a set of {@link FileStore + * file-systems} that are not homogeneous then only some of the file systems may + * support ACLs. The {@link FileStore#supportsFileAttributeView + * supportsFileAttributeView} method can be used to test if a file system + * supports ACLs. + * + * <a name="interop"><h4>Interoperability</h4></a> + * + * RFC 3530 allows for special user identities to be used on platforms that + * support the POSIX defined access permissions. The special user identities + * are "{@code OWNER@}", "{@code GROUP@}", and "{@code EVERYONE@}". When both + * the {@code AclFileAttributeView} and the {@link PosixFileAttributeView} + * are supported then these special user identities may be included in ACL {@link + * AclEntry entries} that are read or written. The file system's {@link + * UserPrincipalLookupService} may be used to obtain a {@link UserPrincipal} + * to represent these special identities by invoking the {@link + * UserPrincipalLookupService#lookupPrincipalByName lookupPrincipalByName} + * method. + * + * <p> <b>Usage Example:</b> + * Suppose we wish to add an entry to an existing ACL to grant "joe" access: + * <pre> + * // lookup "joe" + * UserPrincipal joe = file.getFileSystem().getUserPrincipalLookupService() + * .lookupPrincipalByName("joe"); + * + * // get view + * AclFileAttributeView view = file.newFileAttributeView(AclFileAttributeView.class); + * + * // create ACE to give "joe" read access + * AclEntry entry = AclEntry.newBuilder() + * .setType(AclEntryType.ALLOW) + * .setPrincipal(joe) + * .setPermissions(AclEntryPermission.READ_DATA, AclEntryPermission.READ_ATTRIBUTES) + * .build(); + * + * // read ACL, insert ACE, re-write ACL + * List<AclEntry> acl = view.getAcl(); + * acl.add(0, entry); // insert before any DENY entries + * view.setAcl(acl); + * </pre> + * + * <h4> Dynamic Access </h4> + * <p> Where dynamic access to file attributes is required, the attributes + * supported by this attribute view are as follows: + * <blockquote> + * <table border="1" cellpadding="8"> + * <tr> + * <th> Name </th> + * <th> Type </th> + * </tr> + * <tr> + * <td> "acl" </td> + * <td> {@link List}<{@link AclEntry}> </td> + * </tr> + * <tr> + * <td> "owner" </td> + * <td> {@link UserPrincipal} </td> + * </tr> + * </table> + * </blockquote> + * + * <p> The {@link #getAttribute getAttribute} or {@link #readAttributes + * readAttributes} methods may be used to read the ACL or owner attributes as if + * by invoking the {@link #getAcl getAcl} or {@link #getOwner getOwner} methods. + * + * <p> The {@link #setAttribute setAttribute} method may be used to update the + * ACL or owner attributes as if by invoking the {@link #setAcl setAcl} or {@link + * #setOwner setOwner} methods. + * + * <h4> Setting the ACL when creating a file </h4> + * + * <p> Implementations supporting this attribute view may also support setting + * the initial ACL when creating a file or directory. The initial ACL + * may be provided to methods such as {@link Path#createFile createFile} or {@link + * Path#createDirectory createDirectory} as an {@link FileAttribute} with {@link + * FileAttribute#name name} {@code "acl:acl"} and a {@link FileAttribute#value + * value} that is the list of {@code AclEntry} objects. + * + * <p> Where an implementation supports an ACL model that differs from the NFSv4 + * defined ACL model then setting the initial ACL when creating the file must + * translate the ACL to the model supported by the file system. Methods that + * create a file should reject (by throwing {@link IOException IOException}) + * any attempt to create a file that would be less secure as a result of the + * translation. + * + * @since 1.7 + * @see Attributes#getAcl + * @see Attributes#setAcl + */ + +public interface AclFileAttributeView + extends FileOwnerAttributeView +{ + /** + * Returns the name of the attribute view. Attribute views of this type + * have the name {@code "acl"}. + */ + @Override + String name(); + + /** + * Reads the access control list. + * + * <p> When the file system uses an ACL model that differs from the NFSv4 + * defined ACL model, then this method returns an ACL that is the translation + * of the ACL to the NFSv4 ACL model. + * + * <p> The returned list is modifiable so as to facilitate changes to the + * existing ACL. The {@link #setAcl setAcl} method is used to update + * the file's ACL attribute. + * + * @return an ordered list of {@link AclEntry entries} representing the + * ACL + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + */ + List<AclEntry> getAcl() throws IOException; + + /** + * Updates (replace) the access control list. + * + * <p> Where the file system supports Access Control Lists, and it uses an + * ACL model that differs from the NFSv4 defined ACL model, then this method + * must translate the ACL to the model supported by the file system. This + * method should reject (by throwing {@link IOException IOException}) any + * attempt to write an ACL that would appear to make the file more secure + * than would be the case if the ACL were updated. Where an implementation + * does not support a mapping of {@link AclEntryType#AUDIT} or {@link + * AclEntryType#ALARM} entries, then this method ignores these entries when + * writing the ACL. + * + * <p> If an ACL entry contains a {@link AclEntry#principal user-principal} + * that is not associated with the same provider as this attribute view then + * {@link ProviderMismatchException} is thrown. Additional validation, if + * any, is implementation dependent. + * + * <p> If the file system supports other security related file attributes + * (such as a file {@link PosixFileAttributes#permissions + * access-permissions} for example), the updating the access control list + * may also cause these security related attributes to be updated. + * + * @param acl + * the new access control list + * + * @throws IOException + * if an I/O error occurs or the ACL is invalid + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + */ + void setAcl(List<AclEntry> acl) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/AttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/AttributeView.java new file mode 100644 index 00000000000..6b0934e7af0 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/AttributeView.java @@ -0,0 +1,118 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.util.*; +import java.io.IOException; + +/** + * An object that provides a read-only or updatable <em>view</em> of non-opaque + * values associated with an object in a filesystem. This interface is extended + * or implemented by specific attribute views that define the attributes + * supported by the view. A specific attribute view will typically define + * type-safe methods to read or update the attributes that it supports. It also + * provides <em>dynamic access</em> where the {@link #readAttributes + * readAttributes}, {@link #getAttribute getAttribute} and {@link #setAttribute + * setAttributs} methods are used to access the attributes by names defined + * by the attribute view. Implementations must ensure that the attribute names + * do not contain the colon (':') or comma (',') characters. + * + * @since 1.7 + */ + +public interface AttributeView { + /** + * Returns the name of the attribute view. + */ + String name(); + + /** + * Reads the value of an attribute. + * + * @param attribute + * the attribute name (case sensitive) + * + * @return the value of the attribute, or {@code null} if the attribute is + * not supported + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * if a security manager is set and it denies access + */ + Object getAttribute(String attribute) throws IOException; + + /** + * Sets/updates the value of an attribute. + * + * @param attribute + * the attribute name (case sensitive) + * @param value + * the attribute value + * + * @throws UnsupportedOperationException + * if the attribute is not supported or this attribute view does + * not support updating the value of the attribute + * @throws IllegalArgumentException + * if the attribute value is of the correct type but has an + * inappropriate value + * @throws ClassCastException + * if the attribute value is not of the expected type or is a + * collection containing elements that are not of the expected + * type + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * if a security manager is set and it denies access + */ + void setAttribute(String attribute, Object value) throws IOException; + + /** + * Reads all, or a subset, of the attributes supported by this file attribute + * view. + * + * <p> The {@code first} and {@code rest} parameters are the names of the + * attributes to read. If any of the parameters has the value {@code "*"} + * then all attributes are read. Attributes that are not supported are + * ignored and will not be present in the returned map. It is implementation + * specific if all attributes are read as an atomic operation with respect + * to other file system operations. + * + * @param first + * the name of an attribute to read (case sensitive) + * @param rest + * the names of other attributes to read (case sensitive) + * + * @return an unmodifiable map of the attributes; may be empty. Its keys are + * the attribute names, its values are the attribute values + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * if a security manager is set and it denies access + */ + Map<String,?> readAttributes(String first, String... rest) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/Attributes.java b/jdk/src/share/classes/java/nio/file/attribute/Attributes.java new file mode 100644 index 00000000000..b3fe130d5ba --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/Attributes.java @@ -0,0 +1,703 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.nio.file.*; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * This class consists exclusively of static methods that operate on or return + * the attributes of files or file stores. These methods provide for convenient + * use of the {@link AttributeView attribute-views} defined in this package. + * + * @since 1.7 + */ + +public final class Attributes { + private Attributes() { + } + + /** + * Splits the given attribute name into the name of an attribute view and + * the attribute. If the attribute view is not identified then it assumed + * to be "basic". + */ + private static String[] split(String attribute) { + String[] s = new String[2]; + int pos = attribute.indexOf(':'); + if (pos == -1) { + s[0] = "basic"; + s[1] = attribute; + } else { + s[0] = attribute.substring(0, pos++); + s[1] = (pos == attribute.length()) ? "" : attribute.substring(pos); + } + return s; + } + + /** + * Sets the value of a file attribute. + * + * <p> The {@code attribute} parameter identifies the attribute to be set + * and takes the form: + * <blockquote> + * [<i>view-name</i><b>:</b>]<i>attribute-name</i> + * </blockquote> + * where square brackets [...] delineate an optional component and the + * character {@code ':'} stands for itself. + * + * <p> <i>view-name</i> is the {@link FileAttributeView#name name} of a {@link + * FileAttributeView} that identifies a set of file attributes. If not + * specified then it defaults to {@code "basic"}, the name of the file + * attribute view that identifies the basic set of file attributes common to + * many file systems. <i>attribute-name</i> is the name of the attribute + * within the set. + * + * <p> <b>Usage Example:</b> + * Suppose we want to set the DOS "hidden" attribute: + * <pre> + * Attributes.setAttribute(file, "dos:hidden", true); + * </pre> + * + * @param file + * A file reference that locates the file + * @param attribute + * The attribute to set + * @param value + * The attribute value + * + * @throws UnsupportedOperationException + * If the attribute view is not available or it does not + * support updating the attribute + * @throws IllegalArgumentException + * If the attribute value is of the correct type but has an + * inappropriate value + * @throws ClassCastException + * If the attribute value is not of the expected type or is a + * collection containing elements that are not of the expected + * type + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. If this method is invoked + * to set security sensitive attributes then the security manager + * may be invoked to check for additional permissions. + */ + public static void setAttribute(FileRef file, String attribute, Object value) + throws IOException + { + String[] s = split(attribute); + FileAttributeView view = file.getFileAttributeView(s[0]); + if (view == null) + throw new UnsupportedOperationException("View '" + s[0] + "' not available"); + view.setAttribute(s[1], value); + } + + /** + * Reads the value of a file attribute. + * + * <p> The {@code attribute} parameter identifies the attribute to be read + * and takes the form: + * <blockquote> + * [<i>view-name</i><b>:</b>]<i>attribute-name</i> + * </blockquote> + * where square brackets [...] delineate an optional component and the + * character {@code ':'} stands for itself. + * + * <p> <i>view-name</i> is the {@link FileAttributeView#name name} of a {@link + * FileAttributeView} that identifies a set of file attributes. If not + * specified then it defaults to {@code "basic"}, the name of the file + * attribute view that identifies the basic set of file attributes common to + * many file systems. <i>attribute-name</i> is the name of the attribute. + * + * <p> The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attribute of the final target + * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed and so + * the method returns the file attribute of the symbolic link. + * + * <p> <b>Usage Example:</b> + * Suppose we require the user ID of the file owner on a system that + * supports a "{@code unix}" view: + * <pre> + * int uid = (Integer)Attributes.getAttribute(file, "unix:uid"); + * </pre> + * + * @param file + * A file reference that locates the file + * @param attribute + * The attribute to read + * @param options + * Options indicating how symbolic links are handled + * + * @return The attribute value, or {@code null} if the attribute view + * is not available or it does not support reading the attribute + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. If this method is invoked + * to read security sensitive attributes then the security manager + * may be invoked to check for additional permissions. + */ + public static Object getAttribute(FileRef file, + String attribute, + LinkOption... options) + throws IOException + { + String[] s = split(attribute); + FileAttributeView view = file.getFileAttributeView(s[0], options); + if (view != null) + return view.getAttribute(s[1]); + // view not available + return null; + } + + /** + * Reads a set of file attributes as a bulk operation. + * + * <p> The {@code attributes} parameter identifies the attributes to be read + * and takes the form: + * <blockquote> + * [<i>view-name</i><b>:</b>]<i>attribute-list</i> + * </blockquote> + * where square brackets [...] delineate an optional component and the + * character {@code ':'} stands for itself. + * + * <p> <i>view-name</i> is the {@link FileAttributeView#name name} of a {@link + * FileAttributeView} that identifies a set of file attributes. If not + * specified then it defaults to {@code "basic"}, the name of the file + * attribute view that identifies the basic set of file attributes common to + * many file systems. + * + * <p> The <i>attribute-list</i> component is a comma separated list of + * zero or more names of attributes to read. If the list contains the value + * {@code "*"} then all attributes are read. Attributes that are not supported + * are ignored and will not be present in the returned map. It is + * implementation specific if all attributes are read as an atomic operation + * with respect to other file system operations. + * + * <p> The following examples demonstrate possible values for the {@code + * attributes} parameter: + * + * <blockquote> + * <table border="0"> + * <tr> + * <td> {@code "*"} </td> + * <td> Read all {@link BasicFileAttributes basic-file-attributes}. </td> + * </tr> + * <tr> + * <td> {@code "size,lastModifiedTime,lastAccessTime"} </td> + * <td> Reads the file size, last modified time, and last access time + * attributes. </td> + * </tr> + * <tr> + * <td> {@code "posix:*"} </td> + * <td> Read all {@link PosixFileAttributes POSIX-file-attributes}.. </td> + * </tr> + * <tr> + * <td> {@code "posix:permissions,owner,size"} </td> + * <td> Reads the POSX file permissions, owner, and file size. </td> + * </tr> + * </table> + * </blockquote> + * + * <p> The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attributes of the final target + * of the link are read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed and so + * the method returns the file attributes of the symbolic link. + * + * @param file + * A file reference that locates the file + * @param attributes + * The attributes to read + * @param options + * Options indicating how symbolic links are handled + * + * @return A map of the attributes returned; may be empty. The map's keys + * are the attribute names, its values are the attribute values + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. If this method is invoked + * to read security sensitive attributes then the security manager + * may be invoke to check for additional permissions. + */ + public static Map<String,?> readAttributes(FileRef file, + String attributes, + LinkOption... options) + throws IOException + { + String[] s = split(attributes); + FileAttributeView view = file.getFileAttributeView(s[0], options); + if (view != null) { + // further split attributes into the first and rest. + String[] names = s[1].split(","); + int rem = names.length-1; + String first = names[0]; + String[] rest = new String[rem]; + if (rem > 0) System.arraycopy(names, 1, rest, 0, rem); + + return view.readAttributes(first, rest); + } + // view not available + return Collections.emptyMap(); + } + + /** + * Reads the basic file attributes of a file. + * + * <p> The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attributes of the final target + * of the link are read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed and so + * the method returns the file attributes of the symbolic link. This option + * should be used where there is a need to determine if a file is a + * symbolic link: + * <pre> + * boolean isSymbolicLink = Attributes.readBasicFileAttributes(file, NOFOLLOW_LINKS).isSymbolicLink(); + * </pre> + * + * <p> It is implementation specific if all file attributes are read as an + * atomic operation with respect to other file system operations. + * + * @param file + * A file reference that locates the file + * @param options + * Options indicating how symbolic links are handled + * + * @return The basic file attributes + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, the security manager's {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to file + * + * @see BasicFileAttributeView#readAttributes + */ + public static BasicFileAttributes readBasicFileAttributes(FileRef file, + LinkOption... options) + throws IOException + { + return file.getFileAttributeView(BasicFileAttributeView.class, options) + .readAttributes(); + } + + /** + * Reads the POSIX file attributes of a file. + * + * <p> The {@code file} parameter locates a file that supports the {@link + * PosixFileAttributeView}. This file attribute view provides access to a + * subset of the file attributes commonly associated with files on file + * systems used by operating systems that implement the Portable Operating + * System Interface (POSIX) family of standards. It is implementation + * specific if all file attributes are read as an atomic operation with + * respect to other file system operations. + * + * <p> The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attributes of the final target + * of the link are read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed and so + * the method returns the file attributes of the symbolic link. + * + * @param file + * A file reference that locates the file + * @param options + * Options indicating how symbolic links are handled + * + * @return The POSIX file attributes + * + * @throws UnsupportedOperationException + * If the {@code PosixFileAttributeView} is not available + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + * + * @see PosixFileAttributeView#readAttributes + */ + public static PosixFileAttributes readPosixFileAttributes(FileRef file, + LinkOption... options) + throws IOException + { + PosixFileAttributeView view = + file.getFileAttributeView(PosixFileAttributeView.class, options); + if (view == null) + throw new UnsupportedOperationException(); + return view.readAttributes(); + } + + /** + * Reads the DOS file attributes of a file. + * + * <p> The {@code file} parameter locates a file that supports the {@link + * DosFileAttributeView}. This file attribute view provides access to + * legacy "DOS" attributes supported by the file systems such as File + * Allocation Table (FAT), commonly used in <em>consumer devices</em>. It is + * implementation specific if all file attributes are read as an atomic + * operation with respect to other file system operations. + * + * <p> The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attributes of the final target + * of the link are read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed and so + * the method returns the file attributes of the symbolic link. + * + * @param file + * A file reference that locates the file + * @param options + * Options indicating how symbolic links are handled + * + * @return The DOS file attributes + * + * @throws UnsupportedOperationException + * If the {@code DosFileAttributeView} is not available + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, the security manager's {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to file + * + * @see DosFileAttributeView#readAttributes + */ + public static DosFileAttributes readDosFileAttributes(FileRef file, + LinkOption... options) + throws IOException + { + DosFileAttributeView view = + file.getFileAttributeView(DosFileAttributeView.class, options); + if (view == null) + throw new UnsupportedOperationException(); + return view.readAttributes(); + } + + /** + * Returns the owner of a file. + * + * <p> The {@code file} parameter locates a file that supports the {@link + * FileOwnerAttributeView}. This file attribute view provides access to + * a file attribute that is the owner of the file. + * + * @param file + * A file reference that locates the file + * + * @return A user principal representing the owner of the file + * + * @throws UnsupportedOperationException + * If the {@code FileOwnerAttributeView} is not available + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + * + * @see FileOwnerAttributeView#getOwner + */ + public static UserPrincipal getOwner(FileRef file) throws IOException { + FileOwnerAttributeView view = + file.getFileAttributeView(FileOwnerAttributeView.class); + if (view == null) + throw new UnsupportedOperationException(); + return view.getOwner(); + } + + /** + * Updates the file owner. + * + * <p> The {@code file} parameter locates a file that supports the {@link + * FileOwnerAttributeView}. This file attribute view provides access to + * a file attribute that is the owner of the file. + * + * @param file + * A file reference that locates the file + * @param owner + * The new file owner + * + * @throws UnsupportedOperationException + * If the {@code FileOwnerAttributeView} is not available + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + * + * @see FileOwnerAttributeView#setOwner + */ + public static void setOwner(FileRef file, UserPrincipal owner) + throws IOException + { + FileOwnerAttributeView view = + file.getFileAttributeView(FileOwnerAttributeView.class); + if (view == null) + throw new UnsupportedOperationException(); + view.setOwner(owner); + } + + /** + * Reads a file's Access Control List (ACL). + * + * <p> The {@code file} parameter locates a file that supports the {@link + * AclFileAttributeView}. This file attribute view provides access to ACLs + * based on the ACL model specified in + * <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC 3530</i></a>. + * + * @param file + * A file reference that locates the file + * + * @return An ordered list of {@link AclEntry entries} representing the + * ACL. The returned list is modifiable. + * + * @throws UnsupportedOperationException + * If the {@code AclAttributeView} is not available + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + * + * @see AclFileAttributeView#getAcl + */ + public static List<AclEntry> getAcl(FileRef file) throws IOException { + AclFileAttributeView view = + file.getFileAttributeView(AclFileAttributeView.class); + if (view == null) + throw new UnsupportedOperationException(); + return view.getAcl(); + } + + /** + * Updates a file's Access Control List (ACL). + * + * <p> The {@code file} parameter locates a file that supports the {@link + * AclFileAttributeView}. This file attribute view provides access to ACLs + * based on the ACL model specified in + * <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC 3530</i></a>. + * + * @param file + * A file reference that locates the file + * @param acl + * The new file ACL + * + * @throws UnsupportedOperationException + * If the {@code AclFileAttributeView} is not available + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + * + * @see AclFileAttributeView#setAcl + */ + public static void setAcl(FileRef file, List<AclEntry> acl) + throws IOException + { + AclFileAttributeView view = + file.getFileAttributeView(AclFileAttributeView.class); + if (view == null) + throw new UnsupportedOperationException(); + view.setAcl(acl); + } + + /** + * Updates the value of a file's last modified time attribute. + * + * <p> The time value is measured since the epoch + * (00:00:00 GMT, January 1, 1970) and is converted to the precision supported + * by the file system. Converting from finer to coarser granularities result + * in precision loss. + * + * <p> If the file system does not support a last modified time attribute then + * this method has no effect. + * + * @param file + * A file reference that locates the file + * + * @param lastModifiedTime + * The new last modified time, or {@code -1L} to update it to + * the current time + * @param unit + * A {@code TimeUnit} determining how to interpret the + * {@code lastModifiedTime} parameter + * + * @throws IllegalArgumentException + * If the {@code lastModifiedime} parameter is a negative value other + * than {@code -1L} + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, the security manager's {@link + * SecurityManager#checkWrite(String) checkWrite} method is invoked + * to check write access to file + * + * @see BasicFileAttributeView#setTimes + */ + public static void setLastModifiedTime(FileRef file, + long lastModifiedTime, + TimeUnit unit) + throws IOException + { + file.getFileAttributeView(BasicFileAttributeView.class) + .setTimes(lastModifiedTime, null, null, unit); + } + + /** + * Updates the value of a file's last access time attribute. + * + * <p> The time value is measured since the epoch + * (00:00:00 GMT, January 1, 1970) and is converted to the precision supported + * by the file system. Converting from finer to coarser granularities result + * in precision loss. + * + * <p> If the file system does not support a last access time attribute then + * this method has no effect. + * + * @param lastAccessTime + * The new last access time, or {@code -1L} to update it to + * the current time + * @param unit + * A {@code TimeUnit} determining how to interpret the + * {@code lastModifiedTime} parameter + * + * @throws IllegalArgumentException + * If the {@code lastAccessTime} parameter is a negative value other + * than {@code -1L} + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, the security manager's {@link + * SecurityManager#checkWrite(String) checkWrite} method is invoked + * to check write access to file + * + * @see BasicFileAttributeView#setTimes + */ + public static void setLastAccessTime(FileRef file, + long lastAccessTime, + TimeUnit unit) + throws IOException + { + file.getFileAttributeView(BasicFileAttributeView.class) + .setTimes(null, lastAccessTime, null, unit); + } + + /** + * Sets a file's POSIX permissions. + * + * <p> The {@code file} parameter is a reference to an existing file. It + * supports the {@link PosixFileAttributeView} that provides access to file + * attributes commonly associated with files on file systems used by + * operating systems that implement the Portable Operating System Interface + * (POSIX) family of standards. + * + * @param file + * A file reference that locates the file + * @param perms + * The new set of permissions + * + * @throws UnsupportedOperationException + * If {@code PosixFileAttributeView} is not available + * @throws ClassCastException + * If the sets contains elements that are not of type {@code + * PosixFilePermission} + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + * + * @see PosixFileAttributeView#setPermissions + */ + public static void setPosixFilePermissions(FileRef file, + Set<PosixFilePermission> perms) + throws IOException + { + PosixFileAttributeView view = + file.getFileAttributeView(PosixFileAttributeView.class); + if (view == null) + throw new UnsupportedOperationException(); + view.setPermissions(perms); + } + + /** + * Reads the space attributes of a file store. + * + * <p> The {@code store} parameter is a file store that supports the + * {@link FileStoreSpaceAttributeView} providing access to the space related + * attributes of the file store. It is implementation specific if all attributes + * are read as an atomic operation with respect to other file system operations. + * + * @param store + * The file store + * + * @return The file store space attributes + * + * @throws UnsupportedOperationException + * If the file store space attribute view is not supported + * @throws IOException + * If an I/O error occurs + * + * @see FileStoreSpaceAttributeView#readAttributes() + */ + public static FileStoreSpaceAttributes readFileStoreSpaceAttributes(FileStore store) + throws IOException + { + FileStoreSpaceAttributeView view = + store.getFileStoreAttributeView(FileStoreSpaceAttributeView.class); + if (view == null) + throw new UnsupportedOperationException(); + return view.readAttributes(); + } +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java new file mode 100644 index 00000000000..70100834d8f --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java @@ -0,0 +1,186 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.util.concurrent.TimeUnit; +import java.io.IOException; + +/** + * A file attribute view that provides a view of a <em>basic set</em> of file + * attributes common to many file systems. The basic set of file attributes + * consist of <em>mandatory</em> and <em>optional</em> file attributes as + * defined by the {@link BasicFileAttributes} interface. + + * <p> The file attributes are retrieved from the file system as a <em>bulk + * operation</em> by invoking the {@link #readAttributes() readAttributes} method. + * This class also defines the {@link #setTimes setTimes} method to update the + * file's time attributes. + * + * <p> Where dynamic access to file attributes is required, the attributes + * supported by this attribute view have the following names and types: + * <blockquote> + * <table border="1" cellpadding="8"> + * <tr> + * <th> Name </th> + * <th> Type </th> + * </tr> + * <tr> + * <td> "lastModifiedTime" </td> + * <td> {@link Long} </td> + * </tr> + * <tr> + * <td> "lastAccessTime" </td> + * <td> {@link Long} </td> + * </tr> + * <tr> + * <td> "creationTime" </td> + * <td> {@link Long} </td> + * </tr> + * <tr> + * <td> "resolution" </td> + * <td> {@link java.util.concurrent.TimeUnit} </td> + * </tr> + * <tr> + * <td> "size" </td> + * <td> {@link Long} </td> + * </tr> + * <tr> + * <td> "isRegularFile" </td> + * <td> {@link Boolean} </td> + * </tr> + * <tr> + * <td> "isDirectory" </td> + * <td> {@link Boolean} </td> + * </tr> + * <tr> + * <td> "isSymbolicLink" </td> + * <td> {@link Boolean} </td> + * </tr> + * <tr> + * <td> "isOther" </td> + * <td> {@link Boolean} </td> + * </tr> + * <tr> + * <td> "linkCount" </td> + * <td> {@link Integer} </td> + * </tr> + * <tr> + * <td> "fileKey" </td> + * <td> {@link Object} </td> + * </tr> + * </table> + * </blockquote> + * + * <p> The {@link #getAttribute getAttribute} or {@link + * #readAttributes(String,String[]) readAttributes(String,String[])} methods may + * be used to read any of these attributes as if by invoking the {@link + * #readAttributes() readAttributes()} method. + * + * <p> The {@link #setAttribute setAttribute} method may be used to update the + * file's last modified time, last access time or create time attributes as if + * by invoking the {@link #setTimes setTimes} method. In that case, the time + * value is interpreted in {@link TimeUnit#MILLISECONDS milliseconds} and + * converted to the precision supported by the file system. + * + * @since 1.7 + * @see Attributes + */ + +public interface BasicFileAttributeView + extends FileAttributeView +{ + /** + * Returns the name of the attribute view. Attribute views of this type + * have the name {@code "basic"}. + */ + @Override + String name(); + + /** + * Reads the basic file attributes as a bulk operation. + * + * <p> It is implementation specific if all file attributes are read as an + * atomic operation with respect to other file system operations. + * + * @return the file attributes + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file + */ + BasicFileAttributes readAttributes() throws IOException; + + /** + * Updates any or all of the file's last modified time, last access time, + * and create time attributes. + * + * <p> This method updates the file's timestamp attributes. The values are + * measured since the epoch (00:00:00 GMT, January 1, 1970) and converted to + * the precision supported by the file system. Converting from finer to + * coarser granularities result in precision loss. If a value is larger + * than the maximum supported by the file system then the corresponding + * timestamp is set to its maximum value. + * + * <p> If any of the {@code lastModifiedTime}, {@code lastAccessTime}, + * or {@code createTime} parameters has the value {@code null} then the + * corresponding timestamp is not changed. An implementation may require to + * read the existing values of the file attributes when only some, but not + * all, of the timestamp attributes are updated. Consequently, this method + * may not be an atomic operation with respect to other file system + * operations. If all of the {@code lastModifiedTime}, {@code + * lastAccessTime} and {@code createTime} parameters are {@code null} then + * this method has no effect. + * + * @param lastModifiedTime + * the new last modified time, or {@code -1L} to update it to + * the current time, or {@code null} to not change the attribute + * @param lastAccessTime + * the last access time, or {@code -1L} to update it to + * the current time, or {@code null} to not change the attribute. + * @param createTime + * the file's create time, or {@code -1L} to update it to + * the current time, or {@code null} to not change the attribute + * @param unit + * a {@code TimeUnit} determining how to interpret the time values + * + * @throws IllegalArgumentException + * if any of the parameters is a negative value other than {@code + * -1L} + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, its {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file + */ + void setTimes(Long lastModifiedTime, + Long lastAccessTime, + Long createTime, + TimeUnit unit) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributes.java b/jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributes.java new file mode 100644 index 00000000000..64c163bc5a1 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributes.java @@ -0,0 +1,163 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.util.concurrent.TimeUnit; + +/** + * Basic attributes associated with a file in a file system. + * + * <p> Basic file attributes are attributes that are common to many file systems + * and consist of mandatory and optional file attributes as defined by this + * interface. + * + * <p> <b>Usage Example:</b> + * <pre> + * FileRef file = ... + * BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file); + * </pre> + * + * @since 1.7 + * + * @see BasicFileAttributeView + */ + +public interface BasicFileAttributes { + + /** + * Returns the time of last modification. + * + * <p> The {@link #resolution() resolution} method returns the {@link TimeUnit} + * to interpret the return value of this method. + * + * @return a <code>long</code> value representing the time the file was + * last modified since the epoch (00:00:00 GMT, January 1, 1970), + * or {@code -1L} if the attribute is not supported. + */ + long lastModifiedTime(); + + /** + * Returns the time of last access if supported. + * + * <p> The {@link #resolution() resolution} method returns the {@link TimeUnit} + * to interpret the return value of this method. + * + * @return a <code>long</code> value representing the time of last access + * since the epoch (00:00:00 GMT, January 1, 1970), or {@code -1L} + * if the attribute is not supported. + */ + long lastAccessTime(); + + /** + * Returns the creation time if supported. The creation time is the time + * that the file was created. + * + * <p> The {@link #resolution() resolution} method returns the {@link TimeUnit} + * to interpret the return value of this method. + * + * @return a <code>long</code> value representing the time the file was + * created since the epoch (00:00:00 GMT, January 1, 1970), or + * {@code -1L} if the attribute is not supported. + */ + long creationTime(); + + /** + * Returns the {@link TimeUnit} required to interpret the time of last + * modification, time of last access, and creation time. + * + * @return the {@code TimeUnit} required to interpret the file time stamps + */ + TimeUnit resolution(); + + /** + * Tells whether the file is a regular file with opaque content. + */ + boolean isRegularFile(); + + /** + * Tells whether the file is a directory. + */ + boolean isDirectory(); + + /** + * Tells whether the file is a symbolic-link. + */ + boolean isSymbolicLink(); + + /** + * Tells whether the file is something other than a regular file, directory, + * or link. + */ + boolean isOther(); + + /** + * Returns the size of the file (in bytes). The size may differ from the + * actual size on the file system due to compression, support for sparse + * files, or other reasons. The size of files that are not {@link + * #isRegularFile regular} files is implementation specific and + * therefore unspecified. + * + * @return the file size, in bytes + */ + long size(); + + /** + * Returns the number of <em>links</em> to this file. + * + * <p> On file systems where the same file may be in several directories then + * the link count is the number of directory entries for the file. The return + * value is {@code 1} on file systems that only allow a file to have a + * single name in a single directory. + * + * @see java.nio.file.Path#createLink + */ + int linkCount(); + + /** + * Returns an object that uniquely identifies the given file, or {@code + * null} if a file key is not available. On some platforms or file systems + * it is possible to use an identifier, or a combination of identifiers to + * uniquely identify a file. Such identifiers are important for operations + * such as file tree traversal in file systems that support <a + * href="../package-summary.html#links">symbolic links</a> or file systems + * that allow a file to be an entry in more than one directory. On UNIX file + * systems, for example, the <em>device ID</em> and <em>inode</em> are + * commonly used for such purposes. + * + * <p> The file key returned by this method can only be guaranteed to be + * unique if the file system and files remain static. Whether a file system + * re-uses identifiers after a file is deleted is implementation dependent and + * therefore unspecified. + * + * <p> File keys returned by this method can be compared for equality and are + * suitable for use in collections. If the file system and files remain static, + * and two files are the {@link java.nio.file.FileRef#isSameFile same} with + * non-{@code null} file keys, then their file keys are equal. + * + * @see java.nio.file.Files#walkFileTree + */ + Object fileKey(); +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java new file mode 100644 index 00000000000..c57683999b6 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java @@ -0,0 +1,179 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.io.IOException; + +/** + * A file attribute view that provides a view of the legacy "DOS" file attributes. + * These attributes are supported by file systems such as the File Allocation + * Table (FAT) format commonly used in <em>consumer devices</em>. + * + * <p> A {@code DosFileAttributeView} is a {@link BasicFileAttributeView} that + * additionally supports access to the set of DOS attribute flags that are used + * to indicate if the file is read-only, hidden, a system file, or archived. + * + * <p> Where dynamic access to file attributes is required, the attributes + * supported by this attribute view are as defined by {@code + * BasicFileAttributeView}, and in addition, the following attributes are + * supported: + * <blockquote> + * <table border="1" cellpadding="8"> + * <tr> + * <th> Name </th> + * <th> Type </th> + * </tr> + * <tr> + * <td> readonly </td> + * <td> {@link Boolean} </td> + * </tr> + * <tr> + * <td> hidden </td> + * <td> {@link Boolean} </td> + * </tr> + * <tr> + * <td> system </td> + * <td> {@link Boolean} </td> + * </tr> + * <tr> + * <td> archive </td> + * <td> {@link Boolean} </td> + * </tr> + * </table> + * </blockquote> + * + * <p> The {@link #getAttribute getAttribute} or {@link #readAttributes(String,String[]) + * readAttributes(String,String[])} methods may be used to read any of these + * attributes, or any of the attributes defined by {@link BasicFileAttributeView} + * as if by invoking the {@link #readAttributes readAttributes()} method. + * + * <p> The {@link #setAttribute setAttribute} method may be used to update the + * file's last modified time, last access time or create time attributes as + * defined by {@link BasicFileAttributeView}. It may also be used to update + * the DOS attributes as if by invoking the {@link #setReadOnly setReadOnly}, + * {@link #setHidden setHidden}, {@link #setSystem setSystem}, and {@link + * #setArchive setArchive} methods respectively. + * + * @since 1.7 + */ + +public interface DosFileAttributeView + extends BasicFileAttributeView +{ + /** + * Returns the name of the attribute view. Attribute views of this type + * have the name {@code "dos"}. + */ + @Override + String name(); + + /** + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + DosFileAttributes readAttributes() throws IOException; + + /** + * Updates the value of the read-only attribute. + * + * <p> It is implementation specific if the attribute can be updated as an + * atomic operation with respect to other file system operations. An + * implementation may, for example, require to read the existing value of + * the DOS attribute in order to update this attribute. + * + * @param value + * the new value of the attribute + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default, and a security manager is installed, + * its {@link SecurityManager#checkWrite(String) checkWrite} method + * is invoked to check write access to the file + */ + void setReadOnly(boolean value) throws IOException; + + /** + * Updates the value of the hidden attribute. + * + * <p> It is implementation specific if the attribute can be updated as an + * atomic operation with respect to other file system operations. An + * implementation may, for example, require to read the existing value of + * the DOS attribute in order to update this attribute. + * + * @param value + * the new value of the attribute + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default, and a security manager is installed, + * its {@link SecurityManager#checkWrite(String) checkWrite} method + * is invoked to check write access to the file + */ + void setHidden(boolean value) throws IOException; + + /** + * Updates the value of the system attribute. + * + * <p> It is implementation specific if the attribute can be updated as an + * atomic operation with respect to other file system operations. An + * implementation may, for example, require to read the existing value of + * the DOS attribute in order to update this attribute. + * + * @param value + * the new value of the attribute + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default, and a security manager is installed, + * its {@link SecurityManager#checkWrite(String) checkWrite} method + * is invoked to check write access to the file + */ + void setSystem(boolean value) throws IOException; + + /** + * Updates the value of the archive attribute. + * + * <p> It is implementation specific if the attribute can be updated as an + * atomic operation with respect to other file system operations. An + * implementation may, for example, require to read the existing value of + * the DOS attribute in order to update this attribute. + * + * @param value + * the new value of the attribute + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default, and a security manager is installed, + * its {@link SecurityManager#checkWrite(String) checkWrite} method + * is invoked to check write access to the file + */ + void setArchive(boolean value) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/DosFileAttributes.java b/jdk/src/share/classes/java/nio/file/attribute/DosFileAttributes.java new file mode 100644 index 00000000000..53e63d51a98 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/DosFileAttributes.java @@ -0,0 +1,84 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +/** + * File attributes associated with a file in a file system that supports + * legacy "DOS" attributes. + * + * <p> The DOS attributes of a file are retrieved using a {@link + * DosFileAttributeView} by invoking its {@link DosFileAttributeView#readAttributes + * readAttributes} method. + * + * @since 1.7 + * + * @see Attributes#readDosFileAttributes + */ + +public interface DosFileAttributes + extends BasicFileAttributes +{ + /** + * Returns the value of the read-only attribute. + * + * <p> This attribute is often used as a simple access control mechanism + * to prevent files from being deleted or updated. Whether the file system + * or platform does any enforcement to prevent <em>read-only</em> files + * from being updated is implementation specific. + * + * @return the value of the read-only attribute + */ + boolean isReadOnly(); + + /** + * Returns the value of the hidden attribute. + * + * <p> This attribute is often used to indicate if the file is visible to + * users. + * + * @return the value of the hidden attribute + */ + boolean isHidden(); + + /** + * Returns the value of the archive attribute. + * + * <p> This attribute is typically used by backup programs. + * + * @return the value of the archive attribute + */ + boolean isArchive(); + + /** + * Returns the value of the system attribute. + * + * <p> This attribute is often used to indicate that the file is a component + * of the operating system. + * + * @return the value of the system attribute + */ + boolean isSystem(); +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/FileAttribute.java b/jdk/src/share/classes/java/nio/file/attribute/FileAttribute.java new file mode 100644 index 00000000000..ed0d7311ff0 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/FileAttribute.java @@ -0,0 +1,50 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +/** + * An object that encapsulates the value of a file attribute that can be set + * atomically when creating a new file or directory by invoking the {@link + * java.nio.file.Path#createFile createFile} or {@link + * java.nio.file.Path#createDirectory createDirectory} methods. + * + * @param <T> The type of the file attribute value + * + * @since 1.7 + * @see PosixFilePermissions#asFileAttribute + */ + +public interface FileAttribute<T> { + /** + * Returns the attribute name. + */ + String name(); + + /** + * Returns the attribute value. + */ + T value(); +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/FileAttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/FileAttributeView.java new file mode 100644 index 00000000000..78a67b4a4cd --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/FileAttributeView.java @@ -0,0 +1,43 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +/** + * An attribute view that is a read-only or updatable view of non-opaque + * values associated with a file in a filesystem. This interface is extended or + * implemented by specific file attribute views that define methods to read + * and/or update the attributes of a file. + * + * @since 1.7 + * + * @see java.nio.file.FileRef#getFileAttributeView(Class,java.nio.file.LinkOption[]) + * @see java.nio.file.FileRef#getFileAttributeView(String,java.nio.file.LinkOption[]) + */ + +public interface FileAttributeView + extends AttributeView +{ +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java new file mode 100644 index 00000000000..0afc19efbff --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java @@ -0,0 +1,101 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.io.IOException; + +/** + * A file attribute view that supports reading or updating the owner of a file. + * This file attribute view is intended for file system implementations that + * support a file attribute that represents an identity that is the owner of + * the file. Often the owner of a file is the identity of the entity that + * created the file. + * + * <p> The {@link #getOwner getOwner} or {@link #setOwner setOwner} methods may + * be used to read or update the owner of the file. + * + * <p> Where dynamic access to file attributes is required, the owner attribute + * is identified by the name {@code "owner"}, and the value of the attribute is + * a {@link UserPrincipal}. The {@link #readAttributes readAttributes}, {@link + * #getAttribute getAttribute} and {@link #setAttribute setAttributes} methods + * may be used to read or update the file owner. + * + * @since 1.7 + */ + +public interface FileOwnerAttributeView + extends FileAttributeView +{ + /** + * Returns the name of the attribute view. Attribute views of this type + * have the name {@code "owner"}. + */ + @Override + String name(); + + /** + * Read the file owner. + * + * <p> It it implementation specific if the file owner can be a {@link + * GroupPrincipal group}. + * + * @return the file owner + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link + * RuntimePermission}<tt>("accessUserInformation")</tt> or its + * {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + */ + UserPrincipal getOwner() throws IOException; + + /** + * Updates the file owner. + * + * <p> It it implementation specific if the file owner can be a {@link + * GroupPrincipal group}. To ensure consistent and correct behavior + * across platforms it is recommended that this method should only be used + * to set the file owner to a user principal that is not a group. + * + * @param owner + * the new file owner + * + * @throws IOException + * if an I/O error occurs, or the {@code owner} parameter is a + * group and this implementation does not support setting the owner + * to a group + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link + * RuntimePermission}<tt>("accessUserInformation")</tt> or its + * {@link SecurityManager#checkWrite(String) checkWrite} method + * denies write access to the file. + */ + void setOwner(UserPrincipal owner) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/FileStoreAttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/FileStoreAttributeView.java new file mode 100644 index 00000000000..6dfb3ff0228 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/FileStoreAttributeView.java @@ -0,0 +1,38 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +/** + * An attribute view that is a read-only or updatable view of the attributes of + * a {@link java.nio.file.FileStore}. + * + * @since 1.7 + */ + +public interface FileStoreAttributeView + extends AttributeView +{ +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributeView.java new file mode 100644 index 00000000000..22d38617cb0 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributeView.java @@ -0,0 +1,85 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.io.IOException; + +/** + * A file store attribute view that supports reading of space attributes. + * + * <p> Where dynamic access to file attributes is required, the attributes + * supported by this attribute view have the following names and types: + * <blockquote> + * <table border="1" cellpadding="8"> + * <tr> + * <th> Name </th> + * <th> Type </th> + * </tr> + * <tr> + * <td> "totalSpace" </td> + * <td> {@link Long} </td> + * </tr> + * <tr> + * <td> "usableSpace" </td> + * <td> {@link Long} </td> + * </tr> + * <tr> + * <td> "unallocatedSpace" </td> + * <td> {@link Long} </td> + * </tr> + * </table> + * </blockquote> + * <p> The {@link #getAttribute getAttribute} or {@link #readAttributes + * readAttributes(String,String[])} methods may be used to read any of these + * attributes as if by invoking the {@link #readAttributes readAttributes()} + * method. + * + * @since 1.7 + */ + +public interface FileStoreSpaceAttributeView + extends FileStoreAttributeView +{ + /** + * Returns the name of the attribute view. Attribute views of this type + * have the name {@code "space"}. + */ + @Override + String name(); + + /** + * Reads the disk space attributes as a bulk operation. + * + * <p> It is file system specific if all attributes are read as an + * atomic operation with respect to other file system operations. + * + * @return The disk space attributes + * + * @throws IOException + * If an I/O error occurs + */ + FileStoreSpaceAttributes readAttributes() throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributes.java b/jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributes.java new file mode 100644 index 00000000000..6f12d71e595 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributes.java @@ -0,0 +1,66 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +/** + * Space related attributes of a file store. + * + * @since 1.7 + * + * @see Attributes#readFileStoreSpaceAttributes + */ + +public interface FileStoreSpaceAttributes { + /** + * Returns the size, in bytes, of the file store. + */ + long totalSpace(); + + /** + * Returns the number of bytes available to this Java virtual machine on the + * file store. + * + * <p> The returned number of available bytes is a hint, but not a + * guarantee, that it is possible to use most or any of these bytes. The + * number of usable bytes is most likely to be accurate immediately + * after the space attributes are obtained. It is likely to be made inaccurate + * by any external I/O operations including those made on the system outside + * of this Java virtual machine. + */ + long usableSpace(); + + /** + * Returns the number of unallocated bytes in the file store. + * + * <p> The returned number of unallocated bytes is a hint, but not a + * guarantee, that it is possible to use most or any of these bytes. The + * number of unallocated bytes is most likely to be accurate immediately + * after the space attributes are obtained. It is likely to be + * made inaccurate by any external I/O operations including those made on + * the system outside of this virtual machine. + */ + long unallocatedSpace(); +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/GroupPrincipal.java b/jdk/src/share/classes/java/nio/file/attribute/GroupPrincipal.java new file mode 100644 index 00000000000..db09d48ae65 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/GroupPrincipal.java @@ -0,0 +1,42 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +/** + * A {@code UserPrincipal} representing a <em>group identity</em>, used to + * determine access rights to objects in a file system. The exact definition of + * a group is implementation specific, but typically, it represents an identity + * created for administrative purposes so as to determine the access rights for + * the members of the group. Whether an entity can be a member of multiple + * groups, and whether groups can be nested, are implementation specified and + * therefore not specified. + * + * @since 1.7 + * + * @see UserPrincipalLookupService#lookupPrincipalByGroupName + */ + +public interface GroupPrincipal extends UserPrincipal { } diff --git a/jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java new file mode 100644 index 00000000000..285b8bb7d1c --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java @@ -0,0 +1,196 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.nio.file.*; +import java.util.Set; +import java.io.IOException; + +/** + * A file attribute view that provides a view of the file attributes commonly + * associated with files on file systems used by operating systems that implement + * the Portable Operating System Interface (POSIX) family of standards. + * + * <p> Operating systems that implement the <a href="http://www.opengroup.org"> + * POSIX</a> family of standards commonly use file systems that have a + * file <em>owner</em>, <em>group-owner</em>, and related <em>access + * permissions</em>. This file attribute view provides read and write access + * to these attributes. + * + * <p> The {@link #readAttributes() readAttributes} method is used to read the + * file's attributes. The file {@link PosixFileAttributes#owner() owner} is + * represented by a {@link UserPrincipal} that is the identity of the file owner + * for the purposes of access control. The {@link PosixFileAttributes#group() + * group-owner}, represented by a {@link GroupPrincipal}, is the identity of the + * group owner, where a group is an identity created for administrative purposes + * so as to determine the access rights for the members of the group. + * + * <p> The {@link PosixFileAttributes#permissions() permissions} attribute is a + * set of access permissions. This file attribute view provides access to the nine + * permission defined by the {@link PosixFilePermission} class. + * These nine permission bits determine the <em>read</em>, <em>write</em>, and + * <em>execute</em> access for the file owner, group, and others (others + * meaning identities other than the owner and members of the group). Some + * operating systems and file systems may provide additional permission bits + * but access to these other bits is not defined by this class in this release. + * + * <p> <b>Usage Example:</b> + * Suppose we need to print out the owner and access permissions of a file: + * <pre> + * FileRef file = ... + * PosixFileAttributes attrs = file.newFileAttributeView(PosixFileAttributeView.class) + * .readAttributes(); + * System.out.format("%s %s%n", + * attrs.owner().getName(), + * PosixFilePermissions.toString(attrs.permissions())); + * </pre> + * + * <h4> Dynamic Access </h4> + * <p> Where dynamic access to file attributes is required, the attributes + * supported by this attribute view are as defined by {@link + * BasicFileAttributeView} and {@link FileOwnerAttributeView}, and in addition, + * the following attributes are supported: + * <blockquote> + * <table border="1" cellpadding="8"> + * <tr> + * <th> Name </th> + * <th> Type </th> + * </tr> + * <tr> + * <td> "permissions" </td> + * <td> {@link Set}<{@link PosixFilePermission}> </td> + * </tr> + * <tr> + * <td> "group" </td> + * <td> {@link GroupPrincipal} </td> + * </tr> + * </table> + * </blockquote> + * + * <p> The {@link #getAttribute getAttribute} or {@link + * #readAttributes(String,String[]) readAttributes(String,String[])} methods may + * be used to read any of these attributes, or any of the attributes defined by + * {@link BasicFileAttributeView} as if by invoking the {@link #readAttributes + * readAttributes()} method. + * + * <p> The {@link #setAttribute setAttribute} method may be used to update the + * file's last modified time, last access time or create time attributes as + * defined by {@link BasicFileAttributeView}. It may also be used to update + * the permissions, owner, or group-owner as if by invoking the {@link + * #setPermissions setPermissions}, {@link #setOwner setOwner}, and {@link + * #setGroup setGroup} methods respectively. + * + * <h4> Setting Initial Permissions </h4> + * <p> Implementations supporting this attribute view may also support setting + * the initial permissions when creating a file or directory. The + * initial permissions are provided to the {@link Path#createFile createFile} + * or {@link Path#createDirectory createDirectory} methods as a {@link + * FileAttribute} with {@link FileAttribute#name name} {@code "posix:permissions"} + * and a {@link FileAttribute#value value} that is the set of permissions. The + * following example uses the {@link PosixFilePermissions#asFileAttribute + * asFileAttribute} method to construct a {@code FileAttribute} when creating a + * file: + * + * <pre> + * Path path = ... + * Set<PosixFilePermission> perms = + * EnumSet.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ); + * path.createFile(PosixFilePermissions.asFileAttribute(perms)); + * </pre> + * + * <p> When the access permissions are set at file creation time then the actual + * value of the permissions may differ that the value of the attribute object. + * The reasons for this are implementation specific. On UNIX systems, for + * example, a process has a <em>umask</em> that impacts the permission bits + * of newly created files. Where an implementation supports the setting of + * the access permissions, and the underlying file system supports access + * permissions, then it is required that the value of the actual access + * permissions will be equal or less than the value of the attribute + * provided to the {@link java.nio.file.Path#createFile createFile} or + * {@link java.nio.file.Path#createDirectory createDirectory} methods. In + * other words, the file may be more secure than requested. + * + * @since 1.7 + * + * @see Attributes#readPosixFileAttributes + */ + +public interface PosixFileAttributeView + extends BasicFileAttributeView, FileOwnerAttributeView +{ + /** + * Returns the name of the attribute view. Attribute views of this type + * have the name {@code "posix"}. + */ + @Override + String name(); + + /** + * @throws IOException {@inheritDoc} + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + */ + @Override + PosixFileAttributes readAttributes() throws IOException; + + /** + * Updates the file permissions. + * + * @param perms + * the new set of permissions + * + * @throws ClassCastException + * if the sets contains elements that are not of type {@code + * PosixFilePermission} + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + */ + void setPermissions(Set<PosixFilePermission> perms) throws IOException; + + /** + * Updates the file group-owner. + * + * @param group + * the new file group-owner + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + */ + void setGroup(GroupPrincipal group) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java b/jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java new file mode 100644 index 00000000000..c09aa9db37c --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java @@ -0,0 +1,77 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.util.Set; + +/** + * File attributes associated with files on file systems used by operating systems + * that implement the Portable Operating System Interface (POSIX) family of + * standards. + * + * <p> The POSIX attributes of a file are retrieved using a {@link + * PosixFileAttributeView} by invoking its {@link + * PosixFileAttributeView#readAttributes readAttributes} method. + * + * @since 1.7 + * + * @see Attributes#readPosixFileAttributes + */ + +public interface PosixFileAttributes + extends BasicFileAttributes +{ + /** + * Returns the owner of the file. + * + * @return the file owner + * + * @see PosixFileAttributeView#setOwner + */ + UserPrincipal owner(); + + /** + * Returns the group owner of the file. + * + * @return the file group owner + * + * @see PosixFileAttributeView#setGroup + */ + GroupPrincipal group(); + + /** + * Returns the permissions of the file. The file permissions are returned + * as a set of {@link PosixFilePermission} elements. The returned set is a + * copy of the file permissions and is modifiable. This allows the result + * to be modified and passed to the {@link PosixFileAttributeView#setPermissions + * setPermissions} method to update the file's permissions. + * + * @return the file permissions + * + * @see PosixFileAttributeView#setPermissions + */ + Set<PosixFilePermission> permissions(); +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/PosixFilePermission.java b/jdk/src/share/classes/java/nio/file/attribute/PosixFilePermission.java new file mode 100644 index 00000000000..795f5099408 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/PosixFilePermission.java @@ -0,0 +1,86 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.util.*; + +/** + * Defines the bits for use with the {@link PosixFileAttributes#permissions() + * permissions} attribute. + * + * <p> The {@link PosixFileAttributes} class defines method methods for + * manipulating {@link Set sets} of permissions. + * + * @since 1.7 + */ + +public enum PosixFilePermission { + + /** + * Read permission, owner. + */ + OWNER_READ, + + /** + * Write permission, owner. + */ + OWNER_WRITE, + + /** + * Execute/search permission, owner. + */ + OWNER_EXECUTE, + + /** + * Read permission, group. + */ + GROUP_READ, + + /** + * Write permission, group. + */ + GROUP_WRITE, + + /** + * Execute/search permission, group. + */ + GROUP_EXECUTE, + + /** + * Read permission, others. + */ + OTHERS_READ, + + /** + * Write permission, others. + */ + OTHERS_WRITE, + + /** + * Execute/search permission, others. + */ + OTHERS_EXECUTE; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/PosixFilePermissions.java b/jdk/src/share/classes/java/nio/file/attribute/PosixFilePermissions.java new file mode 100644 index 00000000000..97d322c6a59 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/PosixFilePermissions.java @@ -0,0 +1,180 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import static java.nio.file.attribute.PosixFilePermission.*; +import java.util.*; + +/** + * This class consists exclusively of static methods that operate on sets of + * {@link PosixFilePermission} objects. + * + * @since 1.7 + */ + +public class PosixFilePermissions { + private PosixFilePermissions() { } + + // Write string representation of permission bits to {@code sb}. + private static void writeBits(StringBuilder sb, boolean r, boolean w, boolean x) { + if (r) { + sb.append('r'); + } else { + sb.append('-'); + } + if (w) { + sb.append('w'); + } else { + sb.append('-'); + } + if (x) { + sb.append('x'); + } else { + sb.append('-'); + } + } + + /** + * Returns the {@code String} representation of a set of permissions. + * + * <p> If the set contains {@code null} or elements that are not of type + * {@code PosixFilePermission} then these elements are ignored. + * + * @param perms + * the set of permissions + * + * @return the string representation of the permission set + * + * @see #fromString + */ + public static String toString(Set<PosixFilePermission> perms) { + StringBuilder sb = new StringBuilder(9); + writeBits(sb, perms.contains(OWNER_READ), perms.contains(OWNER_WRITE), + perms.contains(OWNER_EXECUTE)); + writeBits(sb, perms.contains(GROUP_READ), perms.contains(GROUP_WRITE), + perms.contains(GROUP_EXECUTE)); + writeBits(sb, perms.contains(OTHERS_READ), perms.contains(OTHERS_WRITE), + perms.contains(OTHERS_EXECUTE)); + return sb.toString(); + } + + private static boolean isSet(char c, char setValue) { + if (c == setValue) + return true; + if (c == '-') + return false; + throw new IllegalArgumentException("Invalid mode"); + } + private static boolean isR(char c) { return isSet(c, 'r'); } + private static boolean isW(char c) { return isSet(c, 'w'); } + private static boolean isX(char c) { return isSet(c, 'x'); } + + /** + * Returns the set of permissions corresponding to a given {@code String} + * representation. + * + * <p> The {@code perms} parameter is a {@code String} representing the + * permissions. It has 9 characters that are interpreted as three sets of + * three. The first set refers to the owner's permissions; the next to the + * group permissions and the last to others. Within each set, the first + * character is {@code 'r'} to indicate permission to read, the second + * character is {@code 'w'} to indicate permission to write, and the third + * character is {@code 'x'} for execute permission. Where a permission is + * not set then the corresponding character is set to {@code '-'}. + * + * <p> <b>Usage Example:</b> + * Suppose we require the set of permissions that indicate the owner has read, + * write, and execute permissions, the group has read and execute permissions + * and others have none. + * <pre> + * Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---"); + * </pre> + * + * @param perms + * string representing a set of permissions + * + * @return the resulting set of permissions + * + * @throws IllegalArgumentException + * if the string cannot be converted to a set of permissions + * + * @see #toString(Set) + */ + public static Set<PosixFilePermission> fromString(String perms) { + if (perms.length() != 9) + throw new IllegalArgumentException("Invalid mode"); + Set<PosixFilePermission> result = new HashSet<PosixFilePermission>(); + if (isR(perms.charAt(0))) result.add(OWNER_READ); + if (isW(perms.charAt(1))) result.add(OWNER_WRITE); + if (isX(perms.charAt(2))) result.add(OWNER_EXECUTE); + if (isR(perms.charAt(3))) result.add(GROUP_READ); + if (isW(perms.charAt(4))) result.add(GROUP_WRITE); + if (isX(perms.charAt(5))) result.add(GROUP_EXECUTE); + if (isR(perms.charAt(6))) result.add(OTHERS_READ); + if (isW(perms.charAt(7))) result.add(OTHERS_WRITE); + if (isX(perms.charAt(8))) result.add(OTHERS_EXECUTE); + return result; + } + + /** + * Creates a {@link FileAttribute}, encapsulating a copy of the given file + * permissions, suitable for passing to the {@link java.nio.file.Path#createFile + * createFile} or {@link java.nio.file.Path#createDirectory createDirectory} + * methods. + * + * @param perms + * the set of permissions + * + * @return an attribute encapsulating the given file permissions with + * {@link FileAttribute#name name} {@code "posix:permissions"} + * + * @throws ClassCastException + * if the set contains elements that are not of type {@code + * PosixFilePermission} + */ + public static FileAttribute<Set<PosixFilePermission>> + asFileAttribute(Set<PosixFilePermission> perms) + { + // copy set and check for nulls (CCE will be thrown if an element is not + // a PosixFilePermission) + perms = new HashSet<PosixFilePermission>(perms); + for (PosixFilePermission p: perms) { + if (p == null) + throw new NullPointerException(); + } + final Set<PosixFilePermission> value = perms; + return new FileAttribute<Set<PosixFilePermission>>() { + @Override + public String name() { + return "posix:permissions"; + } + @Override + public Set<PosixFilePermission> value() { + return Collections.unmodifiableSet(value); + } + }; + } +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/UserDefinedFileAttributeView.java b/jdk/src/share/classes/java/nio/file/attribute/UserDefinedFileAttributeView.java new file mode 100644 index 00000000000..c0b6896011a --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/UserDefinedFileAttributeView.java @@ -0,0 +1,232 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.nio.ByteBuffer; +import java.util.List; +import java.io.IOException; + +/** + * A file attribute view that provides a view of a file's user-defined + * attributes, sometimes known as <em>extended attributes</em>. User-defined + * file attributes are used to store metadata with a file that is not meaningful + * to the file system. It is primarily intended for file system implementations + * that support such a capability directly but may be emulated. The details of + * such emulation are highly implementation specific and therefore not specified. + * + * <p> This {@code FileAttributeView} provides a view of a file's user-defined + * attributes as a set of name/value pairs, where the attribute name is + * represented by a {@code String}. An implementation may require to encode and + * decode from the platform or file system representation when accessing the + * attribute. The value has opaque content. This attribute view defines the + * {@link #read read} and {@link #write write} methods to read the value into + * or write from a {@link ByteBuffer}. This {@code FileAttributeView} is not + * intended for use where the size of an attribute value is larger than {@link + * Integer#MAX_VALUE}. + * + * <p> User-defined attributes may be used in some implementations to store + * security related attributes so consequently, in the case of the default + * provider at least, all methods that access user-defined attributes require the + * {@code RuntimePermission("accessUserDefinedAttributes")} permission when a + * security manager is installed. + * + * <p> The {@link java.nio.file.FileStore#supportsFileAttributeView + * supportsFileAttributeView} method may be used to test if a specific {@link + * java.nio.file.FileStore FileStore} supports the storage of user-defined + * attributes. + * + * <p> Where dynamic access to file attributes is required, the {@link + * #getAttribute getAttribute} or {@link #readAttributes(String,String[]) + * readAttributes(String,String[])} methods may be used to read the attribute + * value. The attribute value is returned as a byte array (byte[]). The {@link + * #setAttribute setAttribute} method may be used to write the value of a + * user-defined attribute from a buffer (as if by invoking the {@link #write + * write} method), or byte array (byte[]). + * + * @since 1.7 + */ + +public interface UserDefinedFileAttributeView + extends FileAttributeView +{ + /** + * Returns the name of this attribute view. Attribute views of this type + * have the name {@code "xattr"}. + */ + @Override + String name(); + + /** + * Returns a list containing the names of the user-defined attributes. + * + * @return An unmodifiable list continaing the names of the file's + * user-defined + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link + * RuntimePermission}<tt>("accessUserDefinedAttributes")</tt> + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + */ + List<String> list() throws IOException; + + /** + * Returns the size of the value of a user-defined attribute. + * + * @param name + * The attribute name + * + * @return The size of the attribute value, in bytes. + * + * @throws ArithmeticException + * If the size of the attribute is larger than {@link Integer#MAX_VALUE} + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link + * RuntimePermission}<tt>("accessUserDefinedAttributes")</tt> + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + */ + int size(String name) throws IOException; + + /** + * Read the value of a user-defined attribute into a buffer. + * + * <p> This method reads the value of the attribute into the given buffer + * as a sequence of bytes, failing if the number of bytes remaining in + * the buffer is insufficient to read the complete attribute value. The + * number of bytes transferred into the buffer is {@code n}, where {@code n} + * is the size of the attribute value. The first byte in the sequence is at + * index {@code p} and the last byte is at index {@code p + n - 1}, where + * {@code p} is the buffer's position. Upon return the buffer's position + * will be equal to {@code p + n}; its limit will not have changed. + * + * <p> <b>Usage Example:</b> + * Suppose we want to read a file's MIME type that is stored as a user-defined + * attribute with the name "{@code user.mimetype}". + * <pre> + * UserDefinedFileAttributeView view = file + * .getFileAttributeView(UserDefinedFileAttributeView.class); + * String name = "user.mimetype"; + * ByteBuffer buf = ByteBuffer.allocate(view.size(name)); + * view.read(name, buf); + * buf.flip(); + * String value = Charset.defaultCharset().decode(buf).toString(); + * </pre> + * + * @param name + * The attribute name + * @param dst + * The destination buffer + * + * @return The number of bytes read, possibly zero + * + * @throws IllegalArgumentException + * If the destination buffer is read-only + * @throws IOException + * If an I/O error occurs or there is insufficient space in the + * destination buffer for the attribute value + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link + * RuntimePermission}<tt>("accessUserDefinedAttributes")</tt> + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + * + * @see #size + */ + int read(String name, ByteBuffer dst) throws IOException; + + /** + * Writes the value of a user-defined attribute from a buffer. + * + * <p> This method writes the value of the attribute from a given buffer as + * a sequence of bytes. The size of the value to transfer is {@code r}, + * where {@code r} is the number of bytes remaining in the buffer, that is + * {@code src.remaining()}. The sequence of bytes is transferred from the + * buffer starting at index {@code p}, where {@code p} is the buffer's + * position. Upon return, the buffer's position will be equal to {@code + * p + n}, where {@code n} is the number of bytes transferred; its limit + * will not have changed. + * + * <p> If an attribute of the given name already exists then its value is + * replaced. If the attribute does not exist then it is created. If it + * implementation specific if a test to check for the existence of the + * attribute and the creation of attribute are atomic with repect to other + * file system activities. + * + * <p> Where there is insufficient space to store the attribute, or the + * attribute name or value exceed an implementation specific maximum size + * then an {@code IOException} is thrown. + * + * <p> <b>Usage Example:</b> + * Suppose we want to write a file's MIME type as a user-defined attribute: + * <pre> + * UserDefinedFileAttributeView view = file + * .getFileAttributeView(UserDefinedFileAttributeView.class); + * view.write("user.mimetype", Charset.defaultCharset().encode("text/html")); + * </pre> + * + * @param name + * The attribute name + * @param src + * The buffer containing the attribute value + * + * @return The number of bytes written, possibly zero + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link + * RuntimePermission}<tt>("accessUserDefinedAttributes")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + */ + int write(String name, ByteBuffer src) throws IOException; + + /** + * Deletes a user-defined attribute. + * + * @param name + * The attribute name + * + * @throws IOException + * If an I/O error occurs or the attribute does not exist + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link + * RuntimePermission}<tt>("accessUserDefinedAttributes")</tt> + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + */ + void delete(String name) throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/UserPrincipal.java b/jdk/src/share/classes/java/nio/file/attribute/UserPrincipal.java new file mode 100644 index 00000000000..edb04fc6f3b --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/UserPrincipal.java @@ -0,0 +1,54 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.security.Principal; + +/** + * A {@code Principal} representing an identity used to determine access rights + * to objects in a file system. + * + * <p> On many platforms and file systems an entity requires appropriate access + * rights or permissions in order to access objects in a file system. The + * access rights are generally performed by checking the identity of the entity. + * For example, on implementations that use Access Control Lists (ACLs) to + * enforce privilege separation then a file in the file system may have an + * associated ACL that determines the access rights of identities specified in + * the ACL. + * + * <p> A {@code UserPrincipal} object is an abstract representation of an + * identity. It has a {@link #getName() name} that is typically the username or + * account name that it represents. User principal objects may be obtained using + * a {@link UserPrincipalLookupService}, or returned by {@link + * FileAttributeView} implementations that provide access to identity related + * attributes. For example, the {@link AclFileAttributeView} and {@link + * PosixFileAttributeView} provide access to a file's {@link + * PosixFileAttributes#owner owner}. + * + * @since 1.7 + */ + +public interface UserPrincipal extends Principal { } diff --git a/jdk/src/share/classes/java/nio/file/attribute/UserPrincipalLookupService.java b/jdk/src/share/classes/java/nio/file/attribute/UserPrincipalLookupService.java new file mode 100644 index 00000000000..ba74882ce67 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/UserPrincipalLookupService.java @@ -0,0 +1,104 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.io.IOException; + +/** + * An object to lookup user and group principals by name. A {@link UserPrincipal} + * represents an identity that may be used to determine access rights to objects + * in a file system. A {@link GroupPrincipal} represents a <em>group identity</em>. + * A {@code UserPrincipalLookupService} defines methods to lookup identities by + * name or group name (which are typically user or account names). Whether names + * and group names are case sensitive or not depends on the implementation. + * The exact definition of a group is implementation specific but typically a + * group represents an identity created for administrative purposes so as to + * determine the access rights for the members of the group. In particular it is + * implementation specific if the <em>namespace</em> for names and groups is the + * same or is distinct. To ensure consistent and correct behavior across + * platforms it is recommended that this API be used as if the namespaces are + * distinct. In other words, the {@link #lookupPrincipalByName + * lookupPrincipalByName} should be used to lookup users, and {@link + * #lookupPrincipalByGroupName lookupPrincipalByGroupName} should be used to + * lookup groups. + * + * @since 1.7 + * + * @see java.nio.file.FileSystem#getUserPrincipalLookupService + */ + +public abstract class UserPrincipalLookupService { + + /** + * Initializes a new instance of this class. + */ + protected UserPrincipalLookupService() { + } + + /** + * Lookup a user principal by name. + * + * @param name + * the string representation of the user principal to lookup + * + * @return a user principal + * + * @throws UserPrincipalNotFoundException + * the principal does not exist + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it checks {@link RuntimePermission}<tt>("lookupUserInformation")</tt> + */ + public abstract UserPrincipal lookupPrincipalByName(String name) + throws IOException; + + /** + * Lookup a group principal by group name. + * + * <p> Where an implementation does not support any notion of group then + * this method always throws {@link UserPrincipalNotFoundException}. Where + * the namespace for user accounts and groups is the same, then this method + * is identical to invoking {@link #lookupPrincipalByName + * lookupPrincipalByName}. + * + * @param group + * the string representation of the group to lookup + * + * @return a user principal + * + * @throws UserPrincipalNotFoundException + * the principal does not exist or is not a group + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it checks {@link RuntimePermission}<tt>("lookupUserInformation")</tt> + */ + public abstract GroupPrincipal lookupPrincipalByGroupName(String group) + throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/UserPrincipalNotFoundException.java b/jdk/src/share/classes/java/nio/file/attribute/UserPrincipalNotFoundException.java new file mode 100644 index 00000000000..94cc88ba20a --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/UserPrincipalNotFoundException.java @@ -0,0 +1,64 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.attribute; + +import java.io.IOException; + +/** + * Checked exception thrown when a lookup of {@link UserPrincipal} fails because + * the principal does not exist. + * + * @since 1.7 + */ + +public class UserPrincipalNotFoundException + extends IOException +{ + static final long serialVersionUID = -5369283889045833024L; + + private final String name; + + /** + * Constructs an instance of this class. + * + * @param name + * the principal name; may be {@code null} + */ + public UserPrincipalNotFoundException(String name) { + super(); + this.name = name; + } + + /** + * Returns the user principal name if this exception was created with the + * user principal name that was not found, otherwise <tt>null</tt>. + * + * @return the user principal name or {@code null} + */ + public String getName() { + return name; + } +} diff --git a/jdk/src/share/classes/java/nio/file/attribute/package-info.java b/jdk/src/share/classes/java/nio/file/attribute/package-info.java new file mode 100644 index 00000000000..c5301b1f840 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/attribute/package-info.java @@ -0,0 +1,119 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Interfaces and classes providing access to file and file system attributes. + * + * <blockquote><table cellspacing=1 cellpadding=0 summary="Attribute views"> + * <tr><th><p align="left">Attribute views</p></th><th><p align="left">Description</p></th></tr> + * <tr><td valign=top><tt><i>{@link java.nio.file.attribute.AttributeView}</i></tt></td> + * <td>Can read or update non-opaque values associated with objects in a file system</td></tr> + * <tr><td valign=top><tt>  <i>{@link java.nio.file.attribute.FileAttributeView}</i></tt></td> + * <td>Can read or update file attributes</td></tr> + * <tr><td valign=top><tt>    <i>{@link java.nio.file.attribute.BasicFileAttributeView}  </i></tt></td> + * <td>Can read or update a basic set of file attributes</td></tr> + * <tr><td valign=top><tt>      <i>{@link java.nio.file.attribute.PosixFileAttributeView}  </i></tt></td> + * <td>Can read or update POSIX defined file attributes</td></tr> + * <tr><td valign=top><tt>      <i>{@link java.nio.file.attribute.DosFileAttributeView}  </i></tt></td> + * <td>Can read or update FAT file attributes</td></tr> + * <tr><td valign=top><tt>    <i>{@link java.nio.file.attribute.FileOwnerAttributeView}  </i></tt></td> + * <td>Can read or update the owner of a file</td></tr> + * <tr><td valign=top><tt>     <i>{@link java.nio.file.attribute.AclFileAttributeView}  </i></tt></td> + * <td>Can read or update Access Control Lists</td></tr> + * <tr><td valign=top><tt>    <i>{@link java.nio.file.attribute.UserDefinedFileAttributeView}  </i></tt></td> + * <td>Can read or update user-defined file attributes</td></tr> + * <tr><td valign=top><tt>  <i>{@link java.nio.file.attribute.FileStoreAttributeView}</i></tt></td> + * <td>Can read or update file system attributes</td></tr> + * <tr><td valign=top><tt>    <i>{@link java.nio.file.attribute.FileStoreSpaceAttributeView}  </i></tt></td> + * <td>Can read file system <em>space usage</em> related attributes</td></tr> + * </table></blockquote> + * + * <p> An attribute view provides a read-only or updatable view of the non-opaque + * values, or <em>metadata</em>, associated with objects in a file system. + * The {@link java.nio.file.attribute.FileAttributeView} interface is + * extended by several other interfaces that that views to specific sets of file + * attributes. {@code FileAttributeViews} are selected by invoking the {@link + * java.nio.file.FileRef#getFileAttributeView} method with a + * <em>type-token</em> to identify the required view. Views can also be identified + * by name. The {@link java.nio.file.attribute.FileStoreAttributeView} interface + * provides access to file store attributes. A {@code FileStoreAttributeView} of + * a given type is obtained by invoking the {@link + * java.nio.file.FileStore#getFileStoreAttributeView} method. + * + * <p> The {@link java.nio.file.attribute.BasicFileAttributeView} + * class defines methods to read and update a <em>basic</em> set of file + * attributes that are common to many file systems. + * + * <p> The {@link java.nio.file.attribute.PosixFileAttributeView} + * interface extends {@code BasicFileAttributeView} by defining methods + * to access the file attributes commonly used by file systems and operating systems + * that implement the Portable Operating System Interface (POSIX) family of + * standards. + * + * <p> The {@link java.nio.file.attribute.DosFileAttributeView} + * class extends {@code BasicFileAttributeView} by defining methods to + * access the legacy "DOS" file attributes supported on file systems such as File + * Allocation Tabl (FAT), commonly used in consumer devices. + * + * <p> The {@link java.nio.file.attribute.AclFileAttributeView} + * class defines methods to read and write the Access Control List (ACL) + * file attribute. The ACL model used by this file attribute view is based + * on the model defined by <a href="http://www.ietf.org/rfc/rfc3530.txt"> + * <i>RFC 3530: Network File System (NFS) version 4 Protocol</i></a>. + * + * <p> The {@link java.nio.file.attribute.FileStoreSpaceAttributeView} class + * defines methods to read file system space usage related attributes of a file system. + * + * <p> The {@link java.nio.file.attribute.Attributes} utility class defines + * static methods to access file or file system attribute using the above + * attribute views. + * + * <p> In addition to attribute views, this package also defines classes and + * interfaces that are used when accessing attributes: + * + * <ul> + * + * <p><li> The {@link java.nio.file.attribute.UserPrincipal} and + * {@link java.nio.file.attribute.GroupPrincipal} interfaces represent an + * identity or group identity. </li> + * + * <p><li> The {@link java.nio.file.attribute.UserPrincipalLookupService} + * interface defines methods to lookup user or group principals. </li> + * + * <p><li> The {@link java.nio.file.attribute.Attribute} interface + * represents the value of an attribute for cases where the attribute value is + * require to be set atomically when creating an object in the file system. </li> + * + * </ul> + * + * + * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor + * or method in any class or interface in this package will cause a {@link + * java.lang.NullPointerException NullPointerException} to be thrown. + * + * @since 1.7 + */ + +package java.nio.file.attribute; diff --git a/jdk/src/share/classes/java/nio/file/package-info.java b/jdk/src/share/classes/java/nio/file/package-info.java new file mode 100644 index 00000000000..3623ebe12cd --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/package-info.java @@ -0,0 +1,116 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Defines interfaces and classes for the Java virtual machine to access files, + * file attributes, and file systems. + * + * <p> The java.nio.file package defines classes to access files and file + * systems. The API to access file and file system attributes is defined in the + * {@link java.nio.file.attribute} package. The {@link java.nio.file.spi} + * package is used by service provider implementors wishing to extend the + * platform default provider, or to construct other provider implementations. + * + * <a name="links"><h3>Symbolic Links</h3></a> + * Many operating systems and file systems support for <em>symbolic links</em>. + * A symbolic link is a special file that serves as a reference to another file. + * For the most part, symbolic links are transparent to applications and + * operations on symbolic links are automatically redirected to the <em>target</em> + * of the link. Exceptions to this are when a symbolic link is deleted or + * renamed/moved in which case the link is deleted or removed rather than the + * target of the link. This package includes support for symbolic links where + * implementations provide these semantics. File systems may support other types + * that are semantically close but support for these other types of links is + * not included in this package. + * + * <a name="interop"><h3>Interoperability</h3></a> + * The {@link java.io.File} class defines the {@link java.io.File#toPath + * toPath} method to construct a {@link java.nio.file.Path} by converting + * the abstract path represented by the {@code java.io.File} object. The resulting + * {@code Path} can be used to operate on the same file as the {@code File} + * object. The {@code Path} specification provides further information + * on the <a href="Path.html#interop">interoperability</a> between {@code Path} + * and {@code java.io.File} objects. + * + * <h3>Visibility</h3> + * The view of the files and file system provided by classes in this package are + * guaranteed to be consistent with other views provided by other instances in the + * same Java virtual machine. The view may or may not, however, be consistent with + * the view of the file system as seen by other concurrently running programs due + * to caching performed by the underlying operating system and delays induced by + * network-filesystem protocols. This is true regardless of the language in which + * these other programs are written, and whether they are running on the same machine + * or on some other machine. The exact nature of any such inconsistencies are + * system-dependent and are therefore unspecified. + * + * <a name="integrity"><h3>Synchronized I/O File Integrity</h3></a> + * The {@link java.nio.file.StandardOpenOption#SYNC SYNC} and {@link + * java.nio.file.StandardOpenOption#DSYNC DSYNC} options are used when opening a file + * to require that updates to the file are written synchronously to the underlying + * storage device. In the case of the default provider, and the file resides on + * a local storage device, and the {@link java.nio.channels.SeekableByteChannel + * seekable} channel is connected to a file that was opened with one of these + * options, then an invocation of the {@link + * java.nio.channels.WritableByteChannel#write(java.nio.ByteBuffer) write} + * method is only guaranteed to return when all changes made to the file + * by that invocation have been written to the device. These options are useful + * for ensuring that critical information is not lost in the event of a system + * crash. If the file does not reside on a local device then no such guarantee + * is made. Whether this guarantee is possible with other {@link + * java.nio.file.spi.FileSystemProvider provider} implementations is provider + * specific. + * + * <h3>General Exceptions</h3> + * Unless otherwise noted, passing a {@code null} argument to a constructor + * or method of any class or interface in this package will cause a {@link + * java.lang.NullPointerException NullPointerException} to be thrown. Additionally, + * invoking a method with a collection containing a {@code null} element will + * cause a {@code NullPointerException}, unless otherwise specified. + * + * <p> Unless otherwise noted, methods that attempt to access the file system + * will throw {@link java.nio.file.ClosedFileSystemException} when invoked on + * objects associated with a {@link java.nio.file.FileSystem} that has been + * {@link java.nio.file.FileSystem#close closed}. Additionally, any methods + * that attempt write access to a file system will throw {@link + * java.nio.file.ReadOnlyFileSystemException} when invoked on an object associated + * with a {@link java.nio.file.FileSystem} that only provides read-only access. + * + * <p> Unless otherwise noted, invoking a method of any class or interface in + * this package created by one {@link java.nio.file.spi.FileSystemProvider + * provider} with a parameter that is an object created by another provider, + * will throw {@link java.nio.file.ProviderMismatchException}. + * + * <h3>Optional Specific Exceptions</h3> + * Most of the methods defined by classes in this package that access the + * file system specify that {@link java.io.IOException} be thrown when an I/O + * error occurs. In some cases, these methods define specific I/O exceptions + * for common cases. These exceptions, noted as <i>optional specific exceptions</i>, + * are thrown by the implementation where it can detect the specific error. + * Where the specific error cannot be detected then the more general {@code + * IOException} is thrown. + * + * @since 1.7 + */ +package java.nio.file; diff --git a/jdk/src/share/classes/java/nio/file/spi/AbstractPath.java b/jdk/src/share/classes/java/nio/file/spi/AbstractPath.java new file mode 100644 index 00000000000..133411e3bf8 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/spi/AbstractPath.java @@ -0,0 +1,568 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.spi; + +import java.nio.file.*; +import static java.nio.file.StandardOpenOption.*; +import java.nio.file.attribute.*; +import java.nio.channels.*; +import java.nio.ByteBuffer; +import java.io.*; +import java.util.*; + +/** + * Base implementation class for a {@code Path}. + * + * <p> This class is intended to be extended by provider implementors. It + * implements, or provides default implementations for several of the methods + * defined by the {@code Path} class. It implements the {@link #copyTo copyTo} + * and {@link #moveTo moveTo} methods for the case that the source and target + * are not associated with the same provider. + * + * @since 1.7 + */ + +public abstract class AbstractPath extends Path { + + /** + * Initializes a new instance of this class. + */ + protected AbstractPath() { } + + /** + * Deletes the file referenced by this object. + * + * <p> This method invokes the {@link #delete(boolean) delete(boolean)} + * method with a parameter of {@code true}. It may be overridden where + * required. + * + * @throws NoSuchFileException {@inheritDoc} + * @throws DirectoryNotEmptyException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public void delete() throws IOException { + delete(true); + } + + /** + * Creates a new and empty file, failing if the file already exists. + * + * <p> This method invokes the {@link #newByteChannel(Set,FileAttribute[]) + * newByteChannel(Set,FileAttribute...)} method to create the file. It may be + * overridden where required. + * + * @throws IllegalArgumentException {@inheritDoc} + * @throws FileAlreadyExistsException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public Path createFile(FileAttribute<?>... attrs) + throws IOException + { + EnumSet<StandardOpenOption> options = EnumSet.of(CREATE_NEW, WRITE); + SeekableByteChannel sbc = newByteChannel(options, attrs); + try { + sbc.close(); + } catch (IOException x) { + // ignore + } + return this; + } + + /** + * Opens or creates a file, returning a seekable byte channel to access the + * file. + * + * <p> This method invokes the {@link #newByteChannel(Set,FileAttribute[]) + * newByteChannel(Set,FileAttribute...)} method to open or create the file. + * It may be overridden where required. + * + * @throws IllegalArgumentException {@inheritDoc} + * @throws FileAlreadyExistsException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public SeekableByteChannel newByteChannel(OpenOption... options) + throws IOException + { + Set<OpenOption> set = new HashSet<OpenOption>(options.length); + Collections.addAll(set, options); + return newByteChannel(set); + } + + /** + * Opens the file located by this path for reading, returning an input + * stream to read bytes from the file. + * + * <p> This method returns an {@code InputStream} that is constructed by + * invoking the {@link java.nio.channels.Channels#newInputStream + * Channels.newInputStream} method. It may be overridden where a more + * efficient implementation is available. + * + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public InputStream newInputStream() throws IOException { + return Channels.newInputStream(newByteChannel()); + } + + // opts must be modifiable + private OutputStream implNewOutputStream(Set<OpenOption> opts, + FileAttribute<?>... attrs) + throws IOException + { + if (opts.isEmpty()) { + opts.add(CREATE); + opts.add(TRUNCATE_EXISTING); + } else { + if (opts.contains(READ)) + throw new IllegalArgumentException("READ not allowed"); + } + opts.add(WRITE); + return Channels.newOutputStream(newByteChannel(opts, attrs)); + } + + /** + * Opens or creates the file located by this path for writing, returning an + * output stream to write bytes to the file. + * + * <p> This method returns an {@code OutputStream} that is constructed by + * invoking the {@link java.nio.channels.Channels#newOutputStream + * Channels.newOutputStream} method. It may be overridden where a more + * efficient implementation is available. + * + * @throws IllegalArgumentException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public OutputStream newOutputStream(OpenOption... options) throws IOException { + int len = options.length; + Set<OpenOption> opts = new HashSet<OpenOption>(len + 3); + if (len > 0) { + for (OpenOption opt: options) { + opts.add(opt); + } + } + return implNewOutputStream(opts); + } + + /** + * Opens or creates the file located by this path for writing, returning an + * output stream to write bytes to the file. + * + * <p> This method returns an {@code OutputStream} that is constructed by + * invoking the {@link java.nio.channels.Channels#newOutputStream + * Channels.newOutputStream} method. It may be overridden where a more + * efficient implementation is available. + * + * @throws IllegalArgumentException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public OutputStream newOutputStream(Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + Set<OpenOption> opts = new HashSet<OpenOption>(options); + return implNewOutputStream(opts, attrs); + } + + /** + * Opens the directory referenced by this object, returning a {@code + * DirectoryStream} to iterate over all entries in the directory. + * + * <p> This method invokes the {@link + * #newDirectoryStream(java.nio.file.DirectoryStream.Filter) + * newDirectoryStream(Filter)} method with a filter that accept all entries. + * It may be overridden where required. + * + * @throws NotDirectoryException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public DirectoryStream<Path> newDirectoryStream() throws IOException { + return newDirectoryStream(acceptAllFilter); + } + private static final DirectoryStream.Filter<Path> acceptAllFilter = + new DirectoryStream.Filter<Path>() { + @Override public boolean accept(Path entry) { return true; } + }; + + /** + * Opens the directory referenced by this object, returning a {@code + * DirectoryStream} to iterate over the entries in the directory. The + * entries are filtered by matching the {@code String} representation of + * their file names against a given pattern. + * + * <p> This method constructs a {@link PathMatcher} by invoking the + * file system's {@link java.nio.file.FileSystem#getPathMatcher + * getPathMatcher} method. This method may be overridden where a more + * efficient implementation is available. + * + * @throws java.util.regex.PatternSyntaxException {@inheritDoc} + * @throws UnsupportedOperationException {@inheritDoc} + * @throws NotDirectoryException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public DirectoryStream<Path> newDirectoryStream(String glob) + throws IOException + { + // avoid creating a matcher if all entries are required. + if (glob.equals("*")) + return newDirectoryStream(); + + // create a matcher and return a filter that uses it. + final PathMatcher matcher = getFileSystem().getPathMatcher("glob:" + glob); + DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() { + @Override + public boolean accept(Path entry) { + return matcher.matches(entry.getName()); + } + }; + return newDirectoryStream(filter); + } + + /** + * Tests whether the file located by this path exists. + * + * <p> This method invokes the {@link #checkAccess checkAccess} method to + * check if the file exists. It may be overridden where a more efficient + * implementation is available. + */ + @Override + public boolean exists() { + try { + checkAccess(); + return true; + } catch (IOException x) { + // unable to determine if file exists + } + return false; + } + + /** + * Tests whether the file located by this path does not exist. + * + * <p> This method invokes the {@link #checkAccess checkAccess} method to + * check if the file exists. It may be overridden where a more efficient + * implementation is available. + */ + @Override + public boolean notExists() { + try { + checkAccess(); + return false; + } catch (NoSuchFileException x) { + // file confirmed not to exist + return true; + } catch (IOException x) { + return false; + } + } + + /** + * Registers the file located by this path with a watch service. + * + * <p> This method invokes the {@link #register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier[]) + * register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier...)} + * method to register the file. It may be overridden where required. + */ + @Override + public WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) + throws IOException + { + return register(watcher, events, NO_MODIFIERS); + } + private static final WatchEvent.Modifier[] NO_MODIFIERS = new WatchEvent.Modifier[0]; + + /** + * Copy the file located by this path to a target location. + * + * <p> This method is invoked by the {@link #copyTo copyTo} method for + * the case that this {@code Path} and the target {@code Path} are + * associated with the same provider. + * + * @param target + * The target location + * @param options + * Options specifying how the copy should be done + * + * @throws IllegalArgumentException + * If an invalid option is specified + * @throws FileAlreadyExistsException + * The target file exists and cannot be replaced because the + * {@code REPLACE_EXISTING} option is not specified, or the target + * file is a non-empty directory <i>(optional specific exception)</i> + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the source file, the + * {@link SecurityManager#checkWrite(String) checkWrite} is invoked + * to check write access to the target file. If a symbolic link is + * copied the security manager is invoked to check {@link + * LinkPermission}{@code ("symbolic")}. + */ + protected abstract void implCopyTo(Path target, CopyOption... options) + throws IOException; + + /** + * Move the file located by this path to a target location. + * + * <p> This method is invoked by the {@link #moveTo moveTo} method for + * the case that this {@code Path} and the target {@code Path} are + * associated with the same provider. + * + * @param target + * The target location + * @param options + * Options specifying how the move should be done + * + * @throws IllegalArgumentException + * If an invalid option is specified + * @throws FileAlreadyExistsException + * The target file exists and cannot be replaced because the + * {@code REPLACE_EXISTING} option is not specified, or the target + * file is a non-empty directory + * @throws AtomicMoveNotSupportedException + * The options array contains the {@code ATOMIC_MOVE} option but + * the file cannot be moved as an atomic file system operation. + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to both the source and + * target file. + */ + protected abstract void implMoveTo(Path target, CopyOption... options) + throws IOException; + + /** + * Copy the file located by this path to a target location. + * + * <p> If this path is associated with the same {@link FileSystemProvider + * provider} as the {@code target} then the {@link #implCopyTo implCopyTo} + * method is invoked to copy the file. Otherwise, this method attempts to + * copy the file to the target location in a manner that may be less + * efficient than would be the case that target is associated with the same + * provider as this path. + * + * @throws IllegalArgumentException {@inheritDoc} + * @throws FileAlreadyExistsException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public final Path copyTo(Path target, CopyOption... options) + throws IOException + { + if ((getFileSystem().provider() == target.getFileSystem().provider())) { + implCopyTo(target, options); + } else { + xProviderCopyTo(target, options); + } + return target; + } + + /** + * Move or rename the file located by this path to a target location. + * + * <p> If this path is associated with the same {@link FileSystemProvider + * provider} as the {@code target} then the {@link #implCopyTo implMoveTo} + * method is invoked to move the file. Otherwise, this method attempts to + * copy the file to the target location and delete the source file. This + * implementation may be less efficient than would be the case that + * target is associated with the same provider as this path. + * + * @throws IllegalArgumentException {@inheritDoc} + * @throws FileAlreadyExistsException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ + @Override + public final Path moveTo(Path target, CopyOption... options) + throws IOException + { + if ((getFileSystem().provider() == target.getFileSystem().provider())) { + implMoveTo(target, options); + } else { + // different providers so copy + delete + xProviderCopyTo(target, convertMoveToCopyOptions(options)); + delete(false); + } + return target; + } + + /** + * Converts the given array of options for moving a file to options suitable + * for copying the file when a move is implemented as copy + delete. + */ + private static CopyOption[] convertMoveToCopyOptions(CopyOption... options) + throws AtomicMoveNotSupportedException + { + int len = options.length; + CopyOption[] newOptions = new CopyOption[len+2]; + for (int i=0; i<len; i++) { + CopyOption option = options[i]; + if (option == StandardCopyOption.ATOMIC_MOVE) { + throw new AtomicMoveNotSupportedException(null, null, + "Atomic move between providers is not supported"); + } + newOptions[i] = option; + } + newOptions[len] = LinkOption.NOFOLLOW_LINKS; + newOptions[len+1] = StandardCopyOption.COPY_ATTRIBUTES; + return newOptions; + } + + /** + * Parses the arguments for a file copy operation. + */ + private static class CopyOptions { + boolean replaceExisting = false; + boolean copyAttributes = false; + boolean followLinks = true; + + private CopyOptions() { } + + static CopyOptions parse(CopyOption... options) { + CopyOptions result = new CopyOptions(); + for (CopyOption option: options) { + if (option == StandardCopyOption.REPLACE_EXISTING) { + result.replaceExisting = true; + continue; + } + if (option == LinkOption.NOFOLLOW_LINKS) { + result.followLinks = false; + continue; + } + if (option == StandardCopyOption.COPY_ATTRIBUTES) { + result.copyAttributes = true; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new IllegalArgumentException("'" + option + + "' is not a valid copy option"); + } + return result; + } + } + + /** + * Simple cross-provider copy where the target is a Path. + */ + private void xProviderCopyTo(Path target, CopyOption... options) + throws IOException + { + CopyOptions opts = CopyOptions.parse(options); + LinkOption[] linkOptions = (opts.followLinks) ? new LinkOption[0] : + new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; + + // attributes of source file + BasicFileAttributes attrs = Attributes + .readBasicFileAttributes(this, linkOptions); + if (attrs.isSymbolicLink()) + throw new IOException("Copying of symbolic links not supported"); + + // delete target file + if (opts.replaceExisting) + target.delete(false); + + // create directory or file + if (attrs.isDirectory()) { + target.createDirectory(); + } else { + xProviderCopyRegularFileTo(target); + } + + // copy basic attributes to target + if (opts.copyAttributes) { + BasicFileAttributeView view = target + .getFileAttributeView(BasicFileAttributeView.class, linkOptions); + try { + view.setTimes(attrs.lastModifiedTime(), + attrs.lastAccessTime(), + attrs.creationTime(), + attrs.resolution()); + } catch (IOException x) { + // rollback + try { + target.delete(false); + } catch (IOException ignore) { } + throw x; + } + } + } + + + /** + * Simple copy of regular file to a target file that exists. + */ + private void xProviderCopyRegularFileTo(FileRef target) + throws IOException + { + ReadableByteChannel rbc = newByteChannel(); + try { + // open target file for writing + SeekableByteChannel sbc = target.newByteChannel(CREATE, WRITE); + + // simple copy loop + try { + ByteBuffer buf = ByteBuffer.wrap(new byte[8192]); + int n = 0; + for (;;) { + n = rbc.read(buf); + if (n < 0) + break; + assert n > 0; + buf.flip(); + while (buf.hasRemaining()) { + sbc.write(buf); + } + buf.rewind(); + } + + } finally { + sbc.close(); + } + } finally { + rbc.close(); + } + } +} diff --git a/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java b/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java new file mode 100644 index 00000000000..6b79381bad4 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java @@ -0,0 +1,434 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.spi; + +import java.nio.file.*; +import java.nio.file.attribute.FileAttribute; +import java.nio.channels.*; +import java.net.URI; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.io.IOException; + +/** + * Service-provider class for file systems. + * + * <p> A file system provider is a concrete implementation of this class that + * implements the abstract methods defined by this class. A provider is + * identified by a {@code URI} {@link #getScheme() scheme}. The default provider + * is identified by the URI scheme "file". It creates the {@link FileSystem} that + * provides access to the file systems accessible to the Java virtual machine. + * The {@link FileSystems} class defines how file system providers are located + * and loaded. The default provider is typically a system-default provider but + * may be overridden if the system property {@code + * java.nio.file.spi.DefaultFileSystemProvider} is set. In that case, the + * provider has a one argument constructor whose formal parameter type is {@code + * FileSystemProvider}. All other providers have a zero argument constructor + * that initializes the provider. + * + * <p> A provider is a factory for one or more {@link FileSystem} instances. Each + * file system is identified by a {@code URI} where the URI's scheme matches + * the provider's {@link #getScheme scheme}. The default file system, for example, + * is identified by the URI {@code "file:///"}. A memory-based file system, + * for example, may be identified by a URI such as {@code "memory:///?name=logfs"}. + * The {@link #newFileSystem newFileSystem} method may be used to create a file + * system, and the {@link #getFileSystem getFileSystem} method may be used to + * obtain a reference to an existing file system created by the provider. Where + * a provider is the factory for a single file system then it is provider dependent + * if the file system is created when the provider is initialized, or later when + * the {@code newFileSystem} method is invoked. In the case of the default + * provider, the {@code FileSystem} is created when the provider is initialized. + * + * <p> In addition to file systems, a provider is also a factory for {@link + * FileChannel} and {@link AsynchronousFileChannel} channels. The {@link + * #newFileChannel newFileChannel} and {@link #newAsynchronousFileChannel + * AsynchronousFileChannel} methods are defined to open or create files, returning + * a channel to access the file. These methods are invoked by static factory + * methods defined in the {@link java.nio.channels} package. + * + * <p> All of the methods in this class are safe for use by multiple concurrent + * threads. + * + * @since 1.7 + */ + +public abstract class FileSystemProvider { + // lock using when loading providers + private static final Object lock = new Object(); + + // installed providers + private static volatile List<FileSystemProvider> installedProviders; + + // used to avoid recursive loading of instaled providers + private static boolean loadingProviders = false; + + private static Void checkPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("fileSystemProvider")); + return null; + } + private FileSystemProvider(Void ignore) { } + + /** + * Initializes a new instance of this class. + * + * <p> During construction a provider may safely access files associated + * with the default provider but care needs to be taken to avoid circular + * loading of other installed providers. If circular loading of installed + * providers is detected then an unspecified error is thrown. + * + * @throws SecurityException + * If a security manager has been installed and it denies + * {@link RuntimePermission}<tt>("fileSystemProvider")</tt> + */ + protected FileSystemProvider() { + this(checkPermission()); + } + + // loads all installed providers + private static List<FileSystemProvider> loadInstalledProviders() { + List<FileSystemProvider> list = new ArrayList<FileSystemProvider>(); + + ServiceLoader<FileSystemProvider> sl = ServiceLoader + .load(FileSystemProvider.class, ClassLoader.getSystemClassLoader()); + + // ServiceConfigurationError may be throw here + for (FileSystemProvider provider: sl) { + String scheme = provider.getScheme(); + + // add to list if the provider is not "file" and isn't a duplicate + if (!scheme.equalsIgnoreCase("file")) { + boolean found = false; + for (FileSystemProvider p: list) { + if (p.getScheme().equalsIgnoreCase(scheme)) { + found = true; + break; + } + } + if (!found) { + list.add(provider); + } + } + } + return list; + } + + /** + * Returns a list of the installed file system providers. + * + * <p> The first invocation of this method causes the default provider to be + * initialized (if not already initialized) and loads any other installed + * providers as described by the {@link FileSystems} class. + * + * @return An unmodifiable list of the installed file system providers. The + * list contains at least one element, that is the default file + * system provider + * + * @throws ServiceConfigurationError + * When an error occurs while loading a service provider + */ + public static List<FileSystemProvider> installedProviders() { + if (installedProviders == null) { + // ensure default provider is initialized + FileSystemProvider defaultProvider = FileSystems.getDefault().provider(); + + synchronized (lock) { + if (installedProviders == null) { + if (loadingProviders) { + throw new Error("Circular loading of installed providers detected"); + } + loadingProviders = true; + + List<FileSystemProvider> list = AccessController + .doPrivileged(new PrivilegedAction<List<FileSystemProvider>>() { + @Override + public List<FileSystemProvider> run() { + return loadInstalledProviders(); + }}); + + // insert the default provider at the start of the list + list.add(0, defaultProvider); + + installedProviders = Collections.unmodifiableList(list); + } + } + } + return installedProviders; + } + + /** + * Returns the URI scheme that identifies this provider. + * + * @return The URI scheme + */ + public abstract String getScheme(); + + /** + * Constructs a new {@code FileSystem} object identified by a URI. This + * method is invoked by the {@link FileSystems#newFileSystem(URI,Map)} + * method to open a new file system identified by a URI. + * + * <p> The {@code uri} parameter is an absolute, hierarchical URI, with a + * scheme equal (without regard to case) to the scheme supported by this + * provider. The exact form of the URI is highly provider dependent. The + * {@code env} parameter is a map of provider specific properties to configure + * the file system. + * + * <p> This method throws {@link FileSystemAlreadyExistsException} if the + * file system already exists because it was previously created by an + * invocation of this method. Once a file system is {@link FileSystem#close + * closed} it is provider-dependent if the provider allows a new file system + * to be created with the same URI as a file system it previously created. + * + * @param uri + * URI reference + * @param env + * A map of provider specific properties to configure the file system; + * may be empty + * + * @return A new file system + * + * @throws IllegalArgumentException + * If the pre-conditions for the {@code uri} parameter aren't met, + * or the {@code env} parameter does not contain properties required + * by the provider, or a property value is invalid + * @throws IOException + * An I/O error occurs creating the file system + * @throws SecurityException + * If a security manager is installed and it denies an unspecified + * permission required by the file system provider implementation + * @throws FileSystemAlreadyExistsException + * If the file system has already been created + */ + public abstract FileSystem newFileSystem(URI uri, Map<String,?> env) + throws IOException; + + /** + * Returns an existing {@code FileSystem} created by this provider. + * + * <p> This method returns a reference to a {@code FileSystem} that was + * created by invoking the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)} + * method. File systems created the {@link #newFileSystem(FileRef,Map) + * newFileSystem(FileRef,Map)} method are not returned by this method. + * The file system is identified by its {@code URI}. Its exact form + * is highly provider dependent. In the case of the default provider the URI's + * path component is {@code "/"} and the authority, query and fragment components + * are undefined (Undefined components are represented by {@code null}). + * + * <p> Once a file system created by this provider is {@link FileSystem#close + * closed} it is provider-dependent if this method returns a reference to + * the closed file system or throws {@link FileSystemNotFoundException}. + * If the provider allows a new file system to be created with the same URI + * as a file system it previously created then this method throws the + * exception if invoked after the file system is closed (and before a new + * instance is created by the {@link #newFileSystem newFileSystem} method). + * + * <p> If a security manager is installed then a provider implementation + * may require to check a permission before returning a reference to an + * existing file system. In the case of the {@link FileSystems#getDefault + * default} file system, no permission check is required. + * + * @param uri + * URI reference + * + * @return The file system + * + * @throws IllegalArgumentException + * If the pre-conditions for the {@code uri} parameter aren't met + * @throws FileSystemNotFoundException + * If the file system does not exist + * @throws SecurityException + * If a security manager is installed and it denies an unspecified + * permission. + */ + public abstract FileSystem getFileSystem(URI uri); + + /** + * Return a {@code Path} object by converting the given {@link URI}. + * + * <p> The exact form of the URI is file system provider dependent. In the + * case of the default provider, the URI scheme is {@code "file"} and the + * given URI has a non-empty path component, and undefined query, and + * fragment components. The resulting {@code Path} is associated with the + * default {@link FileSystems#getDefault default} {@code FileSystem}. + * + * <p> If a security manager is installed then a provider implementation + * may require to check a permission. In the case of the {@link + * FileSystems#getDefault default} file system, no permission check is + * required. + * + * @param uri + * The URI to convert + * + * @throws IllegalArgumentException + * If the URI scheme does not identify this provider or other + * preconditions on the uri parameter do not hold + * @throws FileSystemNotFoundException + * The file system, identified by the URI, does not exist + * @throws SecurityException + * If a security manager is installed and it denies an unspecified + * permission. + */ + public abstract Path getPath(URI uri); + + /** + * Constructs a new {@code FileSystem} to access the contents of a file as a + * file system. + * + * <p> This method is intended for specialized providers of pseudo file + * systems where the contents of one or more files is treated as a file + * system. The {@code file} parameter is a reference to an existing file + * and the {@code env} parameter is a map of provider specific properties to + * configure the file system. + * + * <p> If this provider does not support the creation of such file systems + * or if the provider does not recognize the file type of the given file then + * it throws {@code UnsupportedOperationException}. The default implementation + * of this method throws {@code UnsupportedOperationException}. + * + * @param file + * The file + * @param env + * A map of provider specific properties to configure the file system; + * may be empty + * + * @return A new file system + * + * @throws UnsupportedOperationException + * If this provider does not support access to the contents as a + * file system or it does not recognize the file type of the + * given file + * @throws IllegalArgumentException + * If the {@code env} parameter does not contain properties required + * by the provider, or a property value is invalid + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * If a security manager is installed and it denies an unspecified + * permission. + */ + public FileSystem newFileSystem(FileRef file, Map<String,?> env) + throws IOException + { + throw new UnsupportedOperationException(); + } + + /** + * Opens or creates a file for reading and/or writing, returning a file + * channel to access the file. + * + * <p> This method is invoked by the {@link FileChannel#open(Path,Set,FileAttribute[]) + * FileChannel.open} method to open a file channel. A provider that does not + * support all the features required to construct a file channel throws + * {@code UnsupportedOperationException}. The default provider is required + * to support the creation of file channels. When not overridden, the + * default implementation throws {@code UnsupportedOperationException}. + * + * @param path + * The path of the file to open or create + * @param options + * Options specifying how the file is opened + * @param attrs + * An optional list of file attributes to set atomically when + * creating the file + * + * @return A new file channel + * + * @throws IllegalArgumentException + * If the set contains an invalid combination of options + * @throws UnsupportedOperationException + * If this provider that does not support creating file channels, + * or an unsupported open option or file attribute is specified + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default file system, the {@link + * SecurityManager#checkRead(String)} method is invoked to check + * read access if the file is opened for reading. The {@link + * SecurityManager#checkWrite(String)} method is invoked to check + * write access if the file is opened for writing + */ + public FileChannel newFileChannel(Path path, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + throw new UnsupportedOperationException(); + } + + /** + * Opens or creates a file for reading and/or writing, returning an + * asynchronous file channel to access the file. + * + * <p> This method is invoked by the {@link + * AsynchronousFileChannel#open(Path,Set,ExecutorService,FileAttribute[]) + * AsynchronousFileChannel.open} method to open an asynchronous file channel. + * A provider that does not support all the features required to construct + * an asynchronous file channel throws {@code UnsupportedOperationException}. + * The default provider is required to support the creation of asynchronous + * file channels. When not overridden, the default implementation of this + * method throws {@code UnsupportedOperationException}. + * + * @param path + * The path of the file to open or create + * @param options + * Options specifying how the file is opened + * @param executor + * The thread pool or {@code null} to associate the channel with + * the default thread pool + * @param attrs + * An optional list of file attributes to set atomically when + * creating the file + * + * @return A new asynchronous file channel + * + * @throws IllegalArgumentException + * If the set contains an invalid combination of options + * @throws UnsupportedOperationException + * If this provider that does not support creating asynchronous file + * channels, or an unsupported open option or file attribute is + * specified + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default file system, the {@link + * SecurityManager#checkRead(String)} method is invoked to check + * read access if the file is opened for reading. The {@link + * SecurityManager#checkWrite(String)} method is invoked to check + * write access if the file is opened for writing + */ + public AsynchronousFileChannel newAsynchronousFileChannel(Path path, + Set<? extends OpenOption> options, + ExecutorService executor, + FileAttribute<?>... attrs) + throws IOException + { + throw new UnsupportedOperationException(); + } +} diff --git a/jdk/src/share/classes/java/nio/file/spi/FileTypeDetector.java b/jdk/src/share/classes/java/nio/file/spi/FileTypeDetector.java new file mode 100644 index 00000000000..65e3c49c074 --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/spi/FileTypeDetector.java @@ -0,0 +1,106 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.file.spi; + +import java.nio.file.FileRef; +import java.io.IOException; + +/** + * A file type detector for probing a file to guess its file type. + * + * <p> A file type detector is a concrete implementation of this class, has a + * zero-argument constructor, and implements the abstract methods specified + * below. + * + * <p> The means by which a file type detector determines the file type is + * highly implementation specific. A simple implementation might examine the + * <em>file extension</em> (a convention used in some platforms) and map it to + * a file type. In other cases, the file type may be stored as a file <a + * href="../attribute/package-summary.html"> attribute</a> or the bytes in a + * file may be examined to guess its file type. + * + * @see java.nio.file.Files#probeContentType(FileRef) + * + * @since 1.7 + */ + +public abstract class FileTypeDetector { + + private static Void checkPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("fileTypeDetector")); + return null; + } + private FileTypeDetector(Void ignore) { } + + /** + * Initializes a new instance of this class. + * + * @throws SecurityException + * If a security manager has been installed and it denies + * {@link RuntimePermission}<tt>("fileTypeDetector")</tt> + */ + protected FileTypeDetector() { + this(checkPermission()); + } + + /** + * Probes the given file to guess its content type. + * + * <p> The means by which this method determines the file type is highly + * implementation specific. It may simply examine the file name, it may use + * a file <a href="../attribute/package-summary.html">attribute</a>, + * or it may examines bytes in the file. + * + * <p> The probe result is the string form of the value of a + * Multipurpose Internet Mail Extension (MIME) content type as + * defined by <a href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC 2045: + * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet + * Message Bodies</i></a>. The string must be parsable according to the + * grammar in the RFC 2045. + * + * @param file + * The file to probe + * + * @return The content type or {@code null} if the file type is not + * recognized + * + * @throws IOException + * An I/O error occurs + * @throws SecurityException + * If the implementation requires to access the file, and a + * security manager is installed, and it denies an unspecified + * permission required by a file system provider implementation. + * If the file reference is associated with the default file system + * provider then the {@link SecurityManager#checkRead(String)} method + * is invoked to check read access to the file. + * + * @see java.nio.file.Files#probeContentType + */ + public abstract String probeContentType(FileRef file) + throws IOException; +} diff --git a/jdk/src/share/classes/java/nio/file/spi/package-info.java b/jdk/src/share/classes/java/nio/file/spi/package-info.java new file mode 100644 index 00000000000..88149b7974a --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/spi/package-info.java @@ -0,0 +1,39 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Service-provider classes for the <tt>{@link java.nio.file}</tt> package. + * + * <p> Only developers who are defining new file system providers or file type + * detectors should need to make direct use of this package. </p> + * + * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor + * or method in any class or interface in this package will cause a {@link + * java.lang.NullPointerException NullPointerException} to be thrown. + * + * @since 1.7 + */ + +package java.nio.file.spi; diff --git a/jdk/src/share/classes/java/security/Permission.java b/jdk/src/share/classes/java/security/Permission.java index 243f98317bb..a33b6e9f568 100644 --- a/jdk/src/share/classes/java/security/Permission.java +++ b/jdk/src/share/classes/java/security/Permission.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -214,18 +214,18 @@ public abstract class Permission implements Guard, java.io.Serializable { /** * Returns a string describing this Permission. The convention is to * specify the class name, the permission name, and the actions in - * the following format: '("ClassName" "name" "actions")'. + * the following format: '("ClassName" "name" "actions")', or + * '("ClassName" "name")' if actions list is null or empty. * * @return information about this Permission. */ - public String toString() { String actions = getActions(); if ((actions == null) || (actions.length() == 0)) { // OPTIONAL - return "(" + getClass().getName() + " " + name + ")"; + return "(\"" + getClass().getName() + "\" \"" + name + "\")"; } else { - return "(" + getClass().getName() + " " + name + " " + - actions + ")"; + return "(\"" + getClass().getName() + "\" \"" + name + + "\" \"" + actions + "\")"; } } } diff --git a/jdk/src/share/classes/java/security/SecureClassLoader.java b/jdk/src/share/classes/java/security/SecureClassLoader.java index fac4596359c..ff11f38aaaa 100644 --- a/jdk/src/share/classes/java/security/SecureClassLoader.java +++ b/jdk/src/share/classes/java/security/SecureClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,14 +45,19 @@ public class SecureClassLoader extends ClassLoader { * succeed. Otherwise the object is not initialized and the object is * useless. */ - private boolean initialized = false; + private final boolean initialized; // HashMap that maps CodeSource to ProtectionDomain - private HashMap<CodeSource, ProtectionDomain> pdcache = + // @GuardedBy("pdcache") + private final HashMap<CodeSource, ProtectionDomain> pdcache = new HashMap<CodeSource, ProtectionDomain>(11); private static final Debug debug = Debug.getInstance("scl"); + static { + ClassLoader.registerAsParallelCapable(); + } + /** * Creates a new SecureClassLoader using the specified parent * class loader for delegation. @@ -136,10 +141,7 @@ public class SecureClassLoader extends ClassLoader { byte[] b, int off, int len, CodeSource cs) { - if (cs == null) - return defineClass(name, b, off, len); - else - return defineClass(name, b, off, len, getProtectionDomain(cs)); + return defineClass(name, b, off, len, getProtectionDomain(cs)); } /** @@ -172,10 +174,7 @@ public class SecureClassLoader extends ClassLoader { protected final Class<?> defineClass(String name, java.nio.ByteBuffer b, CodeSource cs) { - if (cs == null) - return defineClass(name, b, (ProtectionDomain)null); - else - return defineClass(name, b, getProtectionDomain(cs)); + return defineClass(name, b, getProtectionDomain(cs)); } /** @@ -209,12 +208,10 @@ public class SecureClassLoader extends ClassLoader { if (pd == null) { PermissionCollection perms = getPermissions(cs); pd = new ProtectionDomain(cs, perms, this, null); - if (pd != null) { - pdcache.put(cs, pd); - if (debug != null) { - debug.println(" getPermissions "+ pd); - debug.println(""); - } + pdcache.put(cs, pd); + if (debug != null) { + debug.println(" getPermissions "+ pd); + debug.println(""); } } } diff --git a/jdk/src/share/classes/java/util/ArrayList.java b/jdk/src/share/classes/java/util/ArrayList.java index 6eeb2a4fc2a..dbd46096bf3 100644 --- a/jdk/src/share/classes/java/util/ArrayList.java +++ b/jdk/src/share/classes/java/util/ArrayList.java @@ -179,7 +179,6 @@ public class ArrayList<E> extends AbstractList<E> modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { - Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; diff --git a/jdk/src/share/classes/java/util/Scanner.java b/jdk/src/share/classes/java/util/Scanner.java index 8fd828fffe9..3e3806d1ff4 100644 --- a/jdk/src/share/classes/java/util/Scanner.java +++ b/jdk/src/share/classes/java/util/Scanner.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package java.util; +import java.nio.file.FileRef; import java.util.regex.*; import java.io.*; import java.math.*; @@ -672,6 +673,49 @@ public final class Scanner implements Iterator<String> { charsetName); } + /** + * {@note new} + * Constructs a new <code>Scanner</code> that produces values scanned + * from the specified file. Bytes from the file are converted into + * characters using the underlying platform's + * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * + * @param source + * A file to be scanned + * @throws IOException + * if an I/O error occurs opening source + * + * @since 1.7 + */ + public Scanner(FileRef source) + throws IOException + { + this(source.newByteChannel()); + } + + /** + * {@note new} + * Constructs a new <code>Scanner</code> that produces values scanned + * from the specified file. Bytes from the file are converted into + * characters using the specified charset. + * + * @param source + * A file to be scanned + * @param charsetName + * The encoding type used to convert bytes from the file + * into characters to be scanned + * @throws IOException + * if an I/O error occurs opening source + * @throws IllegalArgumentException + * if the specified encoding is not found + * @since 1.7 + */ + public Scanner(FileRef source, String charsetName) + throws IOException + { + this(source.newByteChannel(), charsetName); + } + /** * Constructs a new <code>Scanner</code> that produces values scanned * from the specified string. diff --git a/jdk/src/share/classes/java/util/TreeMap.java b/jdk/src/share/classes/java/util/TreeMap.java index 6a1c6b411f5..cf97bccb7e7 100644 --- a/jdk/src/share/classes/java/util/TreeMap.java +++ b/jdk/src/share/classes/java/util/TreeMap.java @@ -1068,14 +1068,14 @@ public class TreeMap<K,V> } public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { - return new TreeSet<E>(m.subMap(fromElement, fromInclusive, - toElement, toInclusive)); + return new KeySet<E>(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); } public NavigableSet<E> headSet(E toElement, boolean inclusive) { - return new TreeSet<E>(m.headMap(toElement, inclusive)); + return new KeySet<E>(m.headMap(toElement, inclusive)); } public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { - return new TreeSet<E>(m.tailMap(fromElement, inclusive)); + return new KeySet<E>(m.tailMap(fromElement, inclusive)); } public SortedSet<E> subSet(E fromElement, E toElement) { return subSet(fromElement, true, toElement, false); @@ -1087,7 +1087,7 @@ public class TreeMap<K,V> return tailSet(fromElement, true); } public NavigableSet<E> descendingSet() { - return new TreeSet(m.descendingMap()); + return new KeySet(m.descendingMap()); } } diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java index 143d06713b4..323482acb4e 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java @@ -2394,15 +2394,14 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V> boolean fromInclusive, E toElement, boolean toInclusive) { - return new ConcurrentSkipListSet<E> - (m.subMap(fromElement, fromInclusive, - toElement, toInclusive)); + return new KeySet<E>(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); } public NavigableSet<E> headSet(E toElement, boolean inclusive) { - return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive)); + return new KeySet<E>(m.headMap(toElement, inclusive)); } public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { - return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive)); + return new KeySet<E>(m.tailMap(fromElement, inclusive)); } public NavigableSet<E> subSet(E fromElement, E toElement) { return subSet(fromElement, true, toElement, false); @@ -2414,7 +2413,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V> return tailSet(fromElement, true); } public NavigableSet<E> descendingSet() { - return new ConcurrentSkipListSet(m.descendingMap()); + return new KeySet(m.descendingMap()); } } diff --git a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java index 2b0f36c523d..68135015c29 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java @@ -166,6 +166,11 @@ public abstract class AbstractQueuedLongSynchronizer static final int SIGNAL = -1; /** waitStatus value to indicate thread is waiting on condition */ static final int CONDITION = -2; + /** + * waitStatus value to indicate the next acquireShared should + * unconditionally propagate + */ + static final int PROPAGATE = -3; /** * Status field, taking on only the values: @@ -180,10 +185,16 @@ public abstract class AbstractQueuedLongSynchronizer * Nodes never leave this state. In particular, * a thread with cancelled node never again blocks. * CONDITION: This node is currently on a condition queue. - * It will not be used as a sync queue node until - * transferred. (Use of this value here - * has nothing to do with the other uses - * of the field, but simplifies mechanics.) + * It will not be used as a sync queue node + * until transferred, at which time the status + * will be set to 0. (Use of this value here has + * nothing to do with the other uses of the + * field, but simplifies mechanics.) + * PROPAGATE: A releaseShared should be propagated to other + * nodes. This is set (for head node only) in + * doReleaseShared to ensure propagation + * continues, even if other operations have + * since intervened. * 0: None of the above * * The values are arranged numerically to simplify use. @@ -403,10 +414,13 @@ public abstract class AbstractQueuedLongSynchronizer */ private void unparkSuccessor(Node node) { /* - * Try to clear status in anticipation of signalling. It is - * OK if this fails or if status is changed by waiting thread. + * If status is negative (i.e., possibly needing signal) try + * to clear in anticipation of signalling. It is OK if this + * fails or if status is changed by waiting thread. */ - compareAndSetWaitStatus(node, Node.SIGNAL, 0); + int ws = node.waitStatus; + if (ws < 0) + compareAndSetWaitStatus(node, ws, 0); /* * Thread to unpark is held in successor, which is normally @@ -425,24 +439,71 @@ public abstract class AbstractQueuedLongSynchronizer LockSupport.unpark(s.thread); } + /** + * Release action for shared mode -- signal successor and ensure + * propagation. (Note: For exclusive mode, release just amounts + * to calling unparkSuccessor of head if it needs signal.) + */ + private void doReleaseShared() { + /* + * Ensure that a release propagates, even if there are other + * in-progress acquires/releases. This proceeds in the usual + * way of trying to unparkSuccessor of head if it needs + * signal. But if it does not, status is set to PROPAGATE to + * ensure that upon release, propagation continues. + * Additionally, we must loop in case a new node is added + * while we are doing this. Also, unlike other uses of + * unparkSuccessor, we need to know if CAS to reset status + * fails, if so rechecking. + */ + for (;;) { + Node h = head; + if (h != null && h != tail) { + int ws = h.waitStatus; + if (ws == Node.SIGNAL) { + if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) + continue; // loop to recheck cases + unparkSuccessor(h); + } + else if (ws == 0 && + !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) + continue; // loop on failed CAS + } + if (h == head) // loop if head changed + break; + } + } + /** * Sets head of queue, and checks if successor may be waiting - * in shared mode, if so propagating if propagate > 0. + * in shared mode, if so propagating if either propagate > 0 or + * PROPAGATE status was set. * - * @param pred the node holding waitStatus for node * @param node the node * @param propagate the return value from a tryAcquireShared */ private void setHeadAndPropagate(Node node, long propagate) { + Node h = head; // Record old head for check below setHead(node); - if (propagate > 0 && node.waitStatus != 0) { - /* - * Don't bother fully figuring out successor. If it - * looks null, call unparkSuccessor anyway to be safe. - */ + /* + * Try to signal next queued node if: + * Propagation was indicated by caller, + * or was recorded (as h.waitStatus) by a previous operation + * (note: this uses sign-check of waitStatus because + * PROPAGATE status may transition to SIGNAL.) + * and + * The next node is waiting in shared mode, + * or we don't know, because it appears null + * + * The conservatism in both of these checks may cause + * unnecessary wake-ups, but only when there are multiple + * racing acquires/releases, so most need signals now or soon + * anyway. + */ + if (propagate > 0 || h == null || h.waitStatus < 0) { Node s = node.next; if (s == null || s.isShared()) - unparkSuccessor(node); + doReleaseShared(); } } @@ -465,23 +526,27 @@ public abstract class AbstractQueuedLongSynchronizer while (pred.waitStatus > 0) node.prev = pred = pred.prev; - // Getting this before setting waitStatus ensures staleness + // predNext is the apparent node to unsplice. CASes below will + // fail if not, in which case, we lost race vs another cancel + // or signal, so no further action is necessary. Node predNext = pred.next; - // Can use unconditional write instead of CAS here + // Can use unconditional write instead of CAS here. + // After this atomic step, other Nodes can skip past us. + // Before, we are free of interference from other threads. node.waitStatus = Node.CANCELLED; - // If we are the tail, remove ourselves + // If we are the tail, remove ourselves. if (node == tail && compareAndSetTail(node, pred)) { compareAndSetNext(pred, predNext, null); } else { - // If "active" predecessor found... - if (pred != head - && (pred.waitStatus == Node.SIGNAL - || compareAndSetWaitStatus(pred, 0, Node.SIGNAL)) - && pred.thread != null) { - - // If successor is active, set predecessor's next link + // If successor needs signal, try to set pred's next-link + // so it will get one. Otherwise wake it up to propagate. + int ws; + if (pred != head && + ((ws = pred.waitStatus) == Node.SIGNAL || + (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && + pred.thread != null) { Node next = node.next; if (next != null && next.waitStatus <= 0) compareAndSetNext(pred, predNext, next); @@ -503,14 +568,14 @@ public abstract class AbstractQueuedLongSynchronizer * @return {@code true} if thread should block */ private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { - int s = pred.waitStatus; - if (s < 0) + int ws = pred.waitStatus; + if (ws == Node.SIGNAL) /* * This node has already set status asking a release * to signal it, so it can safely park. */ return true; - if (s > 0) { + if (ws > 0) { /* * Predecessor was cancelled. Skip over predecessors and * indicate retry. @@ -519,14 +584,14 @@ public abstract class AbstractQueuedLongSynchronizer node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; - } - else + } else { /* - * Indicate that we need a signal, but don't park yet. Caller - * will need to retry to make sure it cannot acquire before - * parking. + * waitStatus must be 0 or PROPAGATE. Indicate that we + * need a signal, but don't park yet. Caller will need to + * retry to make sure it cannot acquire before parking. */ - compareAndSetWaitStatus(pred, 0, Node.SIGNAL); + compareAndSetWaitStatus(pred, ws, Node.SIGNAL); + } return false; } @@ -1046,9 +1111,7 @@ public abstract class AbstractQueuedLongSynchronizer */ public final boolean releaseShared(long arg) { if (tryReleaseShared(arg)) { - Node h = head; - if (h != null && h.waitStatus != 0) - unparkSuccessor(h); + doReleaseShared(); return true; } return false; @@ -1222,8 +1285,10 @@ public abstract class AbstractQueuedLongSynchronizer // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. - Node h, s; - return (h = head) != tail && + Node t = tail; // Read fields in reverse initialization order + Node h = head; + Node s; + return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); } @@ -1388,8 +1453,8 @@ public abstract class AbstractQueuedLongSynchronizer * case the waitStatus can be transiently and harmlessly wrong). */ Node p = enq(node); - int c = p.waitStatus; - if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL)) + int ws = p.waitStatus; + if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; } diff --git a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java index 597e15270ae..8de1cad1d50 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -389,6 +389,11 @@ public abstract class AbstractQueuedSynchronizer static final int SIGNAL = -1; /** waitStatus value to indicate thread is waiting on condition */ static final int CONDITION = -2; + /** + * waitStatus value to indicate the next acquireShared should + * unconditionally propagate + */ + static final int PROPAGATE = -3; /** * Status field, taking on only the values: @@ -403,10 +408,16 @@ public abstract class AbstractQueuedSynchronizer * Nodes never leave this state. In particular, * a thread with cancelled node never again blocks. * CONDITION: This node is currently on a condition queue. - * It will not be used as a sync queue node until - * transferred. (Use of this value here - * has nothing to do with the other uses - * of the field, but simplifies mechanics.) + * It will not be used as a sync queue node + * until transferred, at which time the status + * will be set to 0. (Use of this value here has + * nothing to do with the other uses of the + * field, but simplifies mechanics.) + * PROPAGATE: A releaseShared should be propagated to other + * nodes. This is set (for head node only) in + * doReleaseShared to ensure propagation + * continues, even if other operations have + * since intervened. * 0: None of the above * * The values are arranged numerically to simplify use. @@ -626,10 +637,13 @@ public abstract class AbstractQueuedSynchronizer */ private void unparkSuccessor(Node node) { /* - * Try to clear status in anticipation of signalling. It is - * OK if this fails or if status is changed by waiting thread. + * If status is negative (i.e., possibly needing signal) try + * to clear in anticipation of signalling. It is OK if this + * fails or if status is changed by waiting thread. */ - compareAndSetWaitStatus(node, Node.SIGNAL, 0); + int ws = node.waitStatus; + if (ws < 0) + compareAndSetWaitStatus(node, ws, 0); /* * Thread to unpark is held in successor, which is normally @@ -648,24 +662,71 @@ public abstract class AbstractQueuedSynchronizer LockSupport.unpark(s.thread); } + /** + * Release action for shared mode -- signal successor and ensure + * propagation. (Note: For exclusive mode, release just amounts + * to calling unparkSuccessor of head if it needs signal.) + */ + private void doReleaseShared() { + /* + * Ensure that a release propagates, even if there are other + * in-progress acquires/releases. This proceeds in the usual + * way of trying to unparkSuccessor of head if it needs + * signal. But if it does not, status is set to PROPAGATE to + * ensure that upon release, propagation continues. + * Additionally, we must loop in case a new node is added + * while we are doing this. Also, unlike other uses of + * unparkSuccessor, we need to know if CAS to reset status + * fails, if so rechecking. + */ + for (;;) { + Node h = head; + if (h != null && h != tail) { + int ws = h.waitStatus; + if (ws == Node.SIGNAL) { + if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) + continue; // loop to recheck cases + unparkSuccessor(h); + } + else if (ws == 0 && + !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) + continue; // loop on failed CAS + } + if (h == head) // loop if head changed + break; + } + } + /** * Sets head of queue, and checks if successor may be waiting - * in shared mode, if so propagating if propagate > 0. + * in shared mode, if so propagating if either propagate > 0 or + * PROPAGATE status was set. * - * @param pred the node holding waitStatus for node * @param node the node * @param propagate the return value from a tryAcquireShared */ private void setHeadAndPropagate(Node node, int propagate) { + Node h = head; // Record old head for check below setHead(node); - if (propagate > 0 && node.waitStatus != 0) { - /* - * Don't bother fully figuring out successor. If it - * looks null, call unparkSuccessor anyway to be safe. - */ + /* + * Try to signal next queued node if: + * Propagation was indicated by caller, + * or was recorded (as h.waitStatus) by a previous operation + * (note: this uses sign-check of waitStatus because + * PROPAGATE status may transition to SIGNAL.) + * and + * The next node is waiting in shared mode, + * or we don't know, because it appears null + * + * The conservatism in both of these checks may cause + * unnecessary wake-ups, but only when there are multiple + * racing acquires/releases, so most need signals now or soon + * anyway. + */ + if (propagate > 0 || h == null || h.waitStatus < 0) { Node s = node.next; if (s == null || s.isShared()) - unparkSuccessor(node); + doReleaseShared(); } } @@ -688,23 +749,27 @@ public abstract class AbstractQueuedSynchronizer while (pred.waitStatus > 0) node.prev = pred = pred.prev; - // Getting this before setting waitStatus ensures staleness + // predNext is the apparent node to unsplice. CASes below will + // fail if not, in which case, we lost race vs another cancel + // or signal, so no further action is necessary. Node predNext = pred.next; - // Can use unconditional write instead of CAS here + // Can use unconditional write instead of CAS here. + // After this atomic step, other Nodes can skip past us. + // Before, we are free of interference from other threads. node.waitStatus = Node.CANCELLED; - // If we are the tail, remove ourselves + // If we are the tail, remove ourselves. if (node == tail && compareAndSetTail(node, pred)) { compareAndSetNext(pred, predNext, null); } else { - // If "active" predecessor found... - if (pred != head - && (pred.waitStatus == Node.SIGNAL - || compareAndSetWaitStatus(pred, 0, Node.SIGNAL)) - && pred.thread != null) { - - // If successor is active, set predecessor's next link + // If successor needs signal, try to set pred's next-link + // so it will get one. Otherwise wake it up to propagate. + int ws; + if (pred != head && + ((ws = pred.waitStatus) == Node.SIGNAL || + (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && + pred.thread != null) { Node next = node.next; if (next != null && next.waitStatus <= 0) compareAndSetNext(pred, predNext, next); @@ -726,14 +791,14 @@ public abstract class AbstractQueuedSynchronizer * @return {@code true} if thread should block */ private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { - int s = pred.waitStatus; - if (s < 0) + int ws = pred.waitStatus; + if (ws == Node.SIGNAL) /* * This node has already set status asking a release * to signal it, so it can safely park. */ return true; - if (s > 0) { + if (ws > 0) { /* * Predecessor was cancelled. Skip over predecessors and * indicate retry. @@ -742,14 +807,14 @@ public abstract class AbstractQueuedSynchronizer node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; - } - else + } else { /* - * Indicate that we need a signal, but don't park yet. Caller - * will need to retry to make sure it cannot acquire before - * parking. + * waitStatus must be 0 or PROPAGATE. Indicate that we + * need a signal, but don't park yet. Caller will need to + * retry to make sure it cannot acquire before parking. */ - compareAndSetWaitStatus(pred, 0, Node.SIGNAL); + compareAndSetWaitStatus(pred, ws, Node.SIGNAL); + } return false; } @@ -1269,9 +1334,7 @@ public abstract class AbstractQueuedSynchronizer */ public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { - Node h = head; - if (h != null && h.waitStatus != 0) - unparkSuccessor(h); + doReleaseShared(); return true; } return false; @@ -1445,8 +1508,10 @@ public abstract class AbstractQueuedSynchronizer // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. - Node h, s; - return (h = head) != tail && + Node t = tail; // Read fields in reverse initialization order + Node h = head; + Node s; + return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); } @@ -1611,8 +1676,8 @@ public abstract class AbstractQueuedSynchronizer * case the waitStatus can be transiently and harmlessly wrong). */ Node p = enq(node); - int c = p.waitStatus; - if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL)) + int ws = p.waitStatus; + if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; } diff --git a/jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java b/jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java index 8888efb2477..e767dfa62b1 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java @@ -276,7 +276,7 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab * Maintained as a ThreadLocal; cached in cachedHoldCounter */ static final class HoldCounter { - int count; + int count = 0; // Use id, not reference, to avoid garbage retention final long tid = Thread.currentThread().getId(); } @@ -293,8 +293,9 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab } /** - * The number of read locks held by current thread. + * The number of reentrant read locks held by current thread. * Initialized only in constructor and readObject. + * Removed whenever a thread's read hold count drops to 0. */ private transient ThreadLocalHoldCounter readHolds; @@ -304,17 +305,35 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab * where the next thread to release is the last one to * acquire. This is non-volatile since it is just used * as a heuristic, and would be great for threads to cache. + * + * <p>Can outlive the Thread for which it is caching the read + * hold count, but avoids garbage retention by not retaining a + * reference to the Thread. + * + * <p>Accessed via a benign data race; relies on the memory + * model's final field and out-of-thin-air guarantees. */ private transient HoldCounter cachedHoldCounter; /** * firstReader is the first thread to have acquired the read lock. * firstReaderHoldCount is firstReader's hold count. - * This allows tracking of read holds for uncontended read + * + * <p>More precisely, firstReader is the unique thread that last + * changed the shared count from 0 to 1, and has not released the + * read lock since then; null if there is no such thread. + * + * <p>Cannot cause garbage retention unless the thread terminated + * without relinquishing its read locks, since tryReleaseShared + * sets it to null. + * + * <p>Accessed via a benign data race; relies on the memory + * model's out-of-thin-air guarantees for references. + * + * <p>This allows tracking of read holds for uncontended read * locks to be very cheap. */ - private final static long INVALID_THREAD_ID = -1; - private transient long firstReader = INVALID_THREAD_ID; + private transient Thread firstReader = null; private transient int firstReaderHoldCount; Sync() { @@ -393,16 +412,16 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab } protected final boolean tryReleaseShared(int unused) { - long tid = Thread.currentThread().getId(); - if (firstReader == tid) { + Thread current = Thread.currentThread(); + if (firstReader == current) { // assert firstReaderHoldCount > 0; if (firstReaderHoldCount == 1) - firstReader = INVALID_THREAD_ID; + firstReader = null; else firstReaderHoldCount--; } else { HoldCounter rh = cachedHoldCounter; - if (rh == null || rh.tid != tid) + if (rh == null || rh.tid != current.getId()) rh = readHolds.get(); int count = rh.count; if (count <= 1) { @@ -416,6 +435,9 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab int c = getState(); int nextc = c - SHARED_UNIT; if (compareAndSetState(c, nextc)) + // Releasing the read lock has no effect on readers, + // but it may allow waiting writers to proceed if + // both read and write locks are now free. return nextc == 0; } } @@ -450,15 +472,14 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) { - long tid = current.getId(); if (r == 0) { - firstReader = tid; + firstReader = current; firstReaderHoldCount = 1; - } else if (firstReader == tid) { + } else if (firstReader == current) { firstReaderHoldCount++; } else { HoldCounter rh = cachedHoldCounter; - if (rh == null || rh.tid != tid) + if (rh == null || rh.tid != current.getId()) cachedHoldCounter = rh = readHolds.get(); else if (rh.count == 0) readHolds.set(rh); @@ -485,19 +506,17 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab int c = getState(); if (exclusiveCount(c) != 0) { if (getExclusiveOwnerThread() != current) - //if (removeNeeded) readHolds.remove(); return -1; // else we hold the exclusive lock; blocking here // would cause deadlock. } else if (readerShouldBlock()) { // Make sure we're not acquiring read lock reentrantly - long tid = current.getId(); - if (firstReader == tid) { + if (firstReader == current) { // assert firstReaderHoldCount > 0; } else { if (rh == null) { rh = cachedHoldCounter; - if (rh == null || rh.tid != tid) { + if (rh == null || rh.tid != current.getId()) { rh = readHolds.get(); if (rh.count == 0) readHolds.remove(); @@ -510,25 +529,20 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab if (sharedCount(c) == MAX_COUNT) throw new Error("Maximum lock count exceeded"); if (compareAndSetState(c, c + SHARED_UNIT)) { - long tid = current.getId(); if (sharedCount(c) == 0) { - firstReader = tid; + firstReader = current; firstReaderHoldCount = 1; - } else if (firstReader == tid) { + } else if (firstReader == current) { firstReaderHoldCount++; } else { - if (rh == null) { + if (rh == null) rh = cachedHoldCounter; - if (rh != null && rh.tid == tid) { - if (rh.count == 0) - readHolds.set(rh); - } else { - rh = readHolds.get(); - } - } else if (rh.count == 0) + if (rh == null || rh.tid != current.getId()) + rh = readHolds.get(); + else if (rh.count == 0) readHolds.set(rh); - cachedHoldCounter = rh; // cache for release rh.count++; + cachedHoldCounter = rh; // cache for release } return 1; } @@ -572,15 +586,14 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab if (r == MAX_COUNT) throw new Error("Maximum lock count exceeded"); if (compareAndSetState(c, c + SHARED_UNIT)) { - long tid = current.getId(); if (r == 0) { - firstReader = tid; + firstReader = current; firstReaderHoldCount = 1; - } else if (firstReader == tid) { + } else if (firstReader == current) { firstReaderHoldCount++; } else { HoldCounter rh = cachedHoldCounter; - if (rh == null || rh.tid != tid) + if (rh == null || rh.tid != current.getId()) cachedHoldCounter = rh = readHolds.get(); else if (rh.count == 0) readHolds.set(rh); @@ -626,12 +639,12 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab if (getReadLockCount() == 0) return 0; - long tid = Thread.currentThread().getId(); - if (firstReader == tid) + Thread current = Thread.currentThread(); + if (firstReader == current) return firstReaderHoldCount; HoldCounter rh = cachedHoldCounter; - if (rh != null && rh.tid == tid) + if (rh != null && rh.tid == current.getId()) return rh.count; int count = readHolds.get().count; @@ -647,7 +660,6 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); readHolds = new ThreadLocalHoldCounter(); - firstReader = INVALID_THREAD_ID; setState(0); // reset to unlocked state } diff --git a/jdk/src/share/classes/java/util/logging/LogManager.java b/jdk/src/share/classes/java/util/logging/LogManager.java index 412f749404d..fc8f080eb71 100644 --- a/jdk/src/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/share/classes/java/util/logging/LogManager.java @@ -215,6 +215,14 @@ public class LogManager { // This private class is used as a shutdown hook. // It does a "reset" to close all open handlers. private class Cleaner extends Thread { + + private Cleaner() { + /* Set context class loader to null in order to avoid + * keeping a strong reference to an application classloader. + */ + this.setContextClassLoader(null); + } + public void run() { // This is to ensure the LogManager.<clinit> is completed // before synchronized block. Otherwise deadlocks are possible. diff --git a/jdk/src/share/classes/java/util/regex/Matcher.java b/jdk/src/share/classes/java/util/regex/Matcher.java index ee7931688e2..488e47da89a 100644 --- a/jdk/src/share/classes/java/util/regex/Matcher.java +++ b/jdk/src/share/classes/java/util/regex/Matcher.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -490,6 +490,45 @@ public final class Matcher implements MatchResult { return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString(); } + /** + * Returns the input subsequence captured by the given + * <a href="Pattern.html#groupname">named-capturing group</a> during the previous + * match operation. + * + * <p> If the match was successful but the group specified failed to match + * any part of the input sequence, then <tt>null</tt> is returned. Note + * that some groups, for example <tt>(a*)</tt>, match the empty string. + * This method will return the empty string when such a group successfully + * matches the empty string in the input. </p> + * + * @param name + * The name of a named-capturing group in this matcher's pattern + * + * @return The (possibly empty) subsequence captured by the named group + * during the previous match, or <tt>null</tt> if the group + * failed to match part of the input + * + * @throws IllegalStateException + * If no match has yet been attempted, + * or if the previous match operation failed + * + * @throws IllegalArgumentException + * If there is no capturing group in the pattern + * with the given name + */ + public String group(String name) { + if (name == null) + throw new NullPointerException("Null group name"); + if (first < 0) + throw new IllegalStateException("No match found"); + if (!parentPattern.namedGroups().containsKey(name)) + throw new IllegalArgumentException("No group with name <" + name + ">"); + int group = parentPattern.namedGroups().get(name); + if ((groups[group*2] == -1) || (groups[group*2+1] == -1)) + return null; + return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString(); + } + /** * Returns the number of capturing groups in this matcher's pattern. * @@ -649,9 +688,11 @@ public final class Matcher implements MatchResult { * * <p> The replacement string may contain references to subsequences * captured during the previous match: Each occurrence of - * <tt>$</tt><i>g</i><tt></tt> will be replaced by the result of - * evaluating {@link #group(int) group}<tt>(</tt><i>g</i><tt>)</tt>. - * The first number after the <tt>$</tt> is always treated as part of + * <tt>$</tt><<i>name</i>> or <tt>$</tt><i>g</i> + * will be replaced by the result of evaluating the corresponding + * {@link #group(String) group(name)} or {@link #group(int) group(g)</tt>} + * respectively. For <tt>$</tt><i>g</i><tt></tt>, + * the first number after the <tt>$</tt> is always treated as part of * the group reference. Subsequent numbers are incorporated into g if * they would form a legal group reference. Only the numerals '0' * through '9' are considered as potential components of the group @@ -695,6 +736,10 @@ public final class Matcher implements MatchResult { * If no match has yet been attempted, * or if the previous match operation failed * + * @throws IllegalArgumentException + * If the replacement string refers to a named-capturing + * group that does not exist in the pattern + * * @throws IndexOutOfBoundsException * If the replacement string refers to a capturing group * that does not exist in the pattern @@ -719,29 +764,62 @@ public final class Matcher implements MatchResult { } else if (nextChar == '$') { // Skip past $ cursor++; - // The first number is always a group - int refNum = (int)replacement.charAt(cursor) - '0'; - if ((refNum < 0)||(refNum > 9)) - throw new IllegalArgumentException( - "Illegal group reference"); - cursor++; - - // Capture the largest legal group string - boolean done = false; - while (!done) { - if (cursor >= replacement.length()) { - break; + // A StringIndexOutOfBoundsException is thrown if + // this "$" is the last character in replacement + // string in current implementation, a IAE might be + // more appropriate. + nextChar = replacement.charAt(cursor); + int refNum = -1; + if (nextChar == '<') { + cursor++; + StringBuilder gsb = new StringBuilder(); + while (cursor < replacement.length()) { + nextChar = replacement.charAt(cursor); + if (ASCII.isLower(nextChar) || + ASCII.isUpper(nextChar) || + ASCII.isDigit(nextChar)) { + gsb.append(nextChar); + cursor++; + } else { + break; + } } - int nextDigit = replacement.charAt(cursor) - '0'; - if ((nextDigit < 0)||(nextDigit > 9)) { // not a number - break; - } - int newRefNum = (refNum * 10) + nextDigit; - if (groupCount() < newRefNum) { - done = true; - } else { - refNum = newRefNum; - cursor++; + if (gsb.length() == 0) + throw new IllegalArgumentException( + "named capturing group has 0 length name"); + if (nextChar != '>') + throw new IllegalArgumentException( + "named capturing group is missing trailing '>'"); + String gname = gsb.toString(); + if (!parentPattern.namedGroups().containsKey(gname)) + throw new IllegalArgumentException( + "No group with name <" + gname + ">"); + refNum = parentPattern.namedGroups().get(gname); + cursor++; + } else { + // The first number is always a group + refNum = (int)nextChar - '0'; + if ((refNum < 0)||(refNum > 9)) + throw new IllegalArgumentException( + "Illegal group reference"); + cursor++; + // Capture the largest legal group string + boolean done = false; + while (!done) { + if (cursor >= replacement.length()) { + break; + } + int nextDigit = replacement.charAt(cursor) - '0'; + if ((nextDigit < 0)||(nextDigit > 9)) { // not a number + break; + } + int newRefNum = (refNum * 10) + nextDigit; + if (groupCount() < newRefNum) { + done = true; + } else { + refNum = newRefNum; + cursor++; + } } } // Append group diff --git a/jdk/src/share/classes/java/util/regex/Pattern.java b/jdk/src/share/classes/java/util/regex/Pattern.java index 2458a855e08..bda83849a37 100644 --- a/jdk/src/share/classes/java/util/regex/Pattern.java +++ b/jdk/src/share/classes/java/util/regex/Pattern.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.text.CharacterIterator; import java.text.Normalizer; +import java.util.Map; import java.util.ArrayList; import java.util.HashMap; import java.util.Arrays; @@ -298,6 +299,10 @@ import java.util.Arrays; * <td valign="bottom" headers="matches">Whatever the <i>n</i><sup>th</sup> * <a href="#cg">capturing group</a> matched</td></tr> * + * <tr><td valign="bottom" headers="construct backref"><tt>\</tt><i>k</i><<i>name</i>></td> + * <td valign="bottom" headers="matches">Whatever the + * <a href="#groupname">named-capturing group</a> "name" matched</td></tr> + * * <tr><th> </th></tr> * <tr align="left"><th colspan="2" id="quot">Quotation</th></tr> * @@ -310,8 +315,10 @@ import java.util.Arrays; * <!-- Metachars: !$()*+.<>?[\]^{|} --> * * <tr><th> </th></tr> - * <tr align="left"><th colspan="2" id="special">Special constructs (non-capturing)</th></tr> + * <tr align="left"><th colspan="2" id="special">Special constructs (named-capturing and non-capturing)</th></tr> * + * <tr><td valign="top" headers="construct special"><tt>(?<<a href="#groupname">name</a>></tt><i>X</i><tt>)</tt></td> + * <td headers="matches"><i>X</i>, as a named-capturing group</td></tr> * <tr><td valign="top" headers="construct special"><tt>(?:</tt><i>X</i><tt>)</tt></td> * <td headers="matches"><i>X</i>, as a non-capturing group</td></tr> * <tr><td valign="top" headers="construct special"><tt>(?idmsux-idmsux) </tt></td> @@ -449,6 +456,8 @@ import java.util.Arrays; * <a name="cg"> * <h4> Groups and capturing </h4> * + * <a name="gnumber"> + * <h5> Group number </h5> * <p> Capturing groups are numbered by counting their opening parentheses from * left to right. In the expression <tt>((A)(B(C)))</tt>, for example, there * are four such groups: </p> @@ -471,6 +480,24 @@ import java.util.Arrays; * subsequence may be used later in the expression, via a back reference, and * may also be retrieved from the matcher once the match operation is complete. * + * <a name="groupname"> + * <h5> Group name </h5> + * <p>A capturing group can also be assigned a "name", a <tt>named-capturing group</tt>, + * and then be back-referenced later by the "name". Group names are composed of + * the following characters: + * + * <ul> + * <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt> + * (<tt>'\u0041'</tt> through <tt>'\u005a'</tt>), + * <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt> + * (<tt>'\u0061'</tt> through <tt>'\u007a'</tt>), + * <li> The digits <tt>'0'</tt> through <tt>'9'</tt> + * (<tt>'\u0030'</tt> through <tt>'\u0039'</tt>), + * </ul> + * + * <p> A <tt>named-capturing group</tt> is still numbered as described in + * <a href="#gnumber">Group number</a>. + * * <p> The captured input associated with a group is always the subsequence * that the group most recently matched. If a group is evaluated a second time * because of quantification then its previously-captured value, if any, will @@ -479,9 +506,9 @@ import java.util.Arrays; * group two set to <tt>"b"</tt>. All captured input is discarded at the * beginning of each match. * - * <p> Groups beginning with <tt>(?</tt> are pure, <i>non-capturing</i> groups - * that do not capture text and do not count towards the group total. - * + * <p> Groups beginning with <tt>(?</tt> are either pure, <i>non-capturing</i> groups + * that do not capture text and do not count towards the group total, or + * <i>named-capturing</i> group. * * <h4> Unicode support </h4> * @@ -794,6 +821,12 @@ public final class Pattern */ transient int[] buffer; + /** + * Map the "name" of the "named capturing group" to its group id + * node. + */ + transient volatile Map<String, Integer> namedGroups; + /** * Temporary storage used while parsing group references. */ @@ -1467,6 +1500,7 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) { // Allocate all temporary objects here. buffer = new int[32]; groupNodes = new GroupHead[10]; + namedGroups = null; if (has(LITERAL)) { // Literal pattern handling @@ -1505,6 +1539,12 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) { compiled = true; } + Map<String, Integer> namedGroups() { + if (namedGroups == null) + namedGroups = new HashMap<String, Integer>(2); + return namedGroups; + } + /** * Used to print out a subtree of the Pattern to help with debugging. */ @@ -2156,7 +2196,22 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) { case 'h': case 'i': case 'j': + break; case 'k': + if (inclass) + break; + if (read() != '<') + throw error("\\k is not followed by '<' for named capturing group"); + String name = groupname(read()); + if (!namedGroups().containsKey(name)) + throw error("(named capturing group <"+ name+"> does not exit"); + if (create) { + if (has(CASE_INSENSITIVE)) + root = new CIBackRef(namedGroups().get(name), has(UNICODE_CASE)); + else + root = new BackRef(namedGroups().get(name)); + } + return -1; case 'l': case 'm': break; @@ -2455,6 +2510,24 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) { return p; } + /** + * Parses and returns the name of a "named capturing group", the trailing + * ">" is consumed after parsing. + */ + private String groupname(int ch) { + StringBuilder sb = new StringBuilder(); + sb.append(Character.toChars(ch)); + while (ASCII.isLower(ch=read()) || ASCII.isUpper(ch) || + ASCII.isDigit(ch)) { + sb.append(Character.toChars(ch)); + } + if (sb.length() == 0) + throw error("named capturing group has 0 length name"); + if (ch != '>') + throw error("named capturing group is missing trailing '>'"); + return sb.toString(); + } + /** * Parses a group and returns the head node of a set of nodes that process * the group. Sometimes a double return system is used where the tail is @@ -2494,6 +2567,19 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) { break; case '<': // (?<xxx) look behind ch = read(); + if (ASCII.isLower(ch) || ASCII.isUpper(ch) || ASCII.isDigit(ch)) { + // named captured group + String name = groupname(ch); + if (namedGroups().containsKey(name)) + throw error("Named capturing group <" + name + + "> is already defined"); + capturingGroup = true; + head = createGroup(false); + tail = root; + namedGroups().put(name, capturingGroupCount-1); + head.next = expr(tail); + break; + } int start = cursor; head = createGroup(true); tail = root; diff --git a/jdk/src/share/classes/java/util/zip/ZipConstants64.java b/jdk/src/share/classes/java/util/zip/ZipConstants64.java new file mode 100644 index 00000000000..1bf3b1841b4 --- /dev/null +++ b/jdk/src/share/classes/java/util/zip/ZipConstants64.java @@ -0,0 +1,77 @@ +/* + * Copyright 1995-1996 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.util.zip; + +/* + * This class defines the constants that are used by the classes + * which manipulate Zip64 files. + */ + +class ZipConstants64 { + + /* + * ZIP64 constants + */ + static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006" + static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007" + static final int ZIP64_ENDHDR = 56; // ZIP64 end header size + static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size + static final int ZIP64_EXTHDR = 24; // EXT header size + static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID + + static final int ZIP64_MAGICCOUNT = 0xFFFF; + static final long ZIP64_MAGICVAL = 0xFFFFFFFFL; + + /* + * Zip64 End of central directory (END) header field offsets + */ + static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir + static final int ZIP64_ENDVEM = 12; // version made by + static final int ZIP64_ENDVER = 14; // version needed to extract + static final int ZIP64_ENDNMD = 16; // number of this disk + static final int ZIP64_ENDDSK = 20; // disk number of start + static final int ZIP64_ENDTOD = 24; // total number of entries on this disk + static final int ZIP64_ENDTOT = 32; // total number of entries + static final int ZIP64_ENDSIZ = 40; // central directory size in bytes + static final int ZIP64_ENDOFF = 48; // offset of first CEN header + static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector + + /* + * Zip64 End of central directory locator field offsets + */ + static final int ZIP64_LOCDSK = 4; // disk number start + static final int ZIP64_LOCOFF = 8; // offset of zip64 end + static final int ZIP64_LOCTOT = 16; // total number of disks + + /* + * Zip64 Extra local (EXT) header field offsets + */ + static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value + static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte + static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte + + private ZipConstants64() {} +} diff --git a/jdk/src/share/classes/java/util/zip/ZipEntry.java b/jdk/src/share/classes/java/util/zip/ZipEntry.java index bcc27e63a0f..6c16a9adb15 100644 --- a/jdk/src/share/classes/java/util/zip/ZipEntry.java +++ b/jdk/src/share/classes/java/util/zip/ZipEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,11 +144,13 @@ class ZipEntry implements ZipConstants, Cloneable { * Sets the uncompressed size of the entry data. * @param size the uncompressed size in bytes * @exception IllegalArgumentException if the specified size is less - * than 0 or greater than 0xFFFFFFFF bytes + * than 0, is greater than 0xFFFFFFFF when + * <a href="package-summary.html#zip64">ZIP64 format</a> is not supported, + * or is less than 0 when ZIP64 is supported * @see #getSize() */ public void setSize(long size) { - if (size < 0 || size > 0xFFFFFFFFL) { + if (size < 0) { throw new IllegalArgumentException("invalid entry size"); } this.size = size; diff --git a/jdk/src/share/classes/java/util/zip/ZipInputStream.java b/jdk/src/share/classes/java/util/zip/ZipInputStream.java index e8f0ebdc5d9..1b9b93415cb 100644 --- a/jdk/src/share/classes/java/util/zip/ZipInputStream.java +++ b/jdk/src/share/classes/java/util/zip/ZipInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.io.InputStream; import java.io.IOException; import java.io.EOFException; import java.io.PushbackInputStream; +import static java.util.zip.ZipConstants64.*; /** * This class implements an input stream filter for reading files in the @@ -285,6 +286,29 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { byte[] bb = new byte[len]; readFully(bb, 0, len); e.setExtra(bb); + // extra fields are in "HeaderID(2)DataSize(2)Data... format + if (e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL) { + int off = 0; + while (off + 4 < len) { + int sz = get16(bb, off + 2); + if (get16(bb, off) == ZIP64_EXTID) { + off += 4; + // LOC extra zip64 entry MUST include BOTH original and + // compressed file size fields + if (sz < 16 || (off + sz) > len ) { + // Invalid zip64 extra fields, simply skip. Even it's + // rare, it's possible the entry size happens to be + // the magic value and it "accidnetly" has some bytes + // in extra match the id. + return e; + } + e.size = get64(bb, off); + e.csize = get64(bb, off + 8); + break; + } + off += (sz + 4); + } + } } return e; } @@ -375,18 +399,36 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { } if ((flag & 8) == 8) { /* "Data Descriptor" present */ - readFully(tmpbuf, 0, EXTHDR); - long sig = get32(tmpbuf, 0); - if (sig != EXTSIG) { // no EXTSIG present - e.crc = sig; - e.csize = get32(tmpbuf, EXTSIZ - EXTCRC); - e.size = get32(tmpbuf, EXTLEN - EXTCRC); - ((PushbackInputStream)in).unread( - tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC); + if (inf.getBytesWritten() > ZIP64_MAGICVAL || + inf.getBytesRead() > ZIP64_MAGICVAL) { + // ZIP64 format + readFully(tmpbuf, 0, ZIP64_EXTHDR); + long sig = get32(tmpbuf, 0); + if (sig != EXTSIG) { // no EXTSIG present + e.crc = sig; + 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); + } else { + e.crc = get32(tmpbuf, ZIP64_EXTCRC); + e.csize = get64(tmpbuf, ZIP64_EXTSIZ); + e.size = get64(tmpbuf, ZIP64_EXTLEN); + } } else { - e.crc = get32(tmpbuf, EXTCRC); - e.csize = get32(tmpbuf, EXTSIZ); - e.size = get32(tmpbuf, EXTLEN); + readFully(tmpbuf, 0, EXTHDR); + long sig = get32(tmpbuf, 0); + if (sig != EXTSIG) { // no EXTSIG present + e.crc = sig; + e.csize = get32(tmpbuf, EXTSIZ - EXTCRC); + e.size = get32(tmpbuf, EXTLEN - EXTCRC); + ((PushbackInputStream)in).unread( + tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC); + } else { + e.crc = get32(tmpbuf, EXTCRC); + e.csize = get32(tmpbuf, EXTSIZ); + e.size = get32(tmpbuf, EXTLEN); + } } } if (e.size != inf.getBytesWritten()) { @@ -433,6 +475,14 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { * The bytes are assumed to be in Intel (little-endian) byte order. */ private static final long get32(byte b[], int off) { - return get16(b, off) | ((long)get16(b, off+2) << 16); + return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL; + } + + /* + * Fetches signed 64-bit value from byte array at specified offset. + * The bytes are assumed to be in Intel (little-endian) byte order. + */ + private static final long get64(byte b[], int off) { + return get32(b, off) | (get32(b, off+4) << 32); } } diff --git a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java index 797a37392fe..bd44d3213cf 100644 --- a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java +++ b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.io.OutputStream; import java.io.IOException; import java.util.Vector; import java.util.HashSet; +import static java.util.zip.ZipConstants64.*; /** * This class implements an output stream filter for writing files in the @@ -343,26 +344,52 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { private void writeLOC(XEntry xentry) throws IOException { ZipEntry e = xentry.entry; int flag = xentry.flag; + int elen = (e.extra != null) ? e.extra.length : 0; + boolean hasZip64 = false; + writeInt(LOCSIG); // LOC header signature - writeShort(version(e)); // version needed to extract - writeShort(flag); // general purpose bit flag - writeShort(e.method); // compression method - writeInt(e.time); // last modification time + if ((flag & 8) == 8) { + writeShort(version(e)); // version needed to extract + writeShort(flag); // general purpose bit flag + writeShort(e.method); // compression method + writeInt(e.time); // last modification time + // store size, uncompressed size, and crc-32 in data descriptor // immediately following compressed entry data writeInt(0); writeInt(0); writeInt(0); } else { - writeInt(e.crc); // crc-32 - writeInt(e.csize); // compressed size - writeInt(e.size); // uncompressed size + if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) { + hasZip64 = true; + writeShort(45); // ver 4.5 for zip64 + } else { + writeShort(version(e)); // version needed to extract + } + writeShort(flag); // general purpose bit flag + writeShort(e.method); // compression method + writeInt(e.time); // last modification time + writeInt(e.crc); // crc-32 + if (hasZip64) { + writeInt(ZIP64_MAGICVAL); + writeInt(ZIP64_MAGICVAL); + elen += 20; //headid(2) + size(2) + size(8) + csize(8) + } else { + writeInt(e.csize); // compressed size + writeInt(e.size); // uncompressed size + } } byte[] nameBytes = getUTF8Bytes(e.name); writeShort(nameBytes.length); - writeShort(e.extra != null ? e.extra.length : 0); + writeShort(elen); writeBytes(nameBytes, 0, nameBytes.length); + if (hasZip64) { + writeShort(ZIP64_EXTID); + writeShort(16); + writeLong(e.size); + writeLong(e.csize); + } if (e.extra != null) { writeBytes(e.extra, 0, e.extra.length); } @@ -375,8 +402,13 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { private void writeEXT(ZipEntry e) throws IOException { writeInt(EXTSIG); // EXT header signature writeInt(e.crc); // crc-32 - writeInt(e.csize); // compressed size - writeInt(e.size); // uncompressed size + if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) { + writeLong(e.csize); + writeLong(e.size); + } else { + writeInt(e.csize); // compressed size + writeInt(e.size); // uncompressed size + } } /* @@ -387,18 +419,49 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ZipEntry e = xentry.entry; int flag = xentry.flag; int version = version(e); + + long csize = e.csize; + long size = e.size; + long offset = xentry.offset; + int e64len = 0; + boolean hasZip64 = false; + if (e.csize >= ZIP64_MAGICVAL) { + csize = ZIP64_MAGICVAL; + e64len += 8; // csize(8) + hasZip64 = true; + } + if (e.size >= ZIP64_MAGICVAL) { + size = ZIP64_MAGICVAL; // size(8) + e64len += 8; + hasZip64 = true; + } + if (xentry.offset >= ZIP64_MAGICVAL) { + offset = ZIP64_MAGICVAL; + e64len += 8; // offset(8) + hasZip64 = true; + } writeInt(CENSIG); // CEN header signature - writeShort(version); // version made by - writeShort(version); // version needed to extract + if (hasZip64) { + writeShort(45); // ver 4.5 for zip64 + writeShort(45); + } else { + writeShort(version); // version made by + writeShort(version); // version needed to extract + } writeShort(flag); // general purpose bit flag writeShort(e.method); // compression method writeInt(e.time); // last modification time writeInt(e.crc); // crc-32 - writeInt(e.csize); // compressed size - writeInt(e.size); // uncompressed size + writeInt(csize); // compressed size + writeInt(size); // uncompressed size byte[] nameBytes = getUTF8Bytes(e.name); writeShort(nameBytes.length); - writeShort(e.extra != null ? e.extra.length : 0); + if (hasZip64) { + // + headid(2) + datasize(2) + writeShort(e64len + 4 + (e.extra != null ? e.extra.length : 0)); + } else { + writeShort(e.extra != null ? e.extra.length : 0); + } byte[] commentBytes; if (e.comment != null) { commentBytes = getUTF8Bytes(e.comment); @@ -410,8 +473,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { writeShort(0); // starting disk number writeShort(0); // internal file attributes (unused) writeInt(0); // external file attributes (unused) - writeInt(xentry.offset); // relative offset of local header + writeInt(offset); // relative offset of local header writeBytes(nameBytes, 0, nameBytes.length); + if (hasZip64) { + writeShort(ZIP64_EXTID);// Zip64 extra + writeShort(e64len); + if (size == ZIP64_MAGICVAL) + writeLong(e.size); + if (csize == ZIP64_MAGICVAL) + writeLong(e.csize); + if (offset == ZIP64_MAGICVAL) + writeLong(xentry.offset); + } if (e.extra != null) { writeBytes(e.extra, 0, e.extra.length); } @@ -424,15 +497,50 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { * Writes end of central directory (END) header. */ private void writeEND(long off, long len) throws IOException { + boolean hasZip64 = false; + long xlen = len; + long xoff = off; + if (xlen >= ZIP64_MAGICVAL) { + xlen = ZIP64_MAGICVAL; + hasZip64 = true; + } + if (xoff >= ZIP64_MAGICVAL) { + xoff = ZIP64_MAGICVAL; + hasZip64 = true; + } int count = xentries.size(); - writeInt(ENDSIG); // END record signature - writeShort(0); // number of this disk - writeShort(0); // central directory start disk - writeShort(count); // number of directory entries on disk - writeShort(count); // total number of directory entries - writeInt(len); // length of central directory - writeInt(off); // offset of central directory - if (comment != null) { // zip file comment + if (count >= ZIP64_MAGICCOUNT) { + count = ZIP64_MAGICCOUNT; + hasZip64 = true; + } + if (hasZip64) { + long off64 = written; + //zip64 end of central directory record + writeInt(ZIP64_ENDSIG); // zip64 END record signature + writeLong(ZIP64_ENDHDR - 12); // size of zip64 end + writeShort(45); // version made by + writeShort(45); // version needed to extract + writeInt(0); // number of this disk + writeInt(0); // central directory start disk + writeLong(xentries.size()); // number of directory entires on disk + writeLong(xentries.size()); // number of directory entires + writeLong(len); // length of central directory + writeLong(off); // offset of central directory + + //zip64 end of central directory locator + writeInt(ZIP64_LOCSIG); // zip64 END locator signature + writeInt(0); // zip64 END start disk + writeLong(off64); // offset of zip64 END + writeInt(1); // total number of disks (?) + } + writeInt(ENDSIG); // END record signature + writeShort(0); // number of this disk + writeShort(0); // central directory start disk + writeShort(count); // number of directory entries on disk + writeShort(count); // total number of directory entries + writeInt(xlen); // length of central directory + writeInt(xoff); // offset of central directory + if (comment != null) { // zip file comment byte[] b = getUTF8Bytes(comment); writeShort(b.length); writeBytes(b, 0, b.length); @@ -463,6 +571,22 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { written += 4; } + /* + * Writes a 64-bit int to the output stream in little-endian byte order. + */ + private void writeLong(long v) throws IOException { + OutputStream out = this.out; + out.write((int)((v >>> 0) & 0xff)); + out.write((int)((v >>> 8) & 0xff)); + out.write((int)((v >>> 16) & 0xff)); + out.write((int)((v >>> 24) & 0xff)); + out.write((int)((v >>> 32) & 0xff)); + out.write((int)((v >>> 40) & 0xff)); + out.write((int)((v >>> 48) & 0xff)); + out.write((int)((v >>> 56) & 0xff)); + written += 8; + } + /* * Writes an array of bytes to the output stream. */ diff --git a/jdk/src/share/classes/java/util/zip/package.html b/jdk/src/share/classes/java/util/zip/package.html index d32e0fa0f4a..d4b59263678 100644 --- a/jdk/src/share/classes/java/util/zip/package.html +++ b/jdk/src/share/classes/java/util/zip/package.html @@ -45,6 +45,13 @@ input streams. Info-ZIP Application Note 970311 </a> - a detailed description of the Info-ZIP format upon which the <code>java.util.zip</code> classes are based. +<p> + <a name="zip64"> + <li>An implementation may optionally support the ZIP64(tm) format extensions + defined by the + <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT"> + PKWARE ZIP File Format Specification</a>. The ZIP64(tm) format extensions + are used to overcome the size limitations of the original ZIP format. <p> <li><a href="http://www.isi.edu/in-notes/rfc1950.txt"> ZLIB Compressed Data Format Specification version 3.3</a> @@ -70,7 +77,6 @@ input streams. <li>CRC-32 checksum is described in RFC 1952 (above) <p> <li>Adler-32 checksum is described in RFC 1950 (above) - </ul> diff --git a/jdk/src/share/classes/javax/imageio/ImageTypeSpecifier.java b/jdk/src/share/classes/javax/imageio/ImageTypeSpecifier.java index 4ba0c1062d4..184bf8870cc 100644 --- a/jdk/src/share/classes/javax/imageio/ImageTypeSpecifier.java +++ b/jdk/src/share/classes/javax/imageio/ImageTypeSpecifier.java @@ -67,126 +67,13 @@ public class ImageTypeSpecifier { * <code>BufferedImage</code> types. */ private static ImageTypeSpecifier[] BISpecifier; - + private static ColorSpace sRGB; // Initialize the standard specifiers static { - ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); + sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); BISpecifier = new ImageTypeSpecifier[BufferedImage.TYPE_BYTE_INDEXED + 1]; - - BISpecifier[BufferedImage.TYPE_CUSTOM] = null; - - BISpecifier[BufferedImage.TYPE_INT_RGB] = - createPacked(sRGB, - 0x00ff0000, - 0x0000ff00, - 0x000000ff, - 0x0, - DataBuffer.TYPE_INT, - false); - - BISpecifier[BufferedImage.TYPE_INT_ARGB] = - createPacked(sRGB, - 0x00ff0000, - 0x0000ff00, - 0x000000ff, - 0xff000000, - DataBuffer.TYPE_INT, - false); - - BISpecifier[BufferedImage.TYPE_INT_ARGB_PRE] = - createPacked(sRGB, - 0x00ff0000, - 0x0000ff00, - 0x000000ff, - 0xff000000, - DataBuffer.TYPE_INT, - true); - - BISpecifier[BufferedImage.TYPE_INT_BGR] = - createPacked(sRGB, - 0x000000ff, - 0x0000ff00, - 0x00ff0000, - 0x0, - DataBuffer.TYPE_INT, - false); - - int[] bOffsRGB = { 2, 1, 0 }; - BISpecifier[BufferedImage.TYPE_3BYTE_BGR] = - createInterleaved(sRGB, - bOffsRGB, - DataBuffer.TYPE_BYTE, - false, - false); - - int[] bOffsABGR = { 3, 2, 1, 0 }; - BISpecifier[BufferedImage.TYPE_4BYTE_ABGR] = - createInterleaved(sRGB, - bOffsABGR, - DataBuffer.TYPE_BYTE, - true, - false); - - BISpecifier[BufferedImage.TYPE_4BYTE_ABGR_PRE] = - createInterleaved(sRGB, - bOffsABGR, - DataBuffer.TYPE_BYTE, - true, - true); - - BISpecifier[BufferedImage.TYPE_USHORT_565_RGB] = - createPacked(sRGB, - 0xF800, - 0x07E0, - 0x001F, - 0x0, - DataBuffer.TYPE_USHORT, - false); - - BISpecifier[BufferedImage.TYPE_USHORT_555_RGB] = - createPacked(sRGB, - 0x7C00, - 0x03E0, - 0x001F, - 0x0, - DataBuffer.TYPE_USHORT, - false); - - BISpecifier[BufferedImage.TYPE_BYTE_GRAY] = - createGrayscale(8, - DataBuffer.TYPE_BYTE, - false); - - BISpecifier[BufferedImage.TYPE_USHORT_GRAY] = - createGrayscale(16, - DataBuffer.TYPE_USHORT, - false); - - BISpecifier[BufferedImage.TYPE_BYTE_BINARY] = - createGrayscale(1, - DataBuffer.TYPE_BYTE, - false); - - BufferedImage bi = - new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED); - IndexColorModel icm = (IndexColorModel)bi.getColorModel(); - int mapSize = icm.getMapSize(); - byte[] redLUT = new byte[mapSize]; - byte[] greenLUT = new byte[mapSize]; - byte[] blueLUT = new byte[mapSize]; - byte[] alphaLUT = new byte[mapSize]; - - icm.getReds(redLUT); - icm.getGreens(greenLUT); - icm.getBlues(blueLUT); - icm.getAlphas(alphaLUT); - - BISpecifier[BufferedImage.TYPE_BYTE_INDEXED] = - createIndexed(redLUT, greenLUT, blueLUT, alphaLUT, - 8, - DataBuffer.TYPE_BYTE); } /** @@ -1011,7 +898,7 @@ public class ImageTypeSpecifier { ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) { if (bufferedImageType >= BufferedImage.TYPE_INT_RGB && bufferedImageType <= BufferedImage.TYPE_BYTE_INDEXED) { - return BISpecifier[bufferedImageType]; + return getSpecifier(bufferedImageType); } else if (bufferedImageType == BufferedImage.TYPE_CUSTOM) { throw new IllegalArgumentException("Cannot create from TYPE_CUSTOM!"); } else { @@ -1041,7 +928,7 @@ public class ImageTypeSpecifier { if (image instanceof BufferedImage) { int bufferedImageType = ((BufferedImage)image).getType(); if (bufferedImageType != BufferedImage.TYPE_CUSTOM) { - return BISpecifier[bufferedImageType]; + return getSpecifier(bufferedImageType); } } @@ -1225,4 +1112,130 @@ public class ImageTypeSpecifier { public int hashCode() { return (9 * colorModel.hashCode()) + (14 * sampleModel.hashCode()); } + + private static ImageTypeSpecifier getSpecifier(int type) { + if (BISpecifier[type] == null) { + BISpecifier[type] = createSpecifier(type); + } + return BISpecifier[type]; + } + + private static ImageTypeSpecifier createSpecifier(int type) { + switch(type) { + case BufferedImage.TYPE_INT_RGB: + return createPacked(sRGB, + 0x00ff0000, + 0x0000ff00, + 0x000000ff, + 0x0, + DataBuffer.TYPE_INT, + false); + + case BufferedImage.TYPE_INT_ARGB: + return createPacked(sRGB, + 0x00ff0000, + 0x0000ff00, + 0x000000ff, + 0xff000000, + DataBuffer.TYPE_INT, + false); + + case BufferedImage.TYPE_INT_ARGB_PRE: + return createPacked(sRGB, + 0x00ff0000, + 0x0000ff00, + 0x000000ff, + 0xff000000, + DataBuffer.TYPE_INT, + true); + + case BufferedImage.TYPE_INT_BGR: + return createPacked(sRGB, + 0x000000ff, + 0x0000ff00, + 0x00ff0000, + 0x0, + DataBuffer.TYPE_INT, + false); + + case BufferedImage.TYPE_3BYTE_BGR: + return createInterleaved(sRGB, + new int[] { 2, 1, 0 }, + DataBuffer.TYPE_BYTE, + false, + false); + + case BufferedImage.TYPE_4BYTE_ABGR: + return createInterleaved(sRGB, + new int[] { 3, 2, 1, 0 }, + DataBuffer.TYPE_BYTE, + true, + false); + + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + return createInterleaved(sRGB, + new int[] { 3, 2, 1, 0 }, + DataBuffer.TYPE_BYTE, + true, + true); + + case BufferedImage.TYPE_USHORT_565_RGB: + return createPacked(sRGB, + 0xF800, + 0x07E0, + 0x001F, + 0x0, + DataBuffer.TYPE_USHORT, + false); + + case BufferedImage.TYPE_USHORT_555_RGB: + return createPacked(sRGB, + 0x7C00, + 0x03E0, + 0x001F, + 0x0, + DataBuffer.TYPE_USHORT, + false); + + case BufferedImage.TYPE_BYTE_GRAY: + return createGrayscale(8, + DataBuffer.TYPE_BYTE, + false); + + case BufferedImage.TYPE_USHORT_GRAY: + return createGrayscale(16, + DataBuffer.TYPE_USHORT, + false); + + case BufferedImage.TYPE_BYTE_BINARY: + return createGrayscale(1, + DataBuffer.TYPE_BYTE, + false); + + case BufferedImage.TYPE_BYTE_INDEXED: + { + + BufferedImage bi = + new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED); + IndexColorModel icm = (IndexColorModel)bi.getColorModel(); + int mapSize = icm.getMapSize(); + byte[] redLUT = new byte[mapSize]; + byte[] greenLUT = new byte[mapSize]; + byte[] blueLUT = new byte[mapSize]; + byte[] alphaLUT = new byte[mapSize]; + + icm.getReds(redLUT); + icm.getGreens(greenLUT); + icm.getBlues(blueLUT); + icm.getAlphas(alphaLUT); + + return createIndexed(redLUT, greenLUT, blueLUT, alphaLUT, + 8, + DataBuffer.TYPE_BYTE); + } + default: + throw new IllegalArgumentException("Invalid BufferedImage type!"); + } + } + } diff --git a/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormat.java b/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormat.java index 88ea8e98756..cff46177d62 100644 --- a/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormat.java +++ b/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormat.java @@ -242,8 +242,12 @@ public interface IIOMetadataFormat { /** * A constant returned by <code>getAttributeDataType</code> - * indicating that the value of an attribute is one of 'true' or - * 'false'. + * indicating that the value of an attribute is one of the boolean + * values 'true' or 'false'. + * Attribute values of type DATATYPE_BOOLEAN should be marked as + * enumerations, and the permitted values should be the string + * literal values "TRUE" or "FALSE", although a plugin may also + * recognise lower or mixed case equivalents. */ int DATATYPE_BOOLEAN = 1; diff --git a/jdk/src/share/classes/javax/swing/PopupFactory.java b/jdk/src/share/classes/javax/swing/PopupFactory.java index 753959cea1f..1eb6d1b5405 100644 --- a/jdk/src/share/classes/javax/swing/PopupFactory.java +++ b/jdk/src/share/classes/javax/swing/PopupFactory.java @@ -552,14 +552,15 @@ public class PopupFactory { boolean result = false; Component component = getComponent(); if (owner != null && component != null) { - Container parent = (Container) SwingUtilities.getRoot(owner); int popupWidth = component.getWidth(); int popupHeight = component.getHeight(); - Rectangle parentBounds = parent.getBounds(); + + Container parent = (Container) SwingUtilities.getRoot(owner); if (parent instanceof JFrame || parent instanceof JDialog || parent instanceof JWindow) { + Rectangle parentBounds = parent.getBounds(); Insets i = parent.getInsets(); parentBounds.x += i.left; parentBounds.y += i.top; @@ -577,11 +578,11 @@ public class PopupFactory { .contains(x, y, popupWidth, popupHeight); } } else if (parent instanceof JApplet) { + Rectangle parentBounds = parent.getBounds(); Point p = parent.getLocationOnScreen(); parentBounds.x = p.x; parentBounds.y = p.y; - result = parentBounds - .contains(x, y, popupWidth, popupHeight); + result = parentBounds.contains(x, y, popupWidth, popupHeight); } } return result; diff --git a/jdk/src/share/classes/javax/swing/SwingWorker.java b/jdk/src/share/classes/javax/swing/SwingWorker.java index 9eca7d535f6..263284acc4e 100644 --- a/jdk/src/share/classes/javax/swing/SwingWorker.java +++ b/jdk/src/share/classes/javax/swing/SwingWorker.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -778,35 +778,33 @@ public abstract class SwingWorker<T, V> implements RunnableFuture<T> { threadFactory); appContext.put(SwingWorker.class, executorService); - //register shutdown hook for this executor service + // Don't use ShutdownHook here as it's not enough. We should track + // AppContext disposal instead of JVM shutdown, see 6799345 for details final ExecutorService es = executorService; - final Runnable shutdownHook = - new Runnable() { - final WeakReference<ExecutorService> executorServiceRef = - new WeakReference<ExecutorService>(es); - public void run() { - final ExecutorService executorService = - executorServiceRef.get(); - if (executorService != null) { - AccessController.doPrivileged( - new PrivilegedAction<Void>() { - public Void run() { - executorService.shutdown(); - return null; + appContext.addPropertyChangeListener(AppContext.DISPOSED_PROPERTY_NAME, + new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent pce) { + boolean disposed = (Boolean)pce.getNewValue(); + if (disposed) { + final WeakReference<ExecutorService> executorServiceRef = + new WeakReference<ExecutorService>(es); + final ExecutorService executorService = + executorServiceRef.get(); + if (executorService != null) { + AccessController.doPrivileged( + new PrivilegedAction<Void>() { + public Void run() { + executorService.shutdown(); + return null; + } } - }); + ); + } } } - }; - - AccessController.doPrivileged( - new PrivilegedAction<Void>() { - public Void run() { - Runtime.getRuntime().addShutdownHook( - new Thread(shutdownHook)); - return null; - } - }); + } + ); } return executorService; } diff --git a/jdk/src/share/classes/javax/swing/TimerQueue.java b/jdk/src/share/classes/javax/swing/TimerQueue.java index 8cd7d16d87c..642bc56bac7 100644 --- a/jdk/src/share/classes/javax/swing/TimerQueue.java +++ b/jdk/src/share/classes/javax/swing/TimerQueue.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,7 +191,12 @@ class TimerQueue implements Runnable } finally { timer.getLock().unlock(); } - } catch (InterruptedException ignore) { + } catch (InterruptedException ie) { + // Shouldn't ignore InterruptedExceptions here, so AppContext + // is disposed gracefully, see 6799345 for details + if (AppContext.getAppContext().isDisposed()) { + break; + } } } } diff --git a/jdk/src/share/classes/javax/swing/UIManager.java b/jdk/src/share/classes/javax/swing/UIManager.java index 43476f2d693..bd6f6ac9144 100644 --- a/jdk/src/share/classes/javax/swing/UIManager.java +++ b/jdk/src/share/classes/javax/swing/UIManager.java @@ -58,6 +58,8 @@ import sun.awt.OSInfo; import sun.security.action.GetPropertyAction; import sun.swing.SwingUtilities2; import java.lang.reflect.Method; +import java.util.HashMap; +import sun.awt.AppContext; /** @@ -1323,19 +1325,29 @@ public class UIManager implements Serializable return; } - String metalLnf = getCrossPlatformLookAndFeelClassName(); - String lnfDefault = metalLnf; + // Try to get default LAF from system property, then from AppContext + // (6653395), then use cross-platform one by default. + String lafName = null; + HashMap lafData = + (HashMap) AppContext.getAppContext().remove("swing.lafdata"); + if (lafData != null) { + lafName = (String) lafData.remove("defaultlaf"); + } + if (lafName == null) { + lafName = getCrossPlatformLookAndFeelClassName(); + } + lafName = swingProps.getProperty(defaultLAFKey, lafName); - String lnfName = "<undefined>" ; try { - lnfName = swingProps.getProperty(defaultLAFKey, lnfDefault); - setLookAndFeel(lnfName); + setLookAndFeel(lafName); } catch (Exception e) { - try { - lnfName = swingProps.getProperty(defaultLAFKey, metalLnf); - setLookAndFeel(lnfName); - } catch (Exception e2) { - throw new Error("can't load " + lnfName); + throw new Error("Cannot load " + lafName); + } + + // Set any properties passed through AppContext (6653395). + if (lafData != null) { + for (Object key: lafData.keySet()) { + UIManager.put(key, lafData.get(key)); } } } diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java index 8cff0a3e7cb..b823553b627 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -27,6 +27,7 @@ package javax.swing.plaf.basic; import java.io.File; import java.util.*; +import java.util.concurrent.Callable; import javax.swing.*; import javax.swing.filechooser.*; import javax.swing.event.*; @@ -223,113 +224,115 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh this.fid = fid; } - private void invokeLater(DoChangeContents runnable) { - runnables.addElement(runnable); - SwingUtilities.invokeLater(runnable); - } - public void run() { run0(); setBusy(false, fid); } public void run0() { - FileSystemView fileSystem = filechooser.getFileSystemView(); + DoChangeContents doChangeContents = ShellFolder.getInvoker().invoke(new Callable<DoChangeContents>() { + public DoChangeContents call() throws Exception { + FileSystemView fileSystem = filechooser.getFileSystemView(); - File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled()); + File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled()); - Vector<File> acceptsList = new Vector<File>(); + Vector<File> acceptsList = new Vector<File>(); - if (isInterrupted()) { - return; - } + if (isInterrupted()) { + return null; + } - // run through the file list, add directories and selectable files to fileCache - for (File file : list) { - if (filechooser.accept(file)) { - acceptsList.addElement(file); - } - } + // run through the file list, add directories and selectable files to fileCache + for (File file : list) { + if (filechooser.accept(file)) { + acceptsList.addElement(file); + } + } - if (isInterrupted()) { - return; - } + if (isInterrupted()) { + return null; + } - // First sort alphabetically by filename - sort(acceptsList); + // First sort alphabetically by filename + sort(acceptsList); - Vector<File> newDirectories = new Vector<File>(50); - Vector<File> newFiles = new Vector<File>(); - // run through list grabbing directories in chunks of ten - for(int i = 0; i < acceptsList.size(); i++) { - File f = acceptsList.elementAt(i); - boolean isTraversable = filechooser.isTraversable(f); - if (isTraversable) { - newDirectories.addElement(f); - } else if (!isTraversable && filechooser.isFileSelectionEnabled()) { - newFiles.addElement(f); - } - if(isInterrupted()) { - return; - } - } + Vector<File> newDirectories = new Vector<File>(50); + Vector<File> newFiles = new Vector<File>(); + // run through list grabbing directories in chunks of ten + for (int i = 0; i < acceptsList.size(); i++) { + File f = acceptsList.elementAt(i); + boolean isTraversable = filechooser.isTraversable(f); + if (isTraversable) { + newDirectories.addElement(f); + } else if (!isTraversable && filechooser.isFileSelectionEnabled()) { + newFiles.addElement(f); + } + if (isInterrupted()) { + return null; + } + } - Vector<File> newFileCache = new Vector<File>(newDirectories); - newFileCache.addAll(newFiles); + Vector<File> newFileCache = new Vector<File>(newDirectories); + newFileCache.addAll(newFiles); - int newSize = newFileCache.size(); - int oldSize = fileCache.size(); + int newSize = newFileCache.size(); + int oldSize = fileCache.size(); - if (newSize > oldSize) { - //see if interval is added - int start = oldSize; - int end = newSize; - for (int i = 0; i < oldSize; i++) { - if (!newFileCache.get(i).equals(fileCache.get(i))) { - start = i; - for (int j = i; j < newSize; j++) { - if (newFileCache.get(j).equals(fileCache.get(i))) { - end = j; + if (newSize > oldSize) { + //see if interval is added + int start = oldSize; + int end = newSize; + for (int i = 0; i < oldSize; i++) { + if (!newFileCache.get(i).equals(fileCache.get(i))) { + start = i; + for (int j = i; j < newSize; j++) { + if (newFileCache.get(j).equals(fileCache.get(i))) { + end = j; + break; + } + } break; } } - break; + if (start >= 0 && end > start + && newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) { + if (isInterrupted()) { + return null; + } + return new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid); + } + } else if (newSize < oldSize) { + //see if interval is removed + int start = -1; + int end = -1; + for (int i = 0; i < newSize; i++) { + if (!newFileCache.get(i).equals(fileCache.get(i))) { + start = i; + end = i + oldSize - newSize; + break; + } + } + if (start >= 0 && end > start + && fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) { + if (isInterrupted()) { + return null; + } + return new DoChangeContents(null, 0, new Vector(fileCache.subList(start, end)), start, fid); + } } - } - if (start >= 0 && end > start - && newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) { - if(isInterrupted()) { - return; + if (!fileCache.equals(newFileCache)) { + if (isInterrupted()) { + cancelRunnables(runnables); + } + return new DoChangeContents(newFileCache, 0, fileCache, 0, fid); } - invokeLater(new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid)); - newFileCache = null; + return null; } - } else if (newSize < oldSize) { - //see if interval is removed - int start = -1; - int end = -1; - for (int i = 0; i < newSize; i++) { - if (!newFileCache.get(i).equals(fileCache.get(i))) { - start = i; - end = i + oldSize - newSize; - break; - } - } - if (start >= 0 && end > start - && fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) { - if(isInterrupted()) { - return; - } - invokeLater(new DoChangeContents(null, 0, new Vector<File>(fileCache.subList(start, end)), - start, fid)); - newFileCache = null; - } - } - if (newFileCache != null && !fileCache.equals(newFileCache)) { - if (isInterrupted()) { - cancelRunnables(runnables); - } - invokeLater(new DoChangeContents(newFileCache, 0, fileCache, 0, fid)); + }); + + if (doChangeContents != null) { + runnables.addElement(doChangeContents); + SwingUtilities.invokeLater(doChangeContents); } } diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java index 864ad13264a..0a858d41c18 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java @@ -1004,47 +1004,62 @@ public class BasicSliderUI extends SliderUI{ g.setColor(DefaultLookup.getColor(slider, this, "Slider.tickColor", Color.black)); if ( slider.getOrientation() == JSlider.HORIZONTAL ) { - g.translate( 0, tickBounds.y); + g.translate(0, tickBounds.y); - int value = slider.getMinimum(); - int xPos; + if (slider.getMinorTickSpacing() > 0) { + int value = slider.getMinimum(); - if ( slider.getMinorTickSpacing() > 0 ) { while ( value <= slider.getMaximum() ) { - xPos = xPositionForValue( value ); + int xPos = xPositionForValue(value); paintMinorTickForHorizSlider( g, tickBounds, xPos ); + + // Overflow checking + if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) { + break; + } + value += slider.getMinorTickSpacing(); } } - if ( slider.getMajorTickSpacing() > 0 ) { - value = slider.getMinimum(); + if (slider.getMajorTickSpacing() > 0) { + int value = slider.getMinimum(); while ( value <= slider.getMaximum() ) { - xPos = xPositionForValue( value ); + int xPos = xPositionForValue(value); paintMajorTickForHorizSlider( g, tickBounds, xPos ); + + // Overflow checking + if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) { + break; + } + value += slider.getMajorTickSpacing(); } } g.translate( 0, -tickBounds.y); - } - else { - g.translate(tickBounds.x, 0); + } else { + g.translate(tickBounds.x, 0); - int value = slider.getMinimum(); - int yPos; - - if ( slider.getMinorTickSpacing() > 0 ) { + if (slider.getMinorTickSpacing() > 0) { int offset = 0; if(!BasicGraphicsUtils.isLeftToRight(slider)) { offset = tickBounds.width - tickBounds.width / 2; g.translate(offset, 0); } - while ( value <= slider.getMaximum() ) { - yPos = yPositionForValue( value ); + int value = slider.getMinimum(); + + while (value <= slider.getMaximum()) { + int yPos = yPositionForValue(value); paintMinorTickForVertSlider( g, tickBounds, yPos ); + + // Overflow checking + if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) { + break; + } + value += slider.getMinorTickSpacing(); } @@ -1053,15 +1068,22 @@ public class BasicSliderUI extends SliderUI{ } } - if ( slider.getMajorTickSpacing() > 0 ) { - value = slider.getMinimum(); + if (slider.getMajorTickSpacing() > 0) { if(!BasicGraphicsUtils.isLeftToRight(slider)) { g.translate(2, 0); } - while ( value <= slider.getMaximum() ) { - yPos = yPositionForValue( value ); + int value = slider.getMinimum(); + + while (value <= slider.getMaximum()) { + int yPos = yPositionForValue(value); paintMajorTickForVertSlider( g, tickBounds, yPos ); + + // Overflow checking + if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) { + break; + } + value += slider.getMajorTickSpacing(); } @@ -1775,8 +1797,6 @@ public class BasicSliderUI extends SliderUI{ thumbMiddle = thumbLeft + halfThumbWidth; slider.setValue(valueForXPosition(thumbMiddle)); break; - default: - return; } } diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java b/jdk/src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java index 4636e07c4fd..58063f585b2 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -38,6 +38,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.*; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.accessibility.*; import sun.awt.shell.ShellFolder; @@ -937,7 +939,11 @@ public class MetalFileChooserUI extends BasicFileChooserUI { File[] baseFolders; if (useShellFolder) { - baseFolders = (File[])ShellFolder.get("fileChooserComboBoxFolders"); + baseFolders = AccessController.doPrivileged(new PrivilegedAction<File[]>() { + public File[] run() { + return (File[]) ShellFolder.get("fileChooserComboBoxFolders"); + } + }); } else { baseFolders = fsv.getRoots(); } diff --git a/jdk/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java b/jdk/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java index 975056a1c69..ac91419f115 100644 --- a/jdk/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java @@ -233,7 +233,7 @@ class SynthTabbedPaneUI extends BasicTabbedPaneUI implements SynthUI, PropertyCh tabContext.getStyle().getGraphicsUtils(tabContext).layoutText( tabContext, metrics, title, icon, SwingUtilities.CENTER, SwingUtilities.CENTER, SwingUtilities.LEADING, - SwingUtilities.TRAILING, calcRect, + SwingUtilities.CENTER, calcRect, iconRect, textRect, textIconGap); return textRect.y + metrics.getAscent() + getBaselineOffset(); } @@ -426,7 +426,7 @@ class SynthTabbedPaneUI extends BasicTabbedPaneUI implements SynthUI, PropertyCh ss.getStyle().getGraphicsUtils(ss).layoutText(ss, metrics, title, icon, SwingUtilities.CENTER, SwingUtilities.CENTER, - SwingUtilities.LEADING, SwingUtilities.TRAILING, + SwingUtilities.LEADING, SwingUtilities.CENTER, tabRect, iconRect, textRect, textIconGap); tabPane.putClientProperty("html", null); diff --git a/jdk/src/share/classes/javax/swing/text/GlyphView.java b/jdk/src/share/classes/javax/swing/text/GlyphView.java index 3cb4efe59f9..364fd69e8ee 100644 --- a/jdk/src/share/classes/javax/swing/text/GlyphView.java +++ b/jdk/src/share/classes/javax/swing/text/GlyphView.java @@ -30,6 +30,7 @@ import javax.swing.event.*; import java.util.BitSet; import java.util.Locale; +import javax.swing.UIManager; import sun.swing.SwingUtilities2; /** @@ -382,11 +383,10 @@ public class GlyphView extends View implements TabableView, Cloneable { Color bg = getBackground(); Color fg = getForeground(); - if (c instanceof JTextComponent) { - JTextComponent tc = (JTextComponent) c; - if (!tc.isEnabled()) { - fg = tc.getDisabledTextColor(); - } + if (c != null && ! c.isEnabled()) { + fg = (c instanceof JTextComponent ? + ((JTextComponent)c).getDisabledTextColor() : + UIManager.getColor("textInactiveText")); } if (bg != null) { g.setColor(bg); diff --git a/jdk/src/share/classes/javax/swing/text/html/ImageView.java b/jdk/src/share/classes/javax/swing/text/html/ImageView.java index 4b645b6a725..0831e2567cd 100644 --- a/jdk/src/share/classes/javax/swing/text/html/ImageView.java +++ b/jdk/src/share/classes/javax/swing/text/html/ImageView.java @@ -25,9 +25,7 @@ package javax.swing.text.html; import java.awt.*; -import java.awt.event.*; import java.awt.image.ImageObserver; -import java.io.*; import java.net.*; import java.util.Dictionary; import javax.swing.*; @@ -97,6 +95,7 @@ public class ImageView extends View { private AttributeSet attr; private Image image; + private Image disabledImage; private int width; private int height; /** Bitmask containing some of the above bitmask values. Because the @@ -193,6 +192,17 @@ public class ImageView extends View { return image; } + private Image getImage(boolean enabled) { + Image img = getImage(); + if (! enabled) { + if (disabledImage == null) { + disabledImage = GrayFilter.createDisabledImage(img); + } + img = disabledImage; + } + return img; + } + /** * Sets how the image is loaded. If <code>newValue</code> is true, * the image we be loaded when first asked for, otherwise it will @@ -338,8 +348,6 @@ public class ImageView extends View { Rectangle rect = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds(); - - Image image = getImage(); Rectangle clip = g.getClipBounds(); fBounds.setBounds(rect); @@ -350,29 +358,29 @@ public class ImageView extends View { rect.width - leftInset - rightInset, rect.height - topInset - bottomInset); } - if (image != null) { - if (!hasPixels(image)) { - // No pixels yet, use the default - Icon icon = (image == null) ? getNoImageIcon() : - getLoadingImageIcon(); + Container host = getContainer(); + Image img = getImage(host == null || host.isEnabled()); + if (img != null) { + if (! hasPixels(img)) { + // No pixels yet, use the default + Icon icon = getLoadingImageIcon(); if (icon != null) { - icon.paintIcon(getContainer(), g, rect.x + leftInset, - rect.y + topInset); + icon.paintIcon(host, g, + rect.x + leftInset, rect.y + topInset); } } else { // Draw the image - g.drawImage(image, rect.x + leftInset, rect.y + topInset, + g.drawImage(img, rect.x + leftInset, rect.y + topInset, width, height, imageObserver); } } else { Icon icon = getNoImageIcon(); - if (icon != null) { - icon.paintIcon(getContainer(), g, rect.x + leftInset, - rect.y + topInset); + icon.paintIcon(host, g, + rect.x + leftInset, rect.y + topInset); } View view = getAltView(); // Paint the view representing the alt text, if its non-null @@ -855,7 +863,9 @@ public class ImageView extends View { // it will pick up the new height/width, if necessary. public boolean imageUpdate(Image img, int flags, int x, int y, int newWidth, int newHeight ) { - if (image == null || image != img || getParent() == null) { + if (img != image && img != disabledImage || + image == null || getParent() == null) { + return false; } @@ -873,6 +883,8 @@ public class ImageView extends View { if ((state & HEIGHT_FLAG) != HEIGHT_FLAG) { height = DEFAULT_HEIGHT; } + } else { + disabledImage = null; } if ((state & LOADING_FLAG) == LOADING_FLAG) { // No need to resize or repaint, still in the process @@ -885,38 +897,37 @@ public class ImageView extends View { return false; } - // Resize image if necessary: - short changed = 0; - if ((flags & ImageObserver.HEIGHT) != 0 && !getElement(). - getAttributes().isDefined(HTML.Attribute.HEIGHT)) { - changed |= 1; - } - if ((flags & ImageObserver.WIDTH) != 0 && !getElement(). - getAttributes().isDefined(HTML.Attribute.WIDTH)) { - changed |= 2; - } + if (image == img) { + // Resize image if necessary: + short changed = 0; + if ((flags & ImageObserver.HEIGHT) != 0 && !getElement(). + getAttributes().isDefined(HTML.Attribute.HEIGHT)) { + changed |= 1; + } + if ((flags & ImageObserver.WIDTH) != 0 && !getElement(). + getAttributes().isDefined(HTML.Attribute.WIDTH)) { + changed |= 2; + } - synchronized(ImageView.this) { - if (image != img) { - return false; + synchronized(ImageView.this) { + if ((changed & 1) == 1 && (state & WIDTH_FLAG) == 0) { + width = newWidth; + } + if ((changed & 2) == 2 && (state & HEIGHT_FLAG) == 0) { + height = newHeight; + } + if ((state & LOADING_FLAG) == LOADING_FLAG) { + // No need to resize or repaint, still in the process of + // loading. + return true; + } } - if ((changed & 1) == 1 && (state & WIDTH_FLAG) == 0) { - width = newWidth; - } - if ((changed & 2) == 2 && (state & HEIGHT_FLAG) == 0) { - height = newHeight; - } - if ((state & LOADING_FLAG) == LOADING_FLAG) { - // No need to resize or repaint, still in the process of - // loading. + if (changed != 0) { + // May need to resize myself, asynchronously: + safePreferenceChanged(); return true; } } - if (changed != 0) { - // May need to resize myself, asynchronously: - safePreferenceChanged(); - return true; - } // Repaint when done or when new pixels arrive: if ((flags & (FRAMEBITS|ALLBITS)) != 0) { diff --git a/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java b/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java index 0cf18047872..c2a07739a04 100644 --- a/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java +++ b/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java @@ -31,6 +31,7 @@ import java.io.*; import java.net.*; import javax.swing.Icon; import javax.swing.ImageIcon; +import javax.swing.UIManager; import javax.swing.border.*; import javax.swing.event.ChangeListener; import javax.swing.text.*; @@ -2161,6 +2162,7 @@ public class StyleSheet extends StyleContext { */ public void paint(Graphics g, float x, float y, float w, float h, View v, int item) { View cv = v.getView(item); + Container host = v.getContainer(); Object name = cv.getElement().getAttributes().getAttribute (StyleConstants.NameAttribute); // Only draw something if the View is a list item. This won't @@ -2171,7 +2173,7 @@ public class StyleSheet extends StyleContext { } // deside on what side draw bullets, etc. isLeftToRight = - cv.getContainer().getComponentOrientation().isLeftToRight(); + host.getComponentOrientation().isLeftToRight(); // How the list indicator is aligned is not specified, it is // left up to the UA. IE and NS differ on this behavior. @@ -2200,15 +2202,15 @@ public class StyleSheet extends StyleContext { } // set the color of a decoration - if (ss != null) { - g.setColor(ss.getForeground(cv.getAttributes())); - } else { - g.setColor(Color.black); - } + Color c = (host.isEnabled() + ? (ss != null + ? ss.getForeground(cv.getAttributes()) + : host.getForeground()) + : UIManager.getColor("textInactiveText")); + g.setColor(c); if (img != null) { - drawIcon(g, (int) x, (int) y, (int) w, (int) h, align, - v.getContainer()); + drawIcon(g, (int) x, (int) y, (int) w, (int) h, align, host); return; } CSS.Value childtype = getChildType(cv); diff --git a/jdk/src/share/classes/sun/awt/FontConfiguration.java b/jdk/src/share/classes/sun/awt/FontConfiguration.java index 6349aa778ea..4504af24e9d 100644 --- a/jdk/src/share/classes/sun/awt/FontConfiguration.java +++ b/jdk/src/share/classes/sun/awt/FontConfiguration.java @@ -98,7 +98,7 @@ public abstract class FontConfiguration { if (!inited) { this.preferLocaleFonts = false; this.preferPropFonts = false; - fontConfig = this; /* static initialization */ + setFontConfiguration(); readFontConfigFile(fontConfigFile); initFontConfig(); inited = true; @@ -1244,6 +1244,10 @@ public abstract class FontConfiguration { return fontConfig; } + protected void setFontConfiguration() { + fontConfig = this; /* static initialization */ + } + ////////////////////////////////////////////////////////////////////// // FontConfig data tables and the index constants in binary file // ////////////////////////////////////////////////////////////////////// diff --git a/jdk/src/share/classes/sun/awt/shell/ShellFolder.java b/jdk/src/share/classes/sun/awt/shell/ShellFolder.java index 16c1b12cb80..0e75ac183dc 100644 --- a/jdk/src/share/classes/sun/awt/shell/ShellFolder.java +++ b/jdk/src/share/classes/sun/awt/shell/ShellFolder.java @@ -31,6 +31,7 @@ import java.awt.Toolkit; import java.io.*; import java.io.FileNotFoundException; import java.util.*; +import java.util.concurrent.Callable; /** * @author Michael Martak @@ -461,6 +462,35 @@ public abstract class ShellFolder extends File { return null; } + private static Invoker invoker; + + /** + * Provides the single access point to the {@link Invoker}. It is guaranteed that the value + * returned by this method will be always the same. + * + * @return the singleton instance of {@link Invoker} + */ + public static Invoker getInvoker() { + if (invoker == null) { + invoker = shellFolderManager.createInvoker(); + } + return invoker; + } + + /** + * Interface allowing to invoke tasks in different environments on different platforms. + */ + public static interface Invoker { + /** + * Invokes a callable task. If the {@code task} throws a checked exception, + * it will be wrapped into a {@link RuntimeException} + * + * @param task a task to invoke + * @return the result of {@code task}'s invokation + */ + <T> T invoke(Callable<T> task); + } + /** * Provides a default comparator for the default column set */ diff --git a/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java b/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java index 8fb15bf0cf8..dc8901f7bc5 100644 --- a/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java +++ b/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java @@ -27,6 +27,7 @@ package sun.awt.shell; import java.io.File; import java.io.FileNotFoundException; +import java.util.concurrent.Callable; /** * @author Michael Martak @@ -96,9 +97,23 @@ class ShellFolderManager { } public boolean isFileSystemRoot(File dir) { - if (dir instanceof ShellFolder && !((ShellFolder)dir).isFileSystem()) { + if (dir instanceof ShellFolder && !((ShellFolder) dir).isFileSystem()) { return false; } return (dir.getParentFile() == null); } + + protected ShellFolder.Invoker createInvoker() { + return new DirectInvoker(); + } + + private static class DirectInvoker implements ShellFolder.Invoker { + public <T> T invoke(Callable<T> task) { + try { + return task.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } } diff --git a/jdk/src/share/classes/sun/beans/editors/ColorEditor.java b/jdk/src/share/classes/sun/beans/editors/ColorEditor.java index a3610e0ee2e..55dd9137be1 100644 --- a/jdk/src/share/classes/sun/beans/editors/ColorEditor.java +++ b/jdk/src/share/classes/sun/beans/editors/ColorEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ import java.awt.*; import java.beans.*; public class ColorEditor extends Panel implements PropertyEditor { + private static final long serialVersionUID = 1781257185164716054L; + public ColorEditor() { setLayout(null); diff --git a/jdk/src/share/classes/sun/beans/editors/FontEditor.java b/jdk/src/share/classes/sun/beans/editors/FontEditor.java index 88de9aea48f..04d4c187e22 100644 --- a/jdk/src/share/classes/sun/beans/editors/FontEditor.java +++ b/jdk/src/share/classes/sun/beans/editors/FontEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.awt.*; import java.beans.*; public class FontEditor extends Panel implements java.beans.PropertyEditor { + private static final long serialVersionUID = 6732704486002715933L; public FontEditor() { setLayout(null); diff --git a/jdk/src/share/classes/sun/font/FileFontStrike.java b/jdk/src/share/classes/sun/font/FileFontStrike.java index dab135e96d2..11dff8a20c1 100644 --- a/jdk/src/share/classes/sun/font/FileFontStrike.java +++ b/jdk/src/share/classes/sun/font/FileFontStrike.java @@ -26,6 +26,7 @@ package sun.font; import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; import java.awt.Font; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; @@ -842,8 +843,36 @@ public class FileFontStrike extends PhysicalStrike { return fileFont.getGlyphOutlineBounds(pScalerContext, glyphCode); } + private + WeakReference<ConcurrentHashMap<Integer,GeneralPath>> outlineMapRef; + GeneralPath getGlyphOutline(int glyphCode, float x, float y) { - return fileFont.getGlyphOutline(pScalerContext, glyphCode, x, y); + + GeneralPath gp = null; + ConcurrentHashMap<Integer, GeneralPath> outlineMap = null; + + if (outlineMapRef != null) { + outlineMap = outlineMapRef.get(); + if (outlineMap != null) { + gp = (GeneralPath)outlineMap.get(glyphCode); + } + } + + if (gp == null) { + gp = fileFont.getGlyphOutline(pScalerContext, glyphCode, 0, 0); + if (outlineMap == null) { + outlineMap = new ConcurrentHashMap<Integer, GeneralPath>(); + outlineMapRef = + new WeakReference + <ConcurrentHashMap<Integer,GeneralPath>>(outlineMap); + } + outlineMap.put(glyphCode, gp); + } + gp = (GeneralPath)gp.clone(); // mutable! + if (x != 0f || y != 0f) { + gp.transform(AffineTransform.getTranslateInstance(x, y)); + } + return gp; } GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) { diff --git a/jdk/src/share/classes/sun/font/FontManager.java b/jdk/src/share/classes/sun/font/FontManager.java index f709f381ada..a8b721daffc 100644 --- a/jdk/src/share/classes/sun/font/FontManager.java +++ b/jdk/src/share/classes/sun/font/FontManager.java @@ -1601,18 +1601,27 @@ public final class FontManager { /* Path may be absolute or a base file name relative to one of * the platform font directories */ - private static String getPathName(String s) { + private static String getPathName(final String s) { File f = new File(s); if (f.isAbsolute()) { return s; } else if (pathDirs.length==1) { return pathDirs[0] + File.separator + s; } else { - for (int p=0; p<pathDirs.length; p++) { - f = new File(pathDirs[p] + File.separator + s); - if (f.exists()) { - return f.getAbsolutePath(); - } + String path = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction<String>() { + public String run() { + for (int p=0; p<pathDirs.length; p++) { + File f = new File(pathDirs[p] +File.separator+ s); + if (f.exists()) { + return f.getAbsolutePath(); + } + } + return null; + } + }); + if (path != null) { + return path; } } return s; // shouldn't happen, but harmless diff --git a/jdk/src/share/classes/sun/font/GlyphLayout.java b/jdk/src/share/classes/sun/font/GlyphLayout.java index 18ebec85a02..91162cb1c57 100644 --- a/jdk/src/share/classes/sun/font/GlyphLayout.java +++ b/jdk/src/share/classes/sun/font/GlyphLayout.java @@ -338,6 +338,8 @@ public final class GlyphLayout { cache = new ConcurrentHashMap<SDKey, SDCache>(10); cacheRef = new SoftReference<ConcurrentHashMap<SDKey, SDCache>>(cache); + } else if (cache.size() >= 512) { + cache.clear(); } cache.put(key, res); } diff --git a/jdk/src/share/classes/sun/font/StrikeCache.java b/jdk/src/share/classes/sun/font/StrikeCache.java index 560be3af2cd..56539e7489f 100644 --- a/jdk/src/share/classes/sun/font/StrikeCache.java +++ b/jdk/src/share/classes/sun/font/StrikeCache.java @@ -232,6 +232,16 @@ public final class StrikeCache { if (disposer.pScalerContext != 0L) { freeLongMemory(new long[0], disposer.pScalerContext); } + } else if (disposer.pScalerContext != 0L) { + /* Rarely a strike may have been created that never cached + * any glyphs. In this case we still want to free the scaler + * context. + */ + if (FontManager.longAddresses) { + freeLongMemory(new long[0], disposer.pScalerContext); + } else { + freeIntMemory(new int[0], disposer.pScalerContext); + } } } diff --git a/jdk/src/share/classes/sun/java2d/cmm/ProfileActivator.java b/jdk/src/share/classes/sun/java2d/cmm/ProfileActivator.java index 32c4e477fb9..f5a28f84232 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/ProfileActivator.java +++ b/jdk/src/share/classes/sun/java2d/cmm/ProfileActivator.java @@ -25,6 +25,7 @@ package sun.java2d.cmm; +import java.awt.color.ProfileDataException; /** * An interface to allow the ProfileDeferralMgr to activate a @@ -35,6 +36,6 @@ public interface ProfileActivator { /** * Activate a previously deferred ICC_Profile object. */ - public void activate(); + public void activate() throws ProfileDataException; } diff --git a/jdk/src/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java b/jdk/src/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java index 41804c3fd9b..116f339da0a 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java +++ b/jdk/src/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java @@ -25,6 +25,7 @@ package sun.java2d.cmm; +import java.awt.color.ProfileDataException; import java.util.Vector; @@ -39,7 +40,7 @@ import java.util.Vector; public class ProfileDeferralMgr { public static boolean deferring = true; - private static Vector aVector; + private static Vector<ProfileActivator> aVector; /** * Records a ProfileActivator object whose activate method will @@ -51,7 +52,7 @@ public class ProfileDeferralMgr { return; } if (aVector == null) { - aVector = new Vector(3, 3); + aVector = new Vector<ProfileActivator>(3, 3); } aVector.addElement(pa); return; @@ -89,8 +90,26 @@ public class ProfileDeferralMgr { return; } n = aVector.size(); - for (i = 0; i < n; i++) { - ((ProfileActivator) aVector.get(i)).activate(); + for (ProfileActivator pa : aVector) { + try { + pa.activate(); + } catch (ProfileDataException e) { + /* + * Ignore profile activation error for now: + * such exception is pssible due to absence + * or corruption of standard color profile. + * As for now we expect all profiles should + * be shiped with jre and presence of this + * exception is indication of some configuration + * problem in jre installation. + * + * NB: we still are greedy loading deferred profiles + * and load them all if any of them is needed. + * Therefore broken profile (if any) might be never used. + * If there will be attempt to use broken profile then + * it will result in CMMException. + */ + } } aVector.removeAllElements(); aVector = null; diff --git a/jdk/src/share/classes/sun/java2d/pisces/Dasher.java b/jdk/src/share/classes/sun/java2d/pisces/Dasher.java index 81c92f44a60..99215e01b8e 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/Dasher.java +++ b/jdk/src/share/classes/sun/java2d/pisces/Dasher.java @@ -120,7 +120,7 @@ public class Dasher extends LineSink { // Normalize so 0 <= phase < dash[0] int idx = 0; - dashOn = false; + dashOn = true; int d; while (phase >= (d = dash[idx])) { phase -= d; diff --git a/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java b/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java index 7f55e886c69..12296daad2c 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java +++ b/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java @@ -245,6 +245,7 @@ public class PiscesRenderingEngine extends RenderingEngine { FloatToS15_16(coords[1])); break; case PathIterator.SEG_CLOSE: + lsink.lineJoin(); lsink.close(); break; default: diff --git a/jdk/src/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/share/classes/sun/launcher/LauncherHelper.java index 3951bcfeb12..76db55ebd34 100644 --- a/jdk/src/share/classes/sun/launcher/LauncherHelper.java +++ b/jdk/src/share/classes/sun/launcher/LauncherHelper.java @@ -1,6 +1,5 @@ - /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,18 +54,24 @@ public enum LauncherHelper { INSTANCE; private static final String defaultBundleName = "sun.launcher.resources.launcher"; - private static ResourceBundle javarb = - ResourceBundle.getBundle(defaultBundleName); private static final String MAIN_CLASS = "Main-Class"; private static StringBuilder outBuf = new StringBuilder(); + private static ResourceBundle javarb = null; + private static synchronized ResourceBundle getLauncherResourceBundle() { + if (javarb == null) { + javarb = ResourceBundle.getBundle(defaultBundleName); + } + return javarb; + } + /** * A private helper method to get a localized message and also * apply any arguments that we might pass. */ private static String getLocalizedMessage(String key, Object... args) { - String msg = javarb.getString(key); + String msg = getLauncherResourceBundle().getString(key); return (args != null) ? MessageFormat.format(msg, args) : msg; } diff --git a/jdk/src/share/classes/sun/management/Agent.java b/jdk/src/share/classes/sun/management/Agent.java index e247412ba91..edc53f93c6e 100644 --- a/jdk/src/share/classes/sun/management/Agent.java +++ b/jdk/src/share/classes/sun/management/Agent.java @@ -31,9 +31,9 @@ import java.io.FileInputStream; import java.io.BufferedInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import java.util.Properties; -import java.util.Enumeration; import java.util.ResourceBundle; import java.util.MissingResourceException; import java.lang.management.ManagementFactory; @@ -41,7 +41,6 @@ import java.lang.reflect.Method; import javax.management.remote.JMXConnectorServer; -import sun.management.snmp.AdaptorBootstrap; import sun.management.jmxremote.ConnectorBootstrap; import static sun.management.AgentConfigurationError.*; import sun.misc.VMSupport; @@ -69,6 +68,9 @@ public class Agent { private static final String LOCAL_CONNECTOR_ADDRESS_PROP = "com.sun.management.jmxremote.localConnectorAddress"; + private static final String SNMP_ADAPTOR_BOOTSTRAP_CLASS_NAME = + "sun.management.snmp.AdaptorBootstrap"; + // invoked by -javaagent or -Dcom.sun.management.agent.class public static void premain(String args) throws Exception { agentmain(args); @@ -128,7 +130,7 @@ public class Agent { try { if (snmpPort != null) { - AdaptorBootstrap.initialize(snmpPort, props); + loadSnmpAgent(snmpPort, props); } /* @@ -204,6 +206,36 @@ public class Agent { return mgmtProps; } + private static void loadSnmpAgent(String snmpPort, Properties props) { + try { + // invoke the following through reflection: + // AdaptorBootstrap.initialize(snmpPort, props); + final Class<?> adaptorClass = + Class.forName(SNMP_ADAPTOR_BOOTSTRAP_CLASS_NAME,true,null); + final Method initializeMethod = + adaptorClass.getMethod("initialize", + String.class, Properties.class); + initializeMethod.invoke(null,snmpPort,props); + } catch (ClassNotFoundException x) { + // The SNMP packages are not present: throws an exception. + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,x); + } catch (NoSuchMethodException x) { + // should not happen... + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,x); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof RuntimeException) + throw (RuntimeException) cause; + else if (cause instanceof Error) + throw (Error) cause; + // should not happen... + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,cause); + } catch (IllegalAccessException x) { + // should not happen... + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,x); + } + } + // read config file and initialize the properties private static void readConfiguration(String fname, Properties p) { if (fname == null) { diff --git a/jdk/src/share/classes/sun/misc/ClassLoaderUtil.java b/jdk/src/share/classes/sun/misc/ClassLoaderUtil.java index b57dfccbb5c..b71a89dfd33 100644 --- a/jdk/src/share/classes/sun/misc/ClassLoaderUtil.java +++ b/jdk/src/share/classes/sun/misc/ClassLoaderUtil.java @@ -77,8 +77,6 @@ public class ClassLoaderUtil { jarsClosed.clear(); } - System.out.println ("classLoader = " + classLoader); - System.out.println ("SharedSecrets.getJavaNetAccess()="+SharedSecrets.getJavaNetAccess()); URLClassPath ucp = SharedSecrets.getJavaNetAccess() .getURLClassPath(classLoader); ArrayList loaders = ucp.loaders; diff --git a/jdk/src/share/classes/sun/misc/FloatingDecimal.java b/jdk/src/share/classes/sun/misc/FloatingDecimal.java index 46e4e55bc18..f0316ff5631 100644 --- a/jdk/src/share/classes/sun/misc/FloatingDecimal.java +++ b/jdk/src/share/classes/sun/misc/FloatingDecimal.java @@ -1867,10 +1867,16 @@ public class FloatingDecimal{ * Grammar is compatible with hexadecimal floating-point constants * described in section 6.4.4.2 of the C99 specification. */ - private static Pattern hexFloatPattern = Pattern.compile( + private static Pattern hexFloatPattern = null; + private static synchronized Pattern getHexFloatPattern() { + if (hexFloatPattern == null) { + hexFloatPattern = Pattern.compile( //1 234 56 7 8 9 "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?" ); + } + return hexFloatPattern; + } /* * Convert string s to a suitable floating decimal; uses the @@ -1880,7 +1886,7 @@ public class FloatingDecimal{ static FloatingDecimal parseHexString(String s) { // Verify string is a member of the hexadecimal floating-point // string language. - Matcher m = hexFloatPattern.matcher(s); + Matcher m = getHexFloatPattern().matcher(s); boolean validInput = m.matches(); if (!validInput) { diff --git a/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java b/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java index a1a658a3e6f..99ba5224950 100644 --- a/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java +++ b/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java @@ -978,15 +978,6 @@ public class FormattedFloatingDecimal{ return new String(result); } - // This method should only ever be called if this object is constructed - // without Form.DECIMAL_FLOAT because the perThreadBuffer is not large - // enough to handle floating-point numbers of large precision. - public String toJavaFormatString() { - char result[] = (char[])(perThreadBuffer.get()); - int i = getChars(result); - return new String(result, 0, i); - } - // returns the exponent before rounding public int getExponent() { return decExponent - 1; @@ -1157,265 +1148,6 @@ public class FormattedFloatingDecimal{ } }; - // This method should only ever be called if this object is constructed - // without Form.DECIMAL_FLOAT because the perThreadBuffer is not large - // enough to handle floating-point numbers of large precision. - public void appendTo(Appendable buf) { - char result[] = (char[])(perThreadBuffer.get()); - int i = getChars(result); - if (buf instanceof StringBuilder) - ((StringBuilder) buf).append(result, 0, i); - else if (buf instanceof StringBuffer) - ((StringBuffer) buf).append(result, 0, i); - else - assert false; - } - - public static FormattedFloatingDecimal - readJavaFormatString( String in ) throws NumberFormatException { - boolean isNegative = false; - boolean signSeen = false; - int decExp; - char c; - - parseNumber: - try{ - in = in.trim(); // don't fool around with white space. - // throws NullPointerException if null - int l = in.length(); - if ( l == 0 ) throw new NumberFormatException("empty String"); - int i = 0; - switch ( c = in.charAt( i ) ){ - case '-': - isNegative = true; - //FALLTHROUGH - case '+': - i++; - signSeen = true; - } - - // Check for NaN and Infinity strings - c = in.charAt(i); - if(c == 'N' || c == 'I') { // possible NaN or infinity - boolean potentialNaN = false; - char targetChars[] = null; // char arrary of "NaN" or "Infinity" - - if(c == 'N') { - targetChars = notANumber; - potentialNaN = true; - } else { - targetChars = infinity; - } - - // compare Input string to "NaN" or "Infinity" - int j = 0; - while(i < l && j < targetChars.length) { - if(in.charAt(i) == targetChars[j]) { - i++; j++; - } - else // something is amiss, throw exception - break parseNumber; - } - - // For the candidate string to be a NaN or infinity, - // all characters in input string and target char[] - // must be matched ==> j must equal targetChars.length - // and i must equal l - if( (j == targetChars.length) && (i == l) ) { // return NaN or infinity - return (potentialNaN ? new FormattedFloatingDecimal(Double.NaN) // NaN has no sign - : new FormattedFloatingDecimal(isNegative? - Double.NEGATIVE_INFINITY: - Double.POSITIVE_INFINITY)) ; - } - else { // something went wrong, throw exception - break parseNumber; - } - - } else if (c == '0') { // check for hexadecimal floating-point number - if (l > i+1 ) { - char ch = in.charAt(i+1); - if (ch == 'x' || ch == 'X' ) // possible hex string - return parseHexString(in); - } - } // look for and process decimal floating-point string - - char[] digits = new char[ l ]; - int nDigits= 0; - boolean decSeen = false; - int decPt = 0; - int nLeadZero = 0; - int nTrailZero= 0; - digitLoop: - while ( i < l ){ - switch ( c = in.charAt( i ) ){ - case '0': - if ( nDigits > 0 ){ - nTrailZero += 1; - } else { - nLeadZero += 1; - } - break; // out of switch. - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - while ( nTrailZero > 0 ){ - digits[nDigits++] = '0'; - nTrailZero -= 1; - } - digits[nDigits++] = c; - break; // out of switch. - case '.': - if ( decSeen ){ - // already saw one ., this is the 2nd. - throw new NumberFormatException("multiple points"); - } - decPt = i; - if ( signSeen ){ - decPt -= 1; - } - decSeen = true; - break; // out of switch. - default: - break digitLoop; - } - i++; - } - /* - * At this point, we've scanned all the digits and decimal - * point we're going to see. Trim off leading and trailing - * zeros, which will just confuse us later, and adjust - * our initial decimal exponent accordingly. - * To review: - * we have seen i total characters. - * nLeadZero of them were zeros before any other digits. - * nTrailZero of them were zeros after any other digits. - * if ( decSeen ), then a . was seen after decPt characters - * ( including leading zeros which have been discarded ) - * nDigits characters were neither lead nor trailing - * zeros, nor point - */ - /* - * special hack: if we saw no non-zero digits, then the - * answer is zero! - * Unfortunately, we feel honor-bound to keep parsing! - */ - if ( nDigits == 0 ){ - digits = zero; - nDigits = 1; - if ( nLeadZero == 0 ){ - // we saw NO DIGITS AT ALL, - // not even a crummy 0! - // this is not allowed. - break parseNumber; // go throw exception - } - - } - - /* Our initial exponent is decPt, adjusted by the number of - * discarded zeros. Or, if there was no decPt, - * then its just nDigits adjusted by discarded trailing zeros. - */ - if ( decSeen ){ - decExp = decPt - nLeadZero; - } else { - decExp = nDigits+nTrailZero; - } - - /* - * Look for 'e' or 'E' and an optionally signed integer. - */ - if ( (i < l) && (((c = in.charAt(i) )=='e') || (c == 'E') ) ){ - int expSign = 1; - int expVal = 0; - int reallyBig = Integer.MAX_VALUE / 10; - boolean expOverflow = false; - switch( in.charAt(++i) ){ - case '-': - expSign = -1; - //FALLTHROUGH - case '+': - i++; - } - int expAt = i; - expLoop: - while ( i < l ){ - if ( expVal >= reallyBig ){ - // the next character will cause integer - // overflow. - expOverflow = true; - } - switch ( c = in.charAt(i++) ){ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - expVal = expVal*10 + ( (int)c - (int)'0' ); - continue; - default: - i--; // back up. - break expLoop; // stop parsing exponent. - } - } - int expLimit = bigDecimalExponent+nDigits+nTrailZero; - if ( expOverflow || ( expVal > expLimit ) ){ - // - // The intent here is to end up with - // infinity or zero, as appropriate. - // The reason for yielding such a small decExponent, - // rather than something intuitive such as - // expSign*Integer.MAX_VALUE, is that this value - // is subject to further manipulation in - // doubleValue() and floatValue(), and I don't want - // it to be able to cause overflow there! - // (The only way we can get into trouble here is for - // really outrageous nDigits+nTrailZero, such as 2 billion. ) - // - decExp = expSign*expLimit; - } else { - // this should not overflow, since we tested - // for expVal > (MAX+N), where N >= abs(decExp) - decExp = decExp + expSign*expVal; - } - - // if we saw something not a digit ( or end of string ) - // after the [Ee][+-], without seeing any digits at all - // this is certainly an error. If we saw some digits, - // but then some trailing garbage, that might be ok. - // so we just fall through in that case. - // HUMBUG - if ( i == expAt ) - break parseNumber; // certainly bad - } - /* - * We parsed everything we could. - * If there are leftovers, then this is not good input! - */ - if ( i < l && - ((i != l - 1) || - (in.charAt(i) != 'f' && - in.charAt(i) != 'F' && - in.charAt(i) != 'd' && - in.charAt(i) != 'D'))) { - break parseNumber; // go throw exception - } - - return new FormattedFloatingDecimal( isNegative, decExp, digits, nDigits, false, Integer.MAX_VALUE, Form.COMPATIBLE ); - } catch ( StringIndexOutOfBoundsException e ){ } - throw new NumberFormatException("For input string: \"" + in + "\""); - } - /* * Take a FormattedFloatingDecimal, which we presumably just scanned in, * and find out what its value is, as a double. @@ -2035,548 +1767,4 @@ public class FormattedFloatingDecimal{ private static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' }; private static final char notANumber[] = { 'N', 'a', 'N' }; private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' }; - - - /* - * Grammar is compatible with hexadecimal floating-point constants - * described in section 6.4.4.2 of the C99 specification. - */ - private static Pattern hexFloatPattern = Pattern.compile( - //1 234 56 7 8 9 - "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?" - ); - - /* - * Convert string s to a suitable floating decimal; uses the - * double constructor and set the roundDir variable appropriately - * in case the value is later converted to a float. - */ - static FormattedFloatingDecimal parseHexString(String s) { - // Verify string is a member of the hexadecimal floating-point - // string language. - Matcher m = hexFloatPattern.matcher(s); - boolean validInput = m.matches(); - - if (!validInput) { - // Input does not match pattern - throw new NumberFormatException("For input string: \"" + s + "\""); - } else { // validInput - /* - * We must isolate the sign, significand, and exponent - * fields. The sign value is straightforward. Since - * floating-point numbers are stored with a normalized - * representation, the significand and exponent are - * interrelated. - * - * After extracting the sign, we normalized the - * significand as a hexadecimal value, calculating an - * exponent adjust for any shifts made during - * normalization. If the significand is zero, the - * exponent doesn't need to be examined since the output - * will be zero. - * - * Next the exponent in the input string is extracted. - * Afterwards, the significand is normalized as a *binary* - * value and the input value's normalized exponent can be - * computed. The significand bits are copied into a - * double significand; if the string has more logical bits - * than can fit in a double, the extra bits affect the - * round and sticky bits which are used to round the final - * value. - */ - - // Extract significand sign - String group1 = m.group(1); - double sign = (( group1 == null ) || group1.equals("+"))? 1.0 : -1.0; - - - // Extract Significand magnitude - /* - * Based on the form of the significand, calculate how the - * binary exponent needs to be adjusted to create a - * normalized *hexadecimal* floating-point number; that - * is, a number where there is one nonzero hex digit to - * the left of the (hexa)decimal point. Since we are - * adjusting a binary, not hexadecimal exponent, the - * exponent is adjusted by a multiple of 4. - * - * There are a number of significand scenarios to consider; - * letters are used in indicate nonzero digits: - * - * 1. 000xxxx => x.xxx normalized - * increase exponent by (number of x's - 1)*4 - * - * 2. 000xxx.yyyy => x.xxyyyy normalized - * increase exponent by (number of x's - 1)*4 - * - * 3. .000yyy => y.yy normalized - * decrease exponent by (number of zeros + 1)*4 - * - * 4. 000.00000yyy => y.yy normalized - * decrease exponent by (number of zeros to right of point + 1)*4 - * - * If the significand is exactly zero, return a properly - * signed zero. - */ - - String significandString =null; - int signifLength = 0; - int exponentAdjust = 0; - { - int leftDigits = 0; // number of meaningful digits to - // left of "decimal" point - // (leading zeros stripped) - int rightDigits = 0; // number of digits to right of - // "decimal" point; leading zeros - // must always be accounted for - /* - * The significand is made up of either - * - * 1. group 4 entirely (integer portion only) - * - * OR - * - * 2. the fractional portion from group 7 plus any - * (optional) integer portions from group 6. - */ - String group4; - if( (group4 = m.group(4)) != null) { // Integer-only significand - // Leading zeros never matter on the integer portion - significandString = stripLeadingZeros(group4); - leftDigits = significandString.length(); - } - else { - // Group 6 is the optional integer; leading zeros - // never matter on the integer portion - String group6 = stripLeadingZeros(m.group(6)); - leftDigits = group6.length(); - - // fraction - String group7 = m.group(7); - rightDigits = group7.length(); - - // Turn "integer.fraction" into "integer"+"fraction" - significandString = - ((group6 == null)?"":group6) + // is the null - // check necessary? - group7; - } - - significandString = stripLeadingZeros(significandString); - signifLength = significandString.length(); - - /* - * Adjust exponent as described above - */ - if (leftDigits >= 1) { // Cases 1 and 2 - exponentAdjust = 4*(leftDigits - 1); - } else { // Cases 3 and 4 - exponentAdjust = -4*( rightDigits - signifLength + 1); - } - - // If the significand is zero, the exponent doesn't - // matter; return a properly signed zero. - - if (signifLength == 0) { // Only zeros in input - return new FormattedFloatingDecimal(sign * 0.0); - } - } - - // Extract Exponent - /* - * Use an int to read in the exponent value; this should - * provide more than sufficient range for non-contrived - * inputs. If reading the exponent in as an int does - * overflow, examine the sign of the exponent and - * significand to determine what to do. - */ - String group8 = m.group(8); - boolean positiveExponent = ( group8 == null ) || group8.equals("+"); - long unsignedRawExponent; - try { - unsignedRawExponent = Integer.parseInt(m.group(9)); - } - catch (NumberFormatException e) { - // At this point, we know the exponent is - // syntactically well-formed as a sequence of - // digits. Therefore, if an NumberFormatException - // is thrown, it must be due to overflowing int's - // range. Also, at this point, we have already - // checked for a zero significand. Thus the signs - // of the exponent and significand determine the - // final result: - // - // significand - // + - - // exponent + +infinity -infinity - // - +0.0 -0.0 - return new FormattedFloatingDecimal(sign * (positiveExponent ? - Double.POSITIVE_INFINITY : 0.0)); - } - - long rawExponent = - (positiveExponent ? 1L : -1L) * // exponent sign - unsignedRawExponent; // exponent magnitude - - // Calculate partially adjusted exponent - long exponent = rawExponent + exponentAdjust ; - - // Starting copying non-zero bits into proper position in - // a long; copy explicit bit too; this will be masked - // later for normal values. - - boolean round = false; - boolean sticky = false; - int bitsCopied=0; - int nextShift=0; - long significand=0L; - // First iteration is different, since we only copy - // from the leading significand bit; one more exponent - // adjust will be needed... - - // IMPORTANT: make leadingDigit a long to avoid - // surprising shift semantics! - long leadingDigit = getHexDigit(significandString, 0); - - /* - * Left shift the leading digit (53 - (bit position of - * leading 1 in digit)); this sets the top bit of the - * significand to 1. The nextShift value is adjusted - * to take into account the number of bit positions of - * the leadingDigit actually used. Finally, the - * exponent is adjusted to normalize the significand - * as a binary value, not just a hex value. - */ - if (leadingDigit == 1) { - significand |= leadingDigit << 52; - nextShift = 52 - 4; - /* exponent += 0 */ } - else if (leadingDigit <= 3) { // [2, 3] - significand |= leadingDigit << 51; - nextShift = 52 - 5; - exponent += 1; - } - else if (leadingDigit <= 7) { // [4, 7] - significand |= leadingDigit << 50; - nextShift = 52 - 6; - exponent += 2; - } - else if (leadingDigit <= 15) { // [8, f] - significand |= leadingDigit << 49; - nextShift = 52 - 7; - exponent += 3; - } else { - throw new AssertionError("Result from digit converstion too large!"); - } - // The preceding if-else could be replaced by a single - // code block based on the high-order bit set in - // leadingDigit. Given leadingOnePosition, - - // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition); - // nextShift = 52 - (3 + leadingOnePosition); - // exponent += (leadingOnePosition-1); - - - /* - * Now the exponent variable is equal to the normalized - * binary exponent. Code below will make representation - * adjustments if the exponent is incremented after - * rounding (includes overflows to infinity) or if the - * result is subnormal. - */ - - // Copy digit into significand until the significand can't - // hold another full hex digit or there are no more input - // hex digits. - int i = 0; - for(i = 1; - i < signifLength && nextShift >= 0; - i++) { - long currentDigit = getHexDigit(significandString, i); - significand |= (currentDigit << nextShift); - nextShift-=4; - } - - // After the above loop, the bulk of the string is copied. - // Now, we must copy any partial hex digits into the - // significand AND compute the round bit and start computing - // sticky bit. - - if ( i < signifLength ) { // at least one hex input digit exists - long currentDigit = getHexDigit(significandString, i); - - // from nextShift, figure out how many bits need - // to be copied, if any - switch(nextShift) { // must be negative - case -1: - // three bits need to be copied in; can - // set round bit - significand |= ((currentDigit & 0xEL) >> 1); - round = (currentDigit & 0x1L) != 0L; - break; - - case -2: - // two bits need to be copied in; can - // set round and start sticky - significand |= ((currentDigit & 0xCL) >> 2); - round = (currentDigit &0x2L) != 0L; - sticky = (currentDigit & 0x1L) != 0; - break; - - case -3: - // one bit needs to be copied in - significand |= ((currentDigit & 0x8L)>>3); - // Now set round and start sticky, if possible - round = (currentDigit &0x4L) != 0L; - sticky = (currentDigit & 0x3L) != 0; - break; - - case -4: - // all bits copied into significand; set - // round and start sticky - round = ((currentDigit & 0x8L) != 0); // is top bit set? - // nonzeros in three low order bits? - sticky = (currentDigit & 0x7L) != 0; - break; - - default: - throw new AssertionError("Unexpected shift distance remainder."); - // break; - } - - // Round is set; sticky might be set. - - // For the sticky bit, it suffices to check the - // current digit and test for any nonzero digits in - // the remaining unprocessed input. - i++; - while(i < signifLength && !sticky) { - currentDigit = getHexDigit(significandString,i); - sticky = sticky || (currentDigit != 0); - i++; - } - - } - // else all of string was seen, round and sticky are - // correct as false. - - - // Check for overflow and update exponent accordingly. - - if (exponent > DoubleConsts.MAX_EXPONENT) { // Infinite result - // overflow to properly signed infinity - return new FormattedFloatingDecimal(sign * Double.POSITIVE_INFINITY); - } else { // Finite return value - if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result - exponent >= DoubleConsts.MIN_EXPONENT) { - - // The result returned in this block cannot be a - // zero or subnormal; however after the - // significand is adjusted from rounding, we could - // still overflow in infinity. - - // AND exponent bits into significand; if the - // significand is incremented and overflows from - // rounding, this combination will update the - // exponent correctly, even in the case of - // Double.MAX_VALUE overflowing to infinity. - - significand = (( ((long)exponent + - (long)DoubleConsts.EXP_BIAS) << - (DoubleConsts.SIGNIFICAND_WIDTH-1)) - & DoubleConsts.EXP_BIT_MASK) | - (DoubleConsts.SIGNIF_BIT_MASK & significand); - - } else { // Subnormal or zero - // (exponent < DoubleConsts.MIN_EXPONENT) - - if (exponent < (DoubleConsts.MIN_SUB_EXPONENT -1 )) { - // No way to round back to nonzero value - // regardless of significand if the exponent is - // less than -1075. - return new FormattedFloatingDecimal(sign * 0.0); - } else { // -1075 <= exponent <= MIN_EXPONENT -1 = -1023 - /* - * Find bit position to round to; recompute - * round and sticky bits, and shift - * significand right appropriately. - */ - - sticky = sticky || round; - round = false; - - // Number of bits of significand to preserve is - // exponent - abs_min_exp +1 - // check: - // -1075 +1074 + 1 = 0 - // -1023 +1074 + 1 = 52 - - int bitsDiscarded = 53 - - ((int)exponent - DoubleConsts.MIN_SUB_EXPONENT + 1); - assert bitsDiscarded >= 1 && bitsDiscarded <= 53; - - // What to do here: - // First, isolate the new round bit - round = (significand & (1L << (bitsDiscarded -1))) != 0L; - if (bitsDiscarded > 1) { - // create mask to update sticky bits; low - // order bitsDiscarded bits should be 1 - long mask = ~((~0L) << (bitsDiscarded -1)); - sticky = sticky || ((significand & mask) != 0L ) ; - } - - // Now, discard the bits - significand = significand >> bitsDiscarded; - - significand = (( ((long)(DoubleConsts.MIN_EXPONENT -1) + // subnorm exp. - (long)DoubleConsts.EXP_BIAS) << - (DoubleConsts.SIGNIFICAND_WIDTH-1)) - & DoubleConsts.EXP_BIT_MASK) | - (DoubleConsts.SIGNIF_BIT_MASK & significand); - } - } - - // The significand variable now contains the currently - // appropriate exponent bits too. - - /* - * Determine if significand should be incremented; - * making this determination depends on the least - * significant bit and the round and sticky bits. - * - * Round to nearest even rounding table, adapted from - * table 4.7 in "Computer Arithmetic" by IsraelKoren. - * The digit to the left of the "decimal" point is the - * least significant bit, the digits to the right of - * the point are the round and sticky bits - * - * Number Round(x) - * x0.00 x0. - * x0.01 x0. - * x0.10 x0. - * x0.11 x1. = x0. +1 - * x1.00 x1. - * x1.01 x1. - * x1.10 x1. + 1 - * x1.11 x1. + 1 - */ - boolean incremented = false; - boolean leastZero = ((significand & 1L) == 0L); - if( ( leastZero && round && sticky ) || - ((!leastZero) && round )) { - incremented = true; - significand++; - } - - FormattedFloatingDecimal fd = new FormattedFloatingDecimal(FpUtils.rawCopySign( - Double.longBitsToDouble(significand), - sign)); - - /* - * Set roundingDir variable field of fd properly so - * that the input string can be properly rounded to a - * float value. There are two cases to consider: - * - * 1. rounding to double discards sticky bit - * information that would change the result of a float - * rounding (near halfway case between two floats) - * - * 2. rounding to double rounds up when rounding up - * would not occur when rounding to float. - * - * For former case only needs to be considered when - * the bits rounded away when casting to float are all - * zero; otherwise, float round bit is properly set - * and sticky will already be true. - * - * The lower exponent bound for the code below is the - * minimum (normalized) subnormal exponent - 1 since a - * value with that exponent can round up to the - * minimum subnormal value and the sticky bit - * information must be preserved (i.e. case 1). - */ - if ((exponent >= FloatConsts.MIN_SUB_EXPONENT-1) && - (exponent <= FloatConsts.MAX_EXPONENT ) ){ - // Outside above exponent range, the float value - // will be zero or infinity. - - /* - * If the low-order 28 bits of a rounded double - * significand are 0, the double could be a - * half-way case for a rounding to float. If the - * double value is a half-way case, the double - * significand may have to be modified to round - * the the right float value (see the stickyRound - * method). If the rounding to double has lost - * what would be float sticky bit information, the - * double significand must be incremented. If the - * double value's significand was itself - * incremented, the float value may end up too - * large so the increment should be undone. - */ - if ((significand & 0xfffffffL) == 0x0L) { - // For negative values, the sign of the - // roundDir is the same as for positive values - // since adding 1 increasing the significand's - // magnitude and subtracting 1 decreases the - // significand's magnitude. If neither round - // nor sticky is true, the double value is - // exact and no adjustment is required for a - // proper float rounding. - if( round || sticky) { - if (leastZero) { // prerounding lsb is 0 - // If round and sticky were both true, - // and the least significant - // significand bit were 0, the rounded - // significand would not have its - // low-order bits be zero. Therefore, - // we only need to adjust the - // significand if round XOR sticky is - // true. - if (round ^ sticky) { - fd.roundDir = 1; - } - } - else { // prerounding lsb is 1 - // If the prerounding lsb is 1 and the - // resulting significand has its - // low-order bits zero, the significand - // was incremented. Here, we undo the - // increment, which will ensure the - // right guard and sticky bits for the - // float rounding. - if (round) - fd.roundDir = -1; - } - } - } - } - - fd.fromHex = true; - return fd; - } - } - } - - /** - * Return <code>s</code> with any leading zeros removed. - */ - static String stripLeadingZeros(String s) { - return s.replaceFirst("^0+", ""); - } - - /** - * Extract a hexadecimal digit from position <code>position</code> - * of string <code>s</code>. - */ - static int getHexDigit(String s, int position) { - int value = Character.digit(s.charAt(position), 16); - if (value <= -1 || value >= 16) { - throw new AssertionError("Unxpected failure of digit converstion of " + - s.charAt(position)); - } - return value; - } - - } diff --git a/jdk/src/share/classes/sun/misc/JavaIOAccess.java b/jdk/src/share/classes/sun/misc/JavaIOAccess.java index 2a076a9d84d..f0b50a8ac4e 100644 --- a/jdk/src/share/classes/sun/misc/JavaIOAccess.java +++ b/jdk/src/share/classes/sun/misc/JavaIOAccess.java @@ -29,6 +29,5 @@ import java.nio.charset.Charset; public interface JavaIOAccess { public Console console(); - public Runnable consoleRestoreHook(); public Charset charset(); } diff --git a/jdk/src/share/classes/sun/misc/JavaLangAccess.java b/jdk/src/share/classes/sun/misc/JavaLangAccess.java index 7c1cc55032f..c288bc8402f 100644 --- a/jdk/src/share/classes/sun/misc/JavaLangAccess.java +++ b/jdk/src/share/classes/sun/misc/JavaLangAccess.java @@ -54,4 +54,7 @@ public interface JavaLangAccess { /** Set thread's blocker field. */ void blockedOn(Thread t, Interruptible b); + + /** register shutdown hook */ + void registerShutdownHook(int slot, Runnable r); } diff --git a/jdk/src/share/classes/sun/misc/Launcher.java b/jdk/src/share/classes/sun/misc/Launcher.java index a64986e6260..030d3e571a1 100644 --- a/jdk/src/share/classes/sun/misc/Launcher.java +++ b/jdk/src/share/classes/sun/misc/Launcher.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,7 +120,10 @@ public class Launcher { * The class loader used for loading installed extensions. */ static class ExtClassLoader extends URLClassLoader { - private File[] dirs; + + static { + ClassLoader.registerAsParallelCapable(); + } /** * create an ExtClassLoader. The ExtClassLoader is created @@ -146,12 +149,12 @@ public class Launcher { } }); } catch (java.security.PrivilegedActionException e) { - throw (IOException) e.getException(); + throw (IOException) e.getException(); } } void addExtURL(URL url) { - super.addURL(url); + super.addURL(url); } /* @@ -159,7 +162,6 @@ public class Launcher { */ public ExtClassLoader(File[] dirs) throws IOException { super(getExtURLs(dirs), null, factory); - this.dirs = dirs; } private static File[] getExtDirs() { @@ -206,20 +208,27 @@ public class Launcher { */ public String findLibrary(String name) { name = System.mapLibraryName(name); - for (int i = 0; i < dirs.length; i++) { - // Look in architecture-specific subdirectory first - String arch = System.getProperty("os.arch"); - if (arch != null) { - File file = new File(new File(dirs[i], arch), name); + URL[] urls = super.getURLs(); + File prevDir = null; + for (int i = 0; i < urls.length; i++) { + // Get the ext directory from the URL + File dir = new File(urls[i].getPath()).getParentFile(); + if (dir != null && !dir.equals(prevDir)) { + // Look in architecture-specific subdirectory first + String arch = System.getProperty("os.arch"); + if (arch != null) { + File file = new File(new File(dir, arch), name); + if (file.exists()) { + return file.getAbsolutePath(); + } + } + // Then check the extension directory + File file = new File(dir, name); if (file.exists()) { return file.getAbsolutePath(); } } - // Then check the extension directory - File file = new File(dirs[i], name); - if (file.exists()) { - return file.getAbsolutePath(); - } + prevDir = dir; } return null; } @@ -248,6 +257,10 @@ public class Launcher { */ static class AppClassLoader extends URLClassLoader { + static { + ClassLoader.registerAsParallelCapable(); + } + public static ClassLoader getAppClassLoader(final ClassLoader extcl) throws IOException { @@ -281,7 +294,7 @@ public class Launcher { /** * Override loadClass so we can checkPackageAccess. */ - public synchronized Class loadClass(String name, boolean resolve) + public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { int i = name.lastIndexOf('.'); diff --git a/jdk/src/share/classes/sun/misc/SharedSecrets.java b/jdk/src/share/classes/sun/misc/SharedSecrets.java index 938e54c6c50..16b5727c604 100644 --- a/jdk/src/share/classes/sun/misc/SharedSecrets.java +++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java @@ -44,7 +44,6 @@ public class SharedSecrets { private static JavaUtilJarAccess javaUtilJarAccess; private static JavaLangAccess javaLangAccess; private static JavaIOAccess javaIOAccess; - private static JavaIODeleteOnExitAccess javaIODeleteOnExitAccess; private static JavaNetAccess javaNetAccess; private static JavaNioAccess javaNioAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; @@ -103,17 +102,6 @@ public class SharedSecrets { return javaIOAccess; } - public static void setJavaIODeleteOnExitAccess(JavaIODeleteOnExitAccess jida) { - javaIODeleteOnExitAccess = jida; - } - - public static JavaIODeleteOnExitAccess getJavaIODeleteOnExitAccess() { - if (javaIODeleteOnExitAccess == null) { - unsafe.ensureClassInitialized(File.class); - } - return javaIODeleteOnExitAccess; - } - public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiofda) { javaIOFileDescriptorAccess = jiofda; } diff --git a/jdk/src/share/classes/sun/net/spi/DefaultProxySelector.java b/jdk/src/share/classes/sun/net/spi/DefaultProxySelector.java index a4fd7df23e1..714dc4ce5c3 100644 --- a/jdk/src/share/classes/sun/net/spi/DefaultProxySelector.java +++ b/jdk/src/share/classes/sun/net/spi/DefaultProxySelector.java @@ -78,7 +78,6 @@ public class DefaultProxySelector extends ProxySelector { }; private static boolean hasSystemProxies = false; - private static Properties defprops = new Properties(); static { final String key = "java.net.useSystemProxies"; @@ -107,6 +106,9 @@ public class DefaultProxySelector extends ProxySelector { RegexpPool hostsPool; String property; + static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null); + static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null); + NonProxyInfo(String p, String s, RegexpPool pool) { property = p; hostsSource = s; @@ -114,8 +116,6 @@ public class DefaultProxySelector extends ProxySelector { } } - private static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null); - private static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null); /** * select() method. Where all the hard work is done. @@ -175,13 +175,13 @@ public class DefaultProxySelector extends ProxySelector { NonProxyInfo pinfo = null; if ("http".equalsIgnoreCase(protocol)) { - pinfo = httpNonProxyInfo; + pinfo = NonProxyInfo.httpNonProxyInfo; } else if ("https".equalsIgnoreCase(protocol)) { // HTTPS uses the same property as HTTP, for backward // compatibility - pinfo = httpNonProxyInfo; + pinfo = NonProxyInfo.httpNonProxyInfo; } else if ("ftp".equalsIgnoreCase(protocol)) { - pinfo = ftpNonProxyInfo; + pinfo = NonProxyInfo.ftpNonProxyInfo; } /** @@ -334,7 +334,6 @@ public class DefaultProxySelector extends ProxySelector { } } - private static final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1"); private boolean isLoopback(String host) { if (host == null || host.length() == 0) return false; @@ -364,6 +363,7 @@ public class DefaultProxySelector extends ProxySelector { } if (host.endsWith(":1")) { + final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1"); return p6.matcher(host).matches(); } return false; diff --git a/jdk/src/share/classes/sun/nio/ch/AbstractFuture.java b/jdk/src/share/classes/sun/nio/ch/AbstractFuture.java new file mode 100644 index 00000000000..f79dc7abbbf --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/AbstractFuture.java @@ -0,0 +1,63 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.AsynchronousChannel; +import java.util.concurrent.Future; + +/** + * Base implementation of Future used for asynchronous I/O + */ + +abstract class AbstractFuture<V,A> + implements Future<V> +{ + private final AsynchronousChannel channel; + private final A attachment; + + protected AbstractFuture(AsynchronousChannel channel, A attachment) { + this.channel = channel; + this.attachment = attachment; + } + + final AsynchronousChannel channel() { + return channel; + } + + final A attachment() { + return attachment; + } + + /** + * Returns the result of the operation if it has completed successfully. + */ + abstract V value(); + + /** + * Returns the exception if the operation has failed. + */ + abstract Throwable exception(); +} diff --git a/jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java b/jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java new file mode 100644 index 00000000000..14e33ffe9d1 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java @@ -0,0 +1,341 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.Channel; +import java.nio.channels.AsynchronousChannelGroup; +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.io.IOException; +import java.io.FileDescriptor; +import java.util.Queue; +import java.util.concurrent.*; +import java.util.concurrent.locks.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.security.PrivilegedAction; +import java.security.AccessController; +import java.security.AccessControlContext; +import sun.security.action.GetIntegerAction; + +/** + * Base implementation of AsynchronousChannelGroup + */ + +abstract class AsynchronousChannelGroupImpl + extends AsynchronousChannelGroup implements Executor +{ + // number of internal threads handling I/O events when using an unbounded + // thread pool. Internal threads do not dispatch to completion handlers. + private static final int internalThreadCount = AccessController.doPrivileged( + new GetIntegerAction("sun.nio.ch.internalThreadPoolSize", 1)); + + // associated thread pool + private final ThreadPool pool; + + // number of tasks running (including internal) + private final AtomicInteger threadCount = new AtomicInteger(); + + // associated Executor for timeouts + private ScheduledThreadPoolExecutor timeoutExecutor; + + // task queue for when using a fixed thread pool. In that case, thread + // waiting on I/O events must be awokon to poll tasks from this queue. + private final Queue<Runnable> taskQueue; + + // group shutdown + // shutdownLock is RW lock so as to allow for concurrent queuing of tasks + // when using a fixed thread pool. + private final ReadWriteLock shutdownLock = new ReentrantReadWriteLock(); + private final Object shutdownNowLock = new Object(); + private volatile boolean shutdown; + private volatile boolean terminateInitiated; + + AsynchronousChannelGroupImpl(AsynchronousChannelProvider provider, + ThreadPool pool) + { + super(provider); + this.pool = pool; + + if (pool.isFixedThreadPool()) { + taskQueue = new ConcurrentLinkedQueue<Runnable>(); + } else { + taskQueue = null; // not used + } + + // use default thread factory as thread should not be visible to + // application (it doesn't execute completion handlers). + this.timeoutExecutor = (ScheduledThreadPoolExecutor) + Executors.newScheduledThreadPool(1, ThreadPool.defaultThreadFactory()); + this.timeoutExecutor.setRemoveOnCancelPolicy(true); + } + + final ExecutorService executor() { + return pool.executor(); + } + + final boolean isFixedThreadPool() { + return pool.isFixedThreadPool(); + } + + final int fixedThreadCount() { + if (isFixedThreadPool()) { + return pool.poolSize(); + } else { + return pool.poolSize() + internalThreadCount; + } + } + + private Runnable bindToGroup(final Runnable task) { + final AsynchronousChannelGroupImpl thisGroup = this; + return new Runnable() { + public void run() { + Invoker.bindToGroup(thisGroup); + task.run(); + } + }; + } + + private void startInternalThread(final Runnable task) { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + @Override + public Void run() { + // internal threads should not be visible to application so + // cannot use user-supplied thread factory + ThreadPool.defaultThreadFactory().newThread(task).start(); + return null; + } + }); + } + + protected final void startThreads(Runnable task) { + if (!isFixedThreadPool()) { + for (int i=0; i<internalThreadCount; i++) { + startInternalThread(task); + threadCount.incrementAndGet(); + } + } + if (pool.poolSize() > 0) { + task = bindToGroup(task); + try { + for (int i=0; i<pool.poolSize(); i++) { + pool.executor().execute(task); + threadCount.incrementAndGet(); + } + } catch (RejectedExecutionException x) { + // nothing we can do + } + } + } + + final int threadCount() { + return threadCount.get(); + } + + /** + * Invoked by tasks as they terminate + */ + final int threadExit(Runnable task, boolean replaceMe) { + if (replaceMe) { + try { + if (Invoker.isBoundToAnyGroup()) { + // submit new task to replace this thread + pool.executor().execute(bindToGroup(task)); + } else { + // replace internal thread + startInternalThread(task); + } + return threadCount.get(); + } catch (RejectedExecutionException x) { + // unable to replace + } + } + return threadCount.decrementAndGet(); + } + + /** + * Wakes up a thread waiting for I/O events to execute the given task. + */ + abstract void executeOnHandlerTask(Runnable task); + + /** + * For a fixed thread pool the task is queued to a thread waiting on I/O + * events. For other thread pools we simply submit the task to the thread + * pool. + */ + final void executeOnPooledThread(Runnable task) { + if (isFixedThreadPool()) { + executeOnHandlerTask(task); + } else { + pool.executor().execute(bindToGroup(task)); + } + } + + final void offerTask(Runnable task) { + taskQueue.offer(task); + } + + final Runnable pollTask() { + return (taskQueue == null) ? null : taskQueue.poll(); + } + + final Future<?> schedule(Runnable task, long timeout, TimeUnit unit) { + try { + return timeoutExecutor.schedule(task, timeout, unit); + } catch (RejectedExecutionException rej) { + if (terminateInitiated) { + // no timeout scheduled as group is terminating + return null; + } + throw new AssertionError(rej); + } + } + + @Override + public final boolean isShutdown() { + return shutdown; + } + + @Override + public final boolean isTerminated() { + return pool.executor().isTerminated(); + } + + /** + * Returns true if there are no channels in the group + */ + abstract boolean isEmpty(); + + /** + * Attaches a foreign channel to this group. + */ + abstract Object attachForeignChannel(Channel channel, FileDescriptor fdo) + throws IOException; + + /** + * Detaches a foreign channel from this group. + */ + abstract void detachForeignChannel(Object key); + + /** + * Closes all channels in the group + */ + abstract void closeAllChannels() throws IOException; + + /** + * Shutdown all tasks waiting for I/O events. + */ + abstract void shutdownHandlerTasks(); + + private void shutdownExecutors() { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + pool.executor().shutdown(); + timeoutExecutor.shutdown(); + return null; + } + }); + } + + @Override + public final void shutdown() { + shutdownLock.writeLock().lock(); + try { + if (shutdown) { + // already shutdown + return; + } + shutdown = true; + } finally { + shutdownLock.writeLock().unlock(); + } + + // if there are channels in the group then shutdown will continue + // when the last channel is closed + if (!isEmpty()) { + return; + } + // initiate termination (acquire shutdownNowLock to ensure that other + // threads invoking shutdownNow will block). + synchronized (shutdownNowLock) { + if (!terminateInitiated) { + terminateInitiated = true; + shutdownHandlerTasks(); + shutdownExecutors(); + } + } + } + + @Override + public final void shutdownNow() throws IOException { + shutdownLock.writeLock().lock(); + try { + shutdown = true; + } finally { + shutdownLock.writeLock().unlock(); + } + synchronized (shutdownNowLock) { + if (!terminateInitiated) { + terminateInitiated = true; + closeAllChannels(); + shutdownHandlerTasks(); + shutdownExecutors(); + } + } + } + + @Override + public final boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException + { + return pool.executor().awaitTermination(timeout, unit); + } + + /** + * Executes the given command on one of the channel group's pooled threads. + */ + @Override + public final void execute(Runnable task) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // when a security manager is installed then the user's task + // must be run with the current calling context + final AccessControlContext acc = AccessController.getContext(); + final Runnable delegate = task; + task = new Runnable() { + @Override + public void run() { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + @Override + public Void run() { + delegate.run(); + return null; + } + }, acc); + } + }; + } + executeOnPooledThread(task); + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java new file mode 100644 index 00000000000..2735a5a29cd --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java @@ -0,0 +1,164 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.locks.*; +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * Base implementation of AsynchronousFileChannel. + */ + +abstract class AsynchronousFileChannelImpl + extends AsynchronousFileChannel +{ + // close support + protected final ReadWriteLock closeLock = new ReentrantReadWriteLock(); + protected volatile boolean closed; + + // file descriptor + protected final FileDescriptor fdObj; + + // indicates if open for reading/writing + protected final boolean reading; + protected final boolean writing; + + // associated Executor + protected final ExecutorService executor; + + protected AsynchronousFileChannelImpl(FileDescriptor fdObj, + boolean reading, + boolean writing, + ExecutorService executor) + { + this.fdObj = fdObj; + this.reading = reading; + this.writing = writing; + this.executor = executor; + } + + final ExecutorService executor() { + return executor; + } + + @Override + public final boolean isOpen() { + return !closed; + } + + /** + * Marks the beginning of an I/O operation. + * + * @throws ClosedChannelException If channel is closed + */ + protected final void begin() throws IOException { + closeLock.readLock().lock(); + if (closed) + throw new ClosedChannelException(); + } + + /** + * Marks the end of an I/O operation. + */ + protected final void end() { + closeLock.readLock().unlock(); + } + + /** + * Marks end of I/O operation + */ + protected final void end(boolean completed) throws IOException { + end(); + if (!completed && !isOpen()) + throw new AsynchronousCloseException(); + } + + // -- file locking -- + + private volatile FileLockTable fileLockTable; + + final void ensureFileLockTableInitialized() throws IOException { + if (fileLockTable == null) { + synchronized (this) { + if (fileLockTable == null) { + fileLockTable = FileLockTable.newSharedFileLockTable(this, fdObj); + } + } + } + } + + final void invalidateAllLocks() { + if (fileLockTable != null) { + try { + fileLockTable.removeAll( new FileLockTable.Releaser() { + public void release(FileLock fl) { + ((FileLockImpl)fl).invalidate(); + } + }); + } catch (IOException e) { + throw new AssertionError(e); + } + } + } + + /** + * Adds region to lock table + */ + protected final FileLockImpl addToFileLockTable(long position, long size, boolean shared) { + final FileLockImpl fli; + try { + // like begin() but returns null instead of exception + closeLock.readLock().lock(); + if (closed) + return null; + + try { + ensureFileLockTableInitialized(); + } catch (IOException x) { + // should not happen + throw new AssertionError(x); + } + fli = new FileLockImpl(this, position, size, shared); + // may throw OverlappedFileLockException + fileLockTable.add(fli); + } finally { + end(); + } + return fli; + } + + protected final void removeFromFileLockTable(FileLockImpl fli) { + fileLockTable.remove(fli); + } + + /** + * Invoked by FileLockImpl to release lock acquired by this channel. + */ + abstract void release(FileLockImpl fli) throws IOException; +} diff --git a/jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java new file mode 100644 index 00000000000..49231930159 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java @@ -0,0 +1,221 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.net.SocketAddress; +import java.net.SocketOption; +import java.net.StandardSocketOption; +import java.net.InetSocketAddress; +import java.io.FileDescriptor; +import java.io.IOException; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import sun.net.NetHooks; + +/** + * Base implementation of AsynchronousServerSocketChannel. + */ + +abstract class AsynchronousServerSocketChannelImpl + extends AsynchronousServerSocketChannel + implements Cancellable, Groupable +{ + protected final FileDescriptor fd; + + // the local address to which the channel's socket is bound + protected volatile SocketAddress localAddress = null; + + // need this lock to set local address + private final Object stateLock = new Object(); + + // close support + private ReadWriteLock closeLock = new ReentrantReadWriteLock(); + private volatile boolean open = true; + + // set true when accept operation is cancelled + private volatile boolean acceptKilled; + + + AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) { + super(group.provider()); + this.fd = Net.serverSocket(true); + } + + @Override + public final boolean isOpen() { + return open; + } + + /** + * Marks beginning of access to file descriptor/handle + */ + final void begin() throws IOException { + closeLock.readLock().lock(); + if (!isOpen()) + throw new ClosedChannelException(); + } + + /** + * Marks end of access to file descriptor/handle + */ + final void end() { + closeLock.readLock().unlock(); + } + + /** + * Invoked to close file descriptor/handle. + */ + abstract void implClose() throws IOException; + + @Override + public final void close() throws IOException { + // synchronize with any threads using file descriptor/handle + closeLock.writeLock().lock(); + try { + if (!open) + return; // already closed + open = false; + } finally { + closeLock.writeLock().unlock(); + } + implClose(); + } + + final boolean isAcceptKilled() { + return acceptKilled; + } + + @Override + public final void onCancel(PendingFuture<?,?> task) { + acceptKilled = true; + } + + @Override + public final AsynchronousServerSocketChannel bind(SocketAddress local, int backlog) + throws IOException + { + InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : + Net.checkAddress(local); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkListen(isa.getPort()); + + try { + begin(); + synchronized (stateLock) { + if (localAddress != null) + throw new AlreadyBoundException(); + NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); + Net.bind(fd, isa.getAddress(), isa.getPort()); + Net.listen(fd, backlog < 1 ? 50 : backlog); + localAddress = Net.localAddress(fd); + } + } finally { + end(); + } + return this; + } + + @Override + public final SocketAddress getLocalAddress() throws IOException { + if (!isOpen()) + throw new ClosedChannelException(); + return localAddress; + } + + @Override + public final <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name, + T value) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + try { + begin(); + Net.setSocketOption(fd, Net.UNSPEC, name, value); + return this; + } finally { + end(); + } + } + + @Override + @SuppressWarnings("unchecked") + public final <T> T getOption(SocketOption<T> name) throws IOException { + if (name == null) + throw new NullPointerException(); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + try { + begin(); + return (T) Net.getSocketOption(fd, Net.UNSPEC, name); + } finally { + end(); + } + } + + private static class DefaultOptionsHolder { + static final Set<SocketOption<?>> defaultOptions = defaultOptions(); + + private static Set<SocketOption<?>> defaultOptions() { + HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2); + set.add(StandardSocketOption.SO_RCVBUF); + set.add(StandardSocketOption.SO_REUSEADDR); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set<SocketOption<?>> supportedOptions() { + return DefaultOptionsHolder.defaultOptions; + } + + @Override + public final String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(this.getClass().getName()); + sb.append('['); + if (!isOpen()) + sb.append("closed"); + else { + if (localAddress == null) { + sb.append("unbound"); + } else { + sb.append(localAddress.toString()); + } + } + sb.append(']'); + return sb.toString(); + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java new file mode 100644 index 00000000000..84b81a0c8b0 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java @@ -0,0 +1,544 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.SocketOption; +import java.net.StandardSocketOption; +import java.net.SocketAddress; +import java.net.InetSocketAddress; +import java.io.IOException; +import java.io.FileDescriptor; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; +import java.util.concurrent.*; +import java.util.concurrent.locks.*; +import sun.net.NetHooks; + +/** + * Base implementation of AsynchronousSocketChannel + */ + +abstract class AsynchronousSocketChannelImpl + extends AsynchronousSocketChannel + implements Cancellable, Groupable +{ + protected final FileDescriptor fd; + + // protects state, localAddress, and remoteAddress + protected final Object stateLock = new Object(); + + protected volatile SocketAddress localAddress = null; + protected volatile SocketAddress remoteAddress = null; + + // State, increases monotonically + static final int ST_UNINITIALIZED = -1; + static final int ST_UNCONNECTED = 0; + static final int ST_PENDING = 1; + static final int ST_CONNECTED = 2; + protected volatile int state = ST_UNINITIALIZED; + + // reading state + private final Object readLock = new Object(); + private boolean reading; + private boolean readShutdown; + private boolean readKilled; // further reading disallowed due to timeout + + // writing state + private final Object writeLock = new Object(); + private boolean writing; + private boolean writeShutdown; + private boolean writeKilled; // further writing disallowed due to timeout + + // close support + private final ReadWriteLock closeLock = new ReentrantReadWriteLock(); + private volatile boolean open = true; + + AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group) + throws IOException + { + super(group.provider()); + this.fd = Net.socket(true); + this.state = ST_UNCONNECTED; + } + + // Constructor for sockets obtained from AsynchronousServerSocketChannelImpl + AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group, + FileDescriptor fd, + InetSocketAddress remote) + throws IOException + { + super(group.provider()); + this.fd = fd; + this.state = ST_CONNECTED; + this.localAddress = Net.localAddress(fd); + this.remoteAddress = remote; + } + + @Override + public final boolean isOpen() { + return open; + } + + /** + * Marks beginning of access to file descriptor/handle + */ + final void begin() throws IOException { + closeLock.readLock().lock(); + if (!isOpen()) + throw new ClosedChannelException(); + } + + /** + * Marks end of access to file descriptor/handle + */ + final void end() { + closeLock.readLock().unlock(); + } + + /** + * Invoked to close socket and release other resources. + */ + abstract void implClose() throws IOException; + + @Override + public final void close() throws IOException { + // synchronize with any threads initiating asynchronous operations + closeLock.writeLock().lock(); + try { + if (!open) + return; // already closed + open = false; + } finally { + closeLock.writeLock().unlock(); + } + implClose(); + } + + final void enableReading(boolean killed) { + synchronized (readLock) { + reading = false; + if (killed) + readKilled = true; + } + } + + final void enableReading() { + enableReading(false); + } + + final void enableWriting(boolean killed) { + synchronized (writeLock) { + writing = false; + if (killed) + writeKilled = true; + } + } + + final void enableWriting() { + enableWriting(false); + } + + final void killReading() { + synchronized (readLock) { + readKilled = true; + } + } + + final void killWriting() { + synchronized (writeLock) { + writeKilled = true; + } + } + + final void killConnect() { + // when a connect is cancelled then the connection may have been + // established so prevent reading or writing. + killReading(); + killWriting(); + } + + /** + * Invoked by read to initiate the I/O operation. + */ + abstract <V extends Number,A> Future<V> readImpl(ByteBuffer[] dsts, + boolean isScatteringRead, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<V,? super A> handler); + + @SuppressWarnings("unchecked") + private <V extends Number,A> Future<V> read(ByteBuffer[] dsts, + boolean isScatteringRead, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<V,? super A> handler) + { + if (!isOpen()) { + CompletedFuture<V,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + if (remoteAddress == null) + throw new NotYetConnectedException(); + if (timeout < 0L) + throw new IllegalArgumentException("Negative timeout"); + + boolean hasSpaceToRead = isScatteringRead || dsts[0].hasRemaining(); + boolean shutdown = false; + + // check and update state + synchronized (readLock) { + if (readKilled) + throw new RuntimeException("Reading not allowed due to timeout or cancellation"); + if (reading) + throw new ReadPendingException(); + if (readShutdown) { + shutdown = true; + } else { + if (hasSpaceToRead) { + reading = true; + } + } + } + + // immediately complete with -1 if shutdown for read + // immediately complete with 0 if no space remaining + if (shutdown || !hasSpaceToRead) { + CompletedFuture<V,A> result; + if (isScatteringRead) { + Long value = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L); + result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, value, attachment); + } else { + int value = (shutdown) ? -1 : 0; + result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, value, attachment); + } + Invoker.invoke(handler, result); + return result; + } + + return readImpl(dsts, isScatteringRead, timeout, unit, attachment, handler); + } + + @Override + public final <A> Future<Integer> read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + if (dst.isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + ByteBuffer[] bufs = new ByteBuffer[1]; + bufs[0] = dst; + return read(bufs, false, timeout, unit, attachment, handler); + } + + @Override + public final <A> Future<Long> read(ByteBuffer[] dsts, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Long,? super A> handler) + { + if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) + throw new IndexOutOfBoundsException(); + ByteBuffer[] bufs = Util.subsequence(dsts, offset, length); + for (int i=0; i<bufs.length; i++) { + if (bufs[i].isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + } + return read(bufs, true, timeout, unit, attachment, handler); + } + + /** + * Invoked by write to initiate the I/O operation. + */ + abstract <V extends Number,A> Future<V> writeImpl(ByteBuffer[] srcs, + boolean isGatheringWrite, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<V,? super A> handler); + + @SuppressWarnings("unchecked") + private <V extends Number,A> Future<V> write(ByteBuffer[] srcs, + boolean isGatheringWrite, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<V,? super A> handler) + { + boolean hasDataToWrite = isGatheringWrite || srcs[0].hasRemaining(); + + boolean closed = false; + if (isOpen()) { + if (remoteAddress == null) + throw new NotYetConnectedException(); + if (timeout < 0L) + throw new IllegalArgumentException("Negative timeout"); + // check and update state + synchronized (writeLock) { + if (writeKilled) + throw new RuntimeException("Writing not allowed due to timeout or cancellation"); + if (writing) + throw new WritePendingException(); + if (writeShutdown) { + closed = true; + } else { + if (hasDataToWrite) + writing = true; + } + } + } else { + closed = true; + } + + // channel is closed or shutdown for write + if (closed) { + CompletedFuture<V,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + // nothing to write so complete immediately + if (!hasDataToWrite) { + CompletedFuture<V,A> result; + if (isGatheringWrite) { + result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, 0L, attachment); + } else { + result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, 0, attachment); + } + Invoker.invoke(handler, result); + return result; + } + + return writeImpl(srcs, isGatheringWrite, timeout, unit, attachment, handler); + } + + @Override + public final <A> Future<Integer> write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + ByteBuffer[] bufs = new ByteBuffer[1]; + bufs[0] = src; + return write(bufs, false, timeout, unit, attachment, handler); + } + + @Override + public final <A> Future<Long> write(ByteBuffer[] srcs, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Long,? super A> handler) + { + if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) + throw new IndexOutOfBoundsException(); + srcs = Util.subsequence(srcs, offset, length); + return write(srcs, true, timeout, unit, attachment, handler); + } + + @Override + public final AsynchronousSocketChannel bind(SocketAddress local) + throws IOException + { + try { + begin(); + synchronized (stateLock) { + if (state == ST_PENDING) + throw new ConnectionPendingException(); + if (localAddress != null) + throw new AlreadyBoundException(); + InetSocketAddress isa = (local == null) ? + new InetSocketAddress(0) : Net.checkAddress(local); + NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); + Net.bind(fd, isa.getAddress(), isa.getPort()); + localAddress = Net.localAddress(fd); + } + } finally { + end(); + } + return this; + } + + @Override + public final SocketAddress getLocalAddress() throws IOException { + if (!isOpen()) + throw new ClosedChannelException(); + return localAddress; + } + + @Override + public final <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + try { + begin(); + if (writeShutdown) + throw new IOException("Connection has been shutdown for writing"); + Net.setSocketOption(fd, Net.UNSPEC, name, value); + return this; + } finally { + end(); + } + } + + @Override + @SuppressWarnings("unchecked") + public final <T> T getOption(SocketOption<T> name) throws IOException { + if (name == null) + throw new NullPointerException(); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + try { + begin(); + return (T) Net.getSocketOption(fd, Net.UNSPEC, name); + } finally { + end(); + } + } + + private static class DefaultOptionsHolder { + static final Set<SocketOption<?>> defaultOptions = defaultOptions(); + + private static Set<SocketOption<?>> defaultOptions() { + HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(5); + set.add(StandardSocketOption.SO_SNDBUF); + set.add(StandardSocketOption.SO_RCVBUF); + set.add(StandardSocketOption.SO_KEEPALIVE); + set.add(StandardSocketOption.SO_REUSEADDR); + set.add(StandardSocketOption.TCP_NODELAY); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set<SocketOption<?>> supportedOptions() { + return DefaultOptionsHolder.defaultOptions; + } + + @Override + @SuppressWarnings("unchecked") + public final SocketAddress getRemoteAddress() throws IOException { + if (!isOpen()) + throw new ClosedChannelException(); + return remoteAddress; + } + + @Override + public final AsynchronousSocketChannel shutdownInput() throws IOException { + try { + begin(); + if (remoteAddress == null) + throw new NotYetConnectedException(); + synchronized (readLock) { + if (!readShutdown) { + Net.shutdown(fd, Net.SHUT_RD); + readShutdown = true; + } + } + } finally { + end(); + } + return this; + } + + @Override + public final AsynchronousSocketChannel shutdownOutput() throws IOException { + try { + begin(); + if (remoteAddress == null) + throw new NotYetConnectedException(); + synchronized (writeLock) { + if (!writeShutdown) { + Net.shutdown(fd, Net.SHUT_WR); + writeShutdown = true; + } + } + } finally { + end(); + } + return this; + } + + @Override + public final String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(this.getClass().getName()); + sb.append('['); + synchronized (stateLock) { + if (!isOpen()) { + sb.append("closed"); + } else { + switch (state) { + case ST_UNCONNECTED: + sb.append("unconnected"); + break; + case ST_PENDING: + sb.append("connection-pending"); + break; + case ST_CONNECTED: + sb.append("connected"); + if (readShutdown) + sb.append(" ishut"); + if (writeShutdown) + sb.append(" oshut"); + break; + } + if (localAddress != null) { + sb.append(" local="); + sb.append(localAddress.toString()); + } + if (remoteAddress != null) { + sb.append(" remote="); + sb.append(remoteAddress.toString()); + } + } + } + sb.append(']'); + return sb.toString(); + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/Cancellable.java b/jdk/src/share/classes/sun/nio/ch/Cancellable.java new file mode 100644 index 00000000000..ae08ed9eb89 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/Cancellable.java @@ -0,0 +1,39 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +/** + * Implemented by asynchronous channels that require notification when an I/O + * operation is cancelled. + */ + +interface Cancellable { + /** + * Invoked to notify channel that cancel has been invoked while holding + * the Future's lock. + */ + void onCancel(PendingFuture<?,?> task); +} diff --git a/jdk/src/share/classes/sun/nio/ch/CompletedFuture.java b/jdk/src/share/classes/sun/nio/ch/CompletedFuture.java new file mode 100644 index 00000000000..221b9f8f5f7 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/CompletedFuture.java @@ -0,0 +1,113 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.AsynchronousChannel; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutionException; +import java.io.IOException; + +/** + * A Future representing the result of an I/O operation that has already + * completed. + */ + +final class CompletedFuture<V,A> + extends AbstractFuture<V,A> +{ + private final V result; + private final Throwable exc; + + private CompletedFuture(AsynchronousChannel channel, + V result, + Throwable exc, + A attachment) + { + super(channel, attachment); + this.result = result; + this.exc = exc; + } + + @SuppressWarnings("unchecked") + static <V,A> CompletedFuture<V,A> withResult(AsynchronousChannel channel, + V result, + A attachment) + { + return new CompletedFuture<V,A>(channel, result, null, attachment); + } + + @SuppressWarnings("unchecked") + static <V,A> CompletedFuture<V,A> withFailure(AsynchronousChannel channel, + Throwable exc, + A attachment) + { + // exception must be IOException or SecurityException + if (!(exc instanceof IOException) && !(exc instanceof SecurityException)) + exc = new IOException(exc); + return new CompletedFuture(channel, null, exc, attachment); + } + + @Override + public V get() throws ExecutionException { + if (exc != null) + throw new ExecutionException(exc); + return result; + } + + @Override + public V get(long timeout, TimeUnit unit) throws ExecutionException { + if (unit == null) + throw new NullPointerException(); + if (exc != null) + throw new ExecutionException(exc); + return result; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return true; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + Throwable exception() { + return exc; + } + + @Override + V value() { + return result; + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index 54cbfba16c3..57b35c9bc20 100644 --- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,8 +111,12 @@ class DatagramChannelImpl public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family) { super(sp); if ((family != StandardProtocolFamily.INET) && - (family != StandardProtocolFamily.INET6)) { - throw new UnsupportedOperationException("Protocol family not supported"); + (family != StandardProtocolFamily.INET6)) + { + if (family == null) + throw new NullPointerException("'family' is null"); + else + throw new UnsupportedOperationException("Protocol family not supported"); } if (family == StandardProtocolFamily.INET6) { if (!Net.isIPv6Available()) { @@ -149,28 +153,28 @@ class DatagramChannelImpl public SocketAddress getLocalAddress() throws IOException { synchronized (stateLock) { if (!isOpen()) - return null; + throw new ClosedChannelException(); return localAddress; } } @Override - public SocketAddress getConnectedAddress() throws IOException { + public SocketAddress getRemoteAddress() throws IOException { synchronized (stateLock) { if (!isOpen()) - return null; + throw new ClosedChannelException(); return remoteAddress; } } @Override - public DatagramChannel setOption(SocketOption name, Object value) + public <T> DatagramChannel setOption(SocketOption<T> name, T value) throws IOException { if (name == null) throw new NullPointerException(); - if (!options().contains(name)) - throw new IllegalArgumentException("Invalid option name"); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); synchronized (stateLock) { ensureOpen(); @@ -224,8 +228,8 @@ class DatagramChannelImpl { if (name == null) throw new NullPointerException(); - if (!options().contains(name)) - throw new IllegalArgumentException("Invalid option name"); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); synchronized (stateLock) { ensureOpen(); @@ -273,7 +277,7 @@ class DatagramChannelImpl } } - private static class LazyInitialization { + private static class DefaultOptionsHolder { static final Set<SocketOption<?>> defaultOptions = defaultOptions(); private static Set<SocketOption<?>> defaultOptions() { @@ -291,8 +295,8 @@ class DatagramChannelImpl } @Override - public final Set<SocketOption<?>> options() { - return LazyInitialization.defaultOptions; + public final Set<SocketOption<?>> supportedOptions() { + return DefaultOptionsHolder.defaultOptions; } private void ensureOpen() throws ClosedChannelException { @@ -309,11 +313,9 @@ class DatagramChannelImpl throw new NullPointerException(); synchronized (readLock) { ensureOpen(); - // If socket is not bound then behave as if nothing received - // Will be fixed by 6621699 - if (localAddress() == null) { - return null; - } + // Socket was not bound before attempting receive + if (localAddress() == null) + bind(null); int n = 0; ByteBuffer bb = null; try { @@ -864,23 +866,26 @@ class DatagramChannelImpl } // package-private - void drop(MembershipKeyImpl key) - throws IOException - { - assert key.getChannel() == this; + void drop(MembershipKeyImpl key) { + assert key.channel() == this; synchronized (stateLock) { if (!key.isValid()) return; - if (family == StandardProtocolFamily.INET6) { - MembershipKeyImpl.Type6 key6 = - (MembershipKeyImpl.Type6)key; - Net.drop6(fd, key6.group(), key6.index(), key6.source()); - } else { - MembershipKeyImpl.Type4 key4 = - (MembershipKeyImpl.Type4)key; - Net.drop4(fd, key4.group(), key4.interfaceAddress(), key4.source()); + try { + if (family == StandardProtocolFamily.INET6) { + MembershipKeyImpl.Type6 key6 = + (MembershipKeyImpl.Type6)key; + Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source()); + } else { + MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4)key; + Net.drop4(fd, key4.groupAddress(), key4.interfaceAddress(), + key4.source()); + } + } catch (IOException ioe) { + // should not happen + throw new AssertionError(ioe); } key.invalidate(); @@ -895,8 +900,8 @@ class DatagramChannelImpl void block(MembershipKeyImpl key, InetAddress source) throws IOException { - assert key.getChannel() == this; - assert key.getSourceAddress() == null; + assert key.channel() == this; + assert key.sourceAddress() == null; synchronized (stateLock) { if (!key.isValid()) @@ -905,19 +910,19 @@ class DatagramChannelImpl throw new IllegalArgumentException("Source address is a wildcard address"); if (source.isMulticastAddress()) throw new IllegalArgumentException("Source address is multicast address"); - if (source.getClass() != key.getGroup().getClass()) + if (source.getClass() != key.group().getClass()) throw new IllegalArgumentException("Source address is different type to group"); int n; if (family == StandardProtocolFamily.INET6) { MembershipKeyImpl.Type6 key6 = (MembershipKeyImpl.Type6)key; - n = Net.block6(fd, key6.group(), key6.index(), + n = Net.block6(fd, key6.groupAddress(), key6.index(), Net.inet6AsByteArray(source)); } else { MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4)key; - n = Net.block4(fd, key4.group(), key4.interfaceAddress(), + n = Net.block4(fd, key4.groupAddress(), key4.interfaceAddress(), Net.inet4AsInt(source)); } if (n == IOStatus.UNAVAILABLE) { @@ -930,26 +935,29 @@ class DatagramChannelImpl /** * Unblock given source. */ - void unblock(MembershipKeyImpl key, InetAddress source) - throws IOException - { - assert key.getChannel() == this; - assert key.getSourceAddress() == null; + void unblock(MembershipKeyImpl key, InetAddress source) { + assert key.channel() == this; + assert key.sourceAddress() == null; synchronized (stateLock) { if (!key.isValid()) throw new IllegalStateException("key is no longer valid"); - if (family == StandardProtocolFamily.INET6) { - MembershipKeyImpl.Type6 key6 = - (MembershipKeyImpl.Type6)key; - Net.unblock6(fd, key6.group(), key6.index(), - Net.inet6AsByteArray(source)); - } else { - MembershipKeyImpl.Type4 key4 = - (MembershipKeyImpl.Type4)key; - Net.unblock4(fd, key4.group(), key4.interfaceAddress(), - Net.inet4AsInt(source)); + try { + if (family == StandardProtocolFamily.INET6) { + MembershipKeyImpl.Type6 key6 = + (MembershipKeyImpl.Type6)key; + Net.unblock6(fd, key6.groupAddress(), key6.index(), + Net.inet6AsByteArray(source)); + } else { + MembershipKeyImpl.Type4 key4 = + (MembershipKeyImpl.Type4)key; + Net.unblock4(fd, key4.groupAddress(), key4.interfaceAddress(), + Net.inet4AsInt(source)); + } + } catch (IOException ioe) { + // should not happen + throw new AssertionError(ioe); } } } diff --git a/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java b/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java index 86e787ef805..d695fd2a4f5 100644 --- a/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java +++ b/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java index 4d0543e4b1c..1d60e9615ff 100644 --- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,27 +26,18 @@ package sun.nio.ch; import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.RandomAccessFile; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.BufferPoolMXBean; import java.nio.channels.*; -import java.nio.channels.spi.*; import java.util.ArrayList; import java.util.List; import java.util.Iterator; -import java.util.concurrent.ConcurrentHashMap; -import java.lang.ref.WeakReference; -import java.lang.ref.ReferenceQueue; import java.lang.reflect.Field; import java.security.AccessController; -import java.security.PrivilegedAction; import javax.management.ObjectName; import javax.management.MalformedObjectNameException; - import sun.misc.Cleaner; import sun.security.action.GetPropertyAction; @@ -55,7 +46,7 @@ public class FileChannelImpl { // Used to make native read and write calls - private static final NativeDispatcher nd; + private static final FileDispatcher nd; // Memory allocation size for mapping buffers private static final long allocationGranularity; @@ -104,20 +95,19 @@ public class FileChannelImpl // -- Standard channel operations -- protected void implCloseChannel() throws IOException { - - nd.preClose(fd); - threads.signal(); - // Invalidate and release any locks that we still hold if (fileLockTable != null) { fileLockTable.removeAll( new FileLockTable.Releaser() { public void release(FileLock fl) throws IOException { ((FileLockImpl)fl).invalidate(); - release0(fd, fl.position(), fl.size()); + nd.release(fd, fl.position(), fl.size()); } }); } + nd.preClose(fd); + threads.signalAndWait(); + if (parent != null) { // Close the fd via the parent stream's close method. The parent @@ -141,9 +131,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return 0; - ti = threads.add(); do { n = IOUtil.read(fd, dst, -1, nd, positionLock); } while ((n == IOStatus.INTERRUPTED) && isOpen()); @@ -165,9 +155,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return 0; - ti = threads.add(); do { n = IOUtil.read(fd, dsts, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); @@ -198,9 +188,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return 0; - ti = threads.add(); do { n = IOUtil.write(fd, src, -1, nd, positionLock); } while ((n == IOStatus.INTERRUPTED) && isOpen()); @@ -222,9 +212,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return 0; - ti = threads.add(); do { n = IOUtil.write(fd, srcs, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); @@ -256,9 +246,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return 0; - ti = threads.add(); do { p = position0(fd, -1); } while ((p == IOStatus.INTERRUPTED) && isOpen()); @@ -280,9 +270,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return null; - ti = threads.add(); do { p = position0(fd, newPosition); } while ((p == IOStatus.INTERRUPTED) && isOpen()); @@ -302,11 +292,11 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return -1; - ti = threads.add(); do { - s = size0(fd); + s = nd.size(fd); } while ((s == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(s); } finally { @@ -331,9 +321,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return null; - ti = threads.add(); // get current position do { @@ -345,7 +335,7 @@ public class FileChannelImpl // truncate file do { - rv = truncate0(fd, size); + rv = nd.truncate(fd, size); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; @@ -371,11 +361,11 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return; - ti = threads.add(); do { - rv = force0(fd, metaData); + rv = nd.force(fd, metaData); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); } finally { threads.remove(ti); @@ -428,9 +418,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return -1; - ti = threads.add(); do { n = transferTo0(thisFDVal, position, icount, targetFDVal); } while ((n == IOStatus.INTERRUPTED) && isOpen()); @@ -635,9 +625,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return -1; - ti = threads.add(); do { n = IOUtil.read(fd, dst, position, nd, positionLock); } while ((n == IOStatus.INTERRUPTED) && isOpen()); @@ -661,9 +651,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return -1; - ti = threads.add(); do { n = IOUtil.write(fd, src, position, nd, positionLock); } while ((n == IOStatus.INTERRUPTED) && isOpen()); @@ -756,9 +746,9 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return null; - ti = threads.add(); if (size() < position + size) { // Extend file size if (!writable) { throw new IOException("Channel not open for writing " + @@ -766,7 +756,7 @@ public class FileChannelImpl } int rv; do { - rv = truncate0(fd, position + size); + rv = nd.truncate(fd, position + size); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); } if (size == 0) { @@ -860,10 +850,7 @@ public class FileChannelImpl // -- Locks -- - public static final int NO_LOCK = -1; // Failed to lock - public static final int LOCKED = 0; // Obtained requested lock - public static final int RET_EX_LOCK = 1; // Obtained exclusive lock - public static final int INTERRUPTED = 2; // Request interrupted + // keeps track of locks on this file private volatile FileLockTable fileLockTable; @@ -893,12 +880,21 @@ public class FileChannelImpl return isSharedFileLockTable; } - private FileLockTable fileLockTable() { + private FileLockTable fileLockTable() throws IOException { if (fileLockTable == null) { synchronized (this) { if (fileLockTable == null) { - fileLockTable = isSharedFileLockTable() ? - new SharedFileLockTable(this) : new SimpleFileLockTable(); + if (isSharedFileLockTable()) { + int ti = threads.add(); + try { + ensureOpen(); + fileLockTable = FileLockTable.newSharedFileLockTable(this, fd); + } finally { + threads.remove(ti); + } + } else { + fileLockTable = new SimpleFileLockTable(); + } } } } @@ -920,18 +916,18 @@ public class FileChannelImpl int ti = -1; try { begin(); + ti = threads.add(); if (!isOpen()) return null; - ti = threads.add(); - int result = lock0(fd, true, position, size, shared); - if (result == RET_EX_LOCK) { + int result = nd.lock(fd, true, position, size, shared); + if (result == FileDispatcher.RET_EX_LOCK) { assert shared; FileLockImpl fli2 = new FileLockImpl(this, position, size, false); flt.replace(fli, fli2); return fli2; } - if (result == INTERRUPTED || result == NO_LOCK) { + if (result == FileDispatcher.INTERRUPTED || result == FileDispatcher.NO_LOCK) { flt.remove(fli); i = false; } @@ -960,77 +956,54 @@ public class FileChannelImpl FileLockImpl fli = new FileLockImpl(this, position, size, shared); FileLockTable flt = fileLockTable(); flt.add(fli); - int result = lock0(fd, false, position, size, shared); - if (result == NO_LOCK) { - flt.remove(fli); - return null; + int result; + + int ti = threads.add(); + try { + try { + ensureOpen(); + result = nd.lock(fd, false, position, size, shared); + } catch (IOException e) { + flt.remove(fli); + throw e; + } + if (result == FileDispatcher.NO_LOCK) { + flt.remove(fli); + return null; + } + if (result == FileDispatcher.RET_EX_LOCK) { + assert shared; + FileLockImpl fli2 = new FileLockImpl(this, position, size, + false); + flt.replace(fli, fli2); + return fli2; + } + return fli; + } finally { + threads.remove(ti); } - if (result == RET_EX_LOCK) { - assert shared; - FileLockImpl fli2 = new FileLockImpl(this, position, size, - false); - flt.replace(fli, fli2); - return fli2; - } - return fli; } void release(FileLockImpl fli) throws IOException { ensureOpen(); - release0(fd, fli.position(), fli.size()); + int ti = threads.add(); + try { + ensureOpen(); + nd.release(fd, fli.position(), fli.size()); + } finally { + threads.remove(ti); + } assert fileLockTable != null; fileLockTable.remove(fli); } - - // -- File lock support -- - - /** - * A table of FileLocks. - */ - private interface FileLockTable { - /** - * Adds a file lock to the table. - * - * @throws OverlappingFileLockException if the file lock overlaps - * with an existing file lock in the table - */ - void add(FileLock fl) throws OverlappingFileLockException; - - /** - * Remove an existing file lock from the table. - */ - void remove(FileLock fl); - - /** - * An implementation of this interface releases a given file lock. - * Used with removeAll. - */ - interface Releaser { - void release(FileLock fl) throws IOException; - } - - /** - * Removes all file locks from the table. - * <p> - * The Releaser#release method is invoked for each file lock before - * it is removed. - * - * @throws IOException if the release method throws IOException - */ - void removeAll(Releaser r) throws IOException; - - /** - * Replaces an existing file lock in the table. - */ - void replace(FileLock fl1, FileLock fl2); - } + // -- File lock support -- /** * A simple file lock table that maintains a list of FileLocks obtained by a * FileChannel. Use to get 1.4/5.0 behaviour. */ - private static class SimpleFileLockTable implements FileLockTable { + private static class SimpleFileLockTable extends FileLockTable { // synchronize on list for access private List<FileLock> lockList = new ArrayList<FileLock>(2); @@ -1080,207 +1053,8 @@ public class FileChannelImpl } } - /** - * A weak reference to a FileLock. - * <p> - * SharedFileLockTable uses a list of file lock references to avoid keeping the - * FileLock (and FileChannel) alive. - */ - private static class FileLockReference extends WeakReference<FileLock> { - private FileKey fileKey; - - FileLockReference(FileLock referent, - ReferenceQueue<FileLock> queue, - FileKey key) { - super(referent, queue); - this.fileKey = key; - } - - private FileKey fileKey() { - return fileKey; - } - } - - /** - * A file lock table that is over a system-wide map of all file locks. - */ - private static class SharedFileLockTable implements FileLockTable { - // The system-wide map is a ConcurrentHashMap that is keyed on the FileKey. - // The map value is a list of file locks represented by FileLockReferences. - // All access to the list must be synchronized on the list. - private static ConcurrentHashMap<FileKey, ArrayList<FileLockReference>> lockMap = - new ConcurrentHashMap<FileKey, ArrayList<FileLockReference>>(); - - // reference queue for cleared refs - private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>(); - - // the enclosing file channel - private FileChannelImpl fci; - - // File key for the file that this channel is connected to - private FileKey fileKey; - - public SharedFileLockTable(FileChannelImpl fci) { - this.fci = fci; - this.fileKey = FileKey.create(fci.fd); - } - - public void add(FileLock fl) throws OverlappingFileLockException { - ArrayList<FileLockReference> list = lockMap.get(fileKey); - - for (;;) { - - // The key isn't in the map so we try to create it atomically - if (list == null) { - list = new ArrayList<FileLockReference>(2); - ArrayList<FileLockReference> prev; - synchronized (list) { - prev = lockMap.putIfAbsent(fileKey, list); - if (prev == null) { - // we successfully created the key so we add the file lock - list.add(new FileLockReference(fl, queue, fileKey)); - break; - } - } - // someone else got there first - list = prev; - } - - // There is already a key. It is possible that some other thread - // is removing it so we re-fetch the value from the map. If it - // hasn't changed then we check the list for overlapping locks - // and add the new lock to the list. - synchronized (list) { - ArrayList<FileLockReference> current = lockMap.get(fileKey); - if (list == current) { - checkList(list, fl.position(), fl.size()); - list.add(new FileLockReference(fl, queue, fileKey)); - break; - } - list = current; - } - - } - - // process any stale entries pending in the reference queue - removeStaleEntries(); - } - - private void removeKeyIfEmpty(FileKey fk, ArrayList<FileLockReference> list) { - assert Thread.holdsLock(list); - assert lockMap.get(fk) == list; - if (list.isEmpty()) { - lockMap.remove(fk); - } - } - - public void remove(FileLock fl) { - assert fl != null; - - // the lock must exist so the list of locks must be present - ArrayList<FileLockReference> list = lockMap.get(fileKey); - assert list != null; - - synchronized (list) { - int index = 0; - while (index < list.size()) { - FileLockReference ref = list.get(index); - FileLock lock = ref.get(); - if (lock == fl) { - assert (lock != null) && (lock.channel() == fci); - ref.clear(); - list.remove(index); - break; - } - index++; - } - } - } - - public void removeAll(Releaser releaser) throws IOException { - ArrayList<FileLockReference> list = lockMap.get(fileKey); - if (list != null) { - synchronized (list) { - int index = 0; - while (index < list.size()) { - FileLockReference ref = list.get(index); - FileLock lock = ref.get(); - - // remove locks obtained by this channel - if (lock != null && lock.channel() == fci) { - // invoke the releaser to invalidate/release the lock - releaser.release(lock); - - // remove the lock from the list - ref.clear(); - list.remove(index); - } else { - index++; - } - } - - // once the lock list is empty we remove it from the map - removeKeyIfEmpty(fileKey, list); - } - } - } - - public void replace(FileLock fromLock, FileLock toLock) { - // the lock must exist so there must be a list - ArrayList<FileLockReference> list = lockMap.get(fileKey); - assert list != null; - - synchronized (list) { - for (int index=0; index<list.size(); index++) { - FileLockReference ref = list.get(index); - FileLock lock = ref.get(); - if (lock == fromLock) { - ref.clear(); - list.set(index, new FileLockReference(toLock, queue, fileKey)); - break; - } - } - } - } - - // Check for overlapping file locks - private void checkList(List<FileLockReference> list, long position, long size) - throws OverlappingFileLockException - { - assert Thread.holdsLock(list); - for (FileLockReference ref: list) { - FileLock fl = ref.get(); - if (fl != null && fl.overlaps(position, size)) - throw new OverlappingFileLockException(); - } - } - - // Process the reference queue - private void removeStaleEntries() { - FileLockReference ref; - while ((ref = (FileLockReference)queue.poll()) != null) { - FileKey fk = ref.fileKey(); - ArrayList<FileLockReference> list = lockMap.get(fk); - if (list != null) { - synchronized (list) { - list.remove(ref); - removeKeyIfEmpty(fk, list); - } - } - } - } - } - // -- Native methods -- - // Grabs a file lock - native int lock0(FileDescriptor fd, boolean blocking, long pos, long size, - boolean shared) throws IOException; - - // Releases a file lock - native void release0(FileDescriptor fd, long pos, long size) - throws IOException; - // Creates a new mapping private native long map0(int prot, long position, long length) throws IOException; @@ -1288,12 +1062,6 @@ public class FileChannelImpl // Removes an existing mapping private static native int unmap0(long address, long length); - // Forces output to device - private native int force0(FileDescriptor fd, boolean metaData); - - // Truncates a file - private native int truncate0(FileDescriptor fd, long size); - // Transfers from src to dst, or returns -2 if kernel can't do that private native long transferTo0(int src, long position, long count, int dst); @@ -1302,16 +1070,13 @@ public class FileChannelImpl // otherwise the position is set to offset private native long position0(FileDescriptor fd, long offset); - // Reports this file's size - private native long size0(FileDescriptor fd); - // Caches fieldIDs private static native long initIDs(); static { Util.load(); allocationGranularity = initIDs(); - nd = new FileDispatcher(); + nd = new FileDispatcherImpl(); } } diff --git a/jdk/src/share/classes/sun/nio/ch/FileDispatcher.java b/jdk/src/share/classes/sun/nio/ch/FileDispatcher.java new file mode 100644 index 00000000000..9f8a0f79e4f --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/FileDispatcher.java @@ -0,0 +1,48 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.io.*; + +abstract class FileDispatcher extends NativeDispatcher { + + public static final int NO_LOCK = -1; // Failed to lock + public static final int LOCKED = 0; // Obtained requested lock + public static final int RET_EX_LOCK = 1; // Obtained exclusive lock + public static final int INTERRUPTED = 2; // Request interrupted + + abstract int force(FileDescriptor fd, boolean metaData) throws IOException; + + abstract int truncate(FileDescriptor fd, long size) throws IOException; + + abstract long size(FileDescriptor fd) throws IOException; + + abstract int lock(FileDescriptor fd, boolean blocking, long pos, long size, + boolean shared) throws IOException; + + abstract void release(FileDescriptor fd, long pos, long size) + throws IOException; +} diff --git a/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java b/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java index 721faf1a0fa..9efd1532b50 100644 --- a/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,7 @@ package sun.nio.ch; import java.io.IOException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.FileLock; -import java.nio.channels.FileChannel; +import java.nio.channels.*; public class FileLockImpl extends FileLock @@ -41,6 +39,12 @@ public class FileLockImpl this.valid = true; } + FileLockImpl(AsynchronousFileChannel channel, long position, long size, boolean shared) + { + super(channel, position, size, shared); + this.valid = true; + } + public synchronized boolean isValid() { return valid; } @@ -50,10 +54,15 @@ public class FileLockImpl } public synchronized void release() throws IOException { - if (!channel().isOpen()) + Channel ch = acquiredBy(); + if (!ch.isOpen()) throw new ClosedChannelException(); if (valid) { - ((FileChannelImpl)channel()).release(this); + if (ch instanceof FileChannelImpl) + ((FileChannelImpl)ch).release(this); + else if (ch instanceof AsynchronousFileChannelImpl) + ((AsynchronousFileChannelImpl)ch).release(this); + else throw new AssertionError(); valid = false; } } diff --git a/jdk/src/share/classes/sun/nio/ch/FileLockTable.java b/jdk/src/share/classes/sun/nio/ch/FileLockTable.java new file mode 100644 index 00000000000..137ab88872b --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/FileLockTable.java @@ -0,0 +1,282 @@ +/* + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.lang.ref.*; +import java.io.FileDescriptor; +import java.io.IOException; + +abstract class FileLockTable { + protected FileLockTable() { + } + + /** + * Creates and returns a file lock table for a channel that is connected to + * the a system-wide map of all file locks for the Java virtual machine. + */ + public static FileLockTable newSharedFileLockTable(Channel channel, + FileDescriptor fd) + throws IOException + { + return new SharedFileLockTable(channel, fd); + } + + /** + * Adds a file lock to the table. + * + * @throws OverlappingFileLockException if the file lock overlaps + * with an existing file lock in the table + */ + public abstract void add(FileLock fl) throws OverlappingFileLockException; + + /** + * Remove an existing file lock from the table. + */ + public abstract void remove(FileLock fl); + + /** + * An implementation of this interface releases a given file lock. + * Used with removeAll. + */ + public abstract interface Releaser { + void release(FileLock fl) throws IOException; + } + + /** + * Removes all file locks from the table. + * <p> + * The Releaser#release method is invoked for each file lock before + * it is removed. + * + * @throws IOException if the release method throws IOException + */ + public abstract void removeAll(Releaser r) throws IOException; + + /** + * Replaces an existing file lock in the table. + */ + public abstract void replace(FileLock fl1, FileLock fl2); +} + + +/** + * A file lock table that is over a system-wide map of all file locks. + */ +class SharedFileLockTable extends FileLockTable { + + /** + * A weak reference to a FileLock. + * <p> + * SharedFileLockTable uses a list of file lock references to avoid keeping the + * FileLock (and FileChannel) alive. + */ + private static class FileLockReference extends WeakReference<FileLock> { + private FileKey fileKey; + + FileLockReference(FileLock referent, + ReferenceQueue<FileLock> queue, + FileKey key) { + super(referent, queue); + this.fileKey = key; + } + + FileKey fileKey() { + return fileKey; + } + } + + // The system-wide map is a ConcurrentHashMap that is keyed on the FileKey. + // The map value is a list of file locks represented by FileLockReferences. + // All access to the list must be synchronized on the list. + private static ConcurrentHashMap<FileKey, List<FileLockReference>> lockMap = + new ConcurrentHashMap<FileKey, List<FileLockReference>>(); + + // reference queue for cleared refs + private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>(); + + // The connection to which this table is connected + private final Channel channel; + + // File key for the file that this channel is connected to + private final FileKey fileKey; + + SharedFileLockTable(Channel channel, FileDescriptor fd) throws IOException { + this.channel = channel; + this.fileKey = FileKey.create(fd); + } + + @Override + public void add(FileLock fl) throws OverlappingFileLockException { + List<FileLockReference> list = lockMap.get(fileKey); + + for (;;) { + + // The key isn't in the map so we try to create it atomically + if (list == null) { + list = new ArrayList<FileLockReference>(2); + List<FileLockReference> prev; + synchronized (list) { + prev = lockMap.putIfAbsent(fileKey, list); + if (prev == null) { + // we successfully created the key so we add the file lock + list.add(new FileLockReference(fl, queue, fileKey)); + break; + } + } + // someone else got there first + list = prev; + } + + // There is already a key. It is possible that some other thread + // is removing it so we re-fetch the value from the map. If it + // hasn't changed then we check the list for overlapping locks + // and add the new lock to the list. + synchronized (list) { + List<FileLockReference> current = lockMap.get(fileKey); + if (list == current) { + checkList(list, fl.position(), fl.size()); + list.add(new FileLockReference(fl, queue, fileKey)); + break; + } + list = current; + } + + } + + // process any stale entries pending in the reference queue + removeStaleEntries(); + } + + private void removeKeyIfEmpty(FileKey fk, List<FileLockReference> list) { + assert Thread.holdsLock(list); + assert lockMap.get(fk) == list; + if (list.isEmpty()) { + lockMap.remove(fk); + } + } + + @Override + public void remove(FileLock fl) { + assert fl != null; + + // the lock must exist so the list of locks must be present + List<FileLockReference> list = lockMap.get(fileKey); + if (list == null) return; + + synchronized (list) { + int index = 0; + while (index < list.size()) { + FileLockReference ref = list.get(index); + FileLock lock = ref.get(); + if (lock == fl) { + assert (lock != null) && (lock.channel() == channel); + ref.clear(); + list.remove(index); + break; + } + index++; + } + } + } + + @Override + public void removeAll(Releaser releaser) throws IOException { + List<FileLockReference> list = lockMap.get(fileKey); + if (list != null) { + synchronized (list) { + int index = 0; + while (index < list.size()) { + FileLockReference ref = list.get(index); + FileLock lock = ref.get(); + + // remove locks obtained by this channel + if (lock != null && lock.channel() == channel) { + // invoke the releaser to invalidate/release the lock + releaser.release(lock); + + // remove the lock from the list + ref.clear(); + list.remove(index); + } else { + index++; + } + } + + // once the lock list is empty we remove it from the map + removeKeyIfEmpty(fileKey, list); + } + } + } + + @Override + public void replace(FileLock fromLock, FileLock toLock) { + // the lock must exist so there must be a list + List<FileLockReference> list = lockMap.get(fileKey); + assert list != null; + + synchronized (list) { + for (int index=0; index<list.size(); index++) { + FileLockReference ref = list.get(index); + FileLock lock = ref.get(); + if (lock == fromLock) { + ref.clear(); + list.set(index, new FileLockReference(toLock, queue, fileKey)); + break; + } + } + } + } + + // Check for overlapping file locks + private void checkList(List<FileLockReference> list, long position, long size) + throws OverlappingFileLockException + { + assert Thread.holdsLock(list); + for (FileLockReference ref: list) { + FileLock fl = ref.get(); + if (fl != null && fl.overlaps(position, size)) + throw new OverlappingFileLockException(); + } + } + + // Process the reference queue + private void removeStaleEntries() { + FileLockReference ref; + while ((ref = (FileLockReference)queue.poll()) != null) { + FileKey fk = ref.fileKey(); + List<FileLockReference> list = lockMap.get(fk); + if (list != null) { + synchronized (list) { + list.remove(ref); + removeKeyIfEmpty(fk, list); + } + } + } + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/Groupable.java b/jdk/src/share/classes/sun/nio/ch/Groupable.java new file mode 100644 index 00000000000..b1760152b37 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/Groupable.java @@ -0,0 +1,35 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +/** + * Implemented by asynchronous channels that can be associated with an + * asynchronous channel group. + */ + +interface Groupable { + AsynchronousChannelGroupImpl group(); +} diff --git a/jdk/src/share/classes/sun/nio/ch/IOUtil.java b/jdk/src/share/classes/sun/nio/ch/IOUtil.java index f57b724b562..8d5bb13a2ee 100644 --- a/jdk/src/share/classes/sun/nio/ch/IOUtil.java +++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,10 +27,7 @@ package sun.nio.ch; import java.io.FileDescriptor; import java.io.IOException; -import java.net.*; import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.nio.channels.spi.*; /** @@ -47,7 +44,6 @@ class IOUtil { */ private static int remaining(ByteBuffer[] bufs) { int numBufs = bufs.length; - boolean remaining = false; for (int i=0; i<numBufs; i++) { if (bufs[i].hasRemaining()) { return i; @@ -138,74 +134,82 @@ class IOUtil { bufs = skipBufs(bufs, nextWithRemaining); int numBufs = bufs.length; - int bytesReadyToWrite = 0; // Create shadow to ensure DirectByteBuffers are used ByteBuffer[] shadow = new ByteBuffer[numBufs]; - for (int i=0; i<numBufs; i++) { - if (!(bufs[i] instanceof DirectBuffer)) { - int pos = bufs[i].position(); - int lim = bufs[i].limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - - ByteBuffer bb = ByteBuffer.allocateDirect(rem); - shadow[i] = bb; - // Leave slow buffer position untouched; it will be updated - // after we see how many bytes were really written out - bb.put(bufs[i]); - bufs[i].position(pos); - bb.flip(); - } else { - shadow[i] = bufs[i]; - } - } - - IOVecWrapper vec = null; - long bytesWritten = 0; try { - // Create a native iovec array - vec= new IOVecWrapper(numBufs); - - // Fill in the iovec array with appropriate data for (int i=0; i<numBufs; i++) { - ByteBuffer nextBuffer = shadow[i]; - // put in the buffer addresses - long pos = nextBuffer.position(); - long len = nextBuffer.limit() - pos; - bytesReadyToWrite += len; - vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos); - vec.putLen(i, len); - } + if (!(bufs[i] instanceof DirectBuffer)) { + int pos = bufs[i].position(); + int lim = bufs[i].limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); - // Invoke native call to fill the buffers - bytesWritten = nd.writev(fd, vec.address, numBufs); - } finally { - vec.free(); - } - long returnVal = bytesWritten; - - // Notify the buffers how many bytes were taken - for (int i=0; i<numBufs; i++) { - ByteBuffer nextBuffer = bufs[i]; - int pos = nextBuffer.position(); - int lim = nextBuffer.limit(); - assert (pos <= lim); - int len = (pos <= lim ? lim - pos : lim); - if (bytesWritten >= len) { - bytesWritten -= len; - int newPosition = pos + len; - nextBuffer.position(newPosition); - } else { // Buffers not completely filled - if (bytesWritten > 0) { - assert(pos + bytesWritten < (long)Integer.MAX_VALUE); - int newPosition = (int)(pos + bytesWritten); - nextBuffer.position(newPosition); + ByteBuffer bb = Util.getTemporaryDirectBuffer(rem); + shadow[i] = bb; + // Leave slow buffer position untouched; it will be updated + // after we see how many bytes were really written out + bb.put(bufs[i]); + bufs[i].position(pos); + bb.flip(); + } else { + shadow[i] = bufs[i]; + } + } + + IOVecWrapper vec = null; + long bytesWritten = 0; + try { + // Create a native iovec array + vec= new IOVecWrapper(numBufs); + + // Fill in the iovec array with appropriate data + for (int i=0; i<numBufs; i++) { + ByteBuffer nextBuffer = shadow[i]; + // put in the buffer addresses + long pos = nextBuffer.position(); + long len = nextBuffer.limit() - pos; + vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos); + vec.putLen(i, len); + } + + // Invoke native call to fill the buffers + bytesWritten = nd.writev(fd, vec.address, numBufs); + } finally { + vec.free(); + } + long returnVal = bytesWritten; + + // Notify the buffers how many bytes were taken + for (int i=0; i<numBufs; i++) { + ByteBuffer nextBuffer = bufs[i]; + int pos = nextBuffer.position(); + int lim = nextBuffer.limit(); + assert (pos <= lim); + int len = (pos <= lim ? lim - pos : lim); + if (bytesWritten >= len) { + bytesWritten -= len; + int newPosition = pos + len; + nextBuffer.position(newPosition); + } else { // Buffers not completely filled + if (bytesWritten > 0) { + assert(pos + bytesWritten < (long)Integer.MAX_VALUE); + int newPosition = (int)(pos + bytesWritten); + nextBuffer.position(newPosition); + } + break; + } + } + return returnVal; + } finally { + // return any substituted buffers to cache + for (int i=0; i<numBufs; i++) { + ByteBuffer bb = shadow[i]; + if (bb != null && bb != bufs[i]) { + Util.releaseTemporaryDirectBuffer(bb); } - break; } } - return returnVal; } static int read(FileDescriptor fd, ByteBuffer dst, long position, @@ -270,68 +274,83 @@ class IOUtil { // Read into the shadow to ensure DirectByteBuffers are used ByteBuffer[] shadow = new ByteBuffer[numBufs]; - for (int i=0; i<numBufs; i++) { - if (bufs[i].isReadOnly()) - throw new IllegalArgumentException("Read-only buffer"); - if (!(bufs[i] instanceof DirectBuffer)) { - shadow[i] = ByteBuffer.allocateDirect(bufs[i].remaining()); - } else { - shadow[i] = bufs[i]; - } - } - - IOVecWrapper vec = null; - long bytesRead = 0; + boolean usingSlowBuffers = false; try { - // Create a native iovec array - vec = new IOVecWrapper(numBufs); + for (int i=0; i<numBufs; i++) { + if (bufs[i].isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + if (!(bufs[i] instanceof DirectBuffer)) { + shadow[i] = Util.getTemporaryDirectBuffer(bufs[i].remaining()); + usingSlowBuffers = true; + } else { + shadow[i] = bufs[i]; + } + } - // Fill in the iovec array with appropriate data + IOVecWrapper vec = null; + long bytesRead = 0; + try { + // Create a native iovec array + vec = new IOVecWrapper(numBufs); + + // Fill in the iovec array with appropriate data + for (int i=0; i<numBufs; i++) { + ByteBuffer nextBuffer = shadow[i]; + // put in the buffer addresses + long pos = nextBuffer.position(); + long len = nextBuffer.remaining(); + vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos); + vec.putLen(i, len); + } + + // Invoke native call to fill the buffers + bytesRead = nd.readv(fd, vec.address, numBufs); + } finally { + vec.free(); + } + long returnVal = bytesRead; + + // Notify the buffers how many bytes were read for (int i=0; i<numBufs; i++) { ByteBuffer nextBuffer = shadow[i]; - // put in the buffer addresses - long pos = nextBuffer.position(); - long len = nextBuffer.remaining(); - vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos); - vec.putLen(i, len); - } - - // Invoke native call to fill the buffers - bytesRead = nd.readv(fd, vec.address, numBufs); - } finally { - vec.free(); - } - long returnVal = bytesRead; - - // Notify the buffers how many bytes were read - for (int i=0; i<numBufs; i++) { - ByteBuffer nextBuffer = shadow[i]; - // Note: should this have been cached from above? - int pos = nextBuffer.position(); - int len = nextBuffer.remaining(); - if (bytesRead >= len) { - bytesRead -= len; - int newPosition = pos + len; - nextBuffer.position(newPosition); - } else { // Buffers not completely filled - if (bytesRead > 0) { - assert(pos + bytesRead < (long)Integer.MAX_VALUE); - int newPosition = (int)(pos + bytesRead); + // Note: should this have been cached from above? + int pos = nextBuffer.position(); + int len = nextBuffer.remaining(); + if (bytesRead >= len) { + bytesRead -= len; + int newPosition = pos + len; nextBuffer.position(newPosition); + } else { // Buffers not completely filled + if (bytesRead > 0) { + assert(pos + bytesRead < (long)Integer.MAX_VALUE); + int newPosition = (int)(pos + bytesRead); + nextBuffer.position(newPosition); + } + break; + } + } + + // Put results from shadow into the slow buffers + if (usingSlowBuffers) { + for (int i=0; i<numBufs; i++) { + if (!(bufs[i] instanceof DirectBuffer)) { + shadow[i].flip(); + bufs[i].put(shadow[i]); + } + } + } + return returnVal; + } finally { + // return any substituted buffers to cache + if (usingSlowBuffers) { + for (int i=0; i<numBufs; i++) { + ByteBuffer bb = shadow[i]; + if (bb != null && bb != bufs[i]) { + Util.releaseTemporaryDirectBuffer(bb); + } } - break; } } - - // Put results from shadow into the slow buffers - for (int i=0; i<numBufs; i++) { - if (!(bufs[i] instanceof DirectBuffer)) { - shadow[i].flip(); - bufs[i].put(shadow[i]); - } - } - - return returnVal; } static FileDescriptor newFD(int i) { diff --git a/jdk/src/share/classes/sun/nio/ch/Invoker.java b/jdk/src/share/classes/sun/nio/ch/Invoker.java new file mode 100644 index 00000000000..182f7989a46 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/Invoker.java @@ -0,0 +1,261 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.util.concurrent.*; +import java.security.AccessController; +import sun.security.action.GetIntegerAction; + +/** + * Defines static methods to invoke a completion handler or arbitrary task. + */ + +class Invoker { + private Invoker() { } + + // maximum number of completion handlers that may be invoked on the current + // thread before it re-directs invocations to the thread pool. This helps + // avoid stack overflow and lessens the risk of starvation. + private static final int maxHandlerInvokeCount = AccessController.doPrivileged( + new GetIntegerAction("sun.nio.ch.maxCompletionHandlersOnStack", 16)); + + // Per-thread object with reference to channel group and a counter for + // the number of completion handlers invoked. This should be reset to 0 + // when all completion handlers have completed. + static class GroupAndInvokeCount { + private final AsynchronousChannelGroupImpl group; + private int handlerInvokeCount; + GroupAndInvokeCount(AsynchronousChannelGroupImpl group) { + this.group = group; + } + AsynchronousChannelGroupImpl group() { + return group; + } + int invokeCount() { + return handlerInvokeCount; + } + void setInvokeCount(int value) { + handlerInvokeCount = value; + } + void resetInvokeCount() { + handlerInvokeCount = 0; + } + void incrementInvokeCount() { + handlerInvokeCount++; + } + } + private static final ThreadLocal<GroupAndInvokeCount> myGroupAndInvokeCount = + new ThreadLocal<GroupAndInvokeCount>() { + @Override protected GroupAndInvokeCount initialValue() { + return null; + } + }; + + /** + * Binds this thread to the given group + */ + static void bindToGroup(AsynchronousChannelGroupImpl group) { + myGroupAndInvokeCount.set(new GroupAndInvokeCount(group)); + } + + /** + * Returns the GroupAndInvokeCount object for this thread. + */ + static GroupAndInvokeCount getGroupAndInvokeCount() { + return myGroupAndInvokeCount.get(); + } + + /** + * Returns true if the current thread is in a channel group's thread pool + */ + static boolean isBoundToAnyGroup() { + return myGroupAndInvokeCount.get() != null; + } + + /** + * Returns true if the current thread is in the given channel's thread + * pool and we haven't exceeded the maximum number of handler frames on + * the stack. + */ + static boolean mayInvokeDirect(GroupAndInvokeCount myGroupAndInvokeCount, + AsynchronousChannelGroupImpl group) + { + if ((myGroupAndInvokeCount != null) && + (myGroupAndInvokeCount.group() == group) && + (myGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount)) + { + return true; + } + return false; + } + + /** + * Invoke handler without checking the thread identity or number of handlers + * on the thread stack. + */ + @SuppressWarnings("unchecked") + static <V,A> void invokeUnchecked(CompletionHandler<V,? super A> handler, + AbstractFuture<V,A> result) + { + if (handler != null && !result.isCancelled()) { + Throwable exc = result.exception(); + if (exc == null) { + handler.completed(result.value(), result.attachment()); + } else { + handler.failed(exc, result.attachment()); + } + + // clear interrupt + Thread.interrupted(); + } + } + + + /** + * Invoke handler after incrementing the invoke count. + */ + static <V,A> void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount, + CompletionHandler<V,? super A> handler, + AbstractFuture<V,A> result) + { + myGroupAndInvokeCount.incrementInvokeCount(); + invokeUnchecked(handler, result); + } + + /** + * Invokes the handler. If the current thread is in the channel group's + * thread pool then the handler is invoked directly, otherwise it is + * invoked indirectly. + */ + static <V,A> void invoke(CompletionHandler<V,? super A> handler, + AbstractFuture<V,A> result) + { + if (handler != null) { + boolean invokeDirect = false; + boolean identityOkay = false; + GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); + if (thisGroupAndInvokeCount != null) { + AsynchronousChannel channel = result.channel(); + if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group())) + identityOkay = true; + if (identityOkay && + (thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount)) + { + // group match + invokeDirect = true; + } + } + if (invokeDirect) { + thisGroupAndInvokeCount.incrementInvokeCount(); + invokeUnchecked(handler, result); + } else { + try { + invokeIndirectly(handler, result); + } catch (RejectedExecutionException ree) { + // channel group shutdown; fallback to invoking directly + // if the current thread has the right identity. + if (identityOkay) { + invokeUnchecked(handler, result); + } else { + throw new ShutdownChannelGroupException(); + } + } + } + } + } + + /** + * Invokes the handler "indirectly" in the channel group's thread pool. + */ + static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler, + final AbstractFuture<V,A> result) + { + if (handler != null) { + AsynchronousChannel channel = result.channel(); + try { + ((Groupable)channel).group().executeOnPooledThread(new Runnable() { + public void run() { + GroupAndInvokeCount thisGroupAndInvokeCount = + myGroupAndInvokeCount.get(); + if (thisGroupAndInvokeCount != null) + thisGroupAndInvokeCount.setInvokeCount(1); + invokeUnchecked(handler, result); + } + }); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); + } + } + } + + /** + * Invokes the handler "indirectly" in the given Executor + */ + static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler, + final AbstractFuture<V,A> result, + Executor executor) + { + if (handler != null) { + try { + executor.execute(new Runnable() { + public void run() { + invokeUnchecked(handler, result); + } + }); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); + } + } + } + + /** + * Invokes the given task on the thread pool associated with the given + * channel. If the current thread is in the thread pool then the task is + * invoked directly. + */ + static void invokeOnThreadInThreadPool(Groupable channel, + Runnable task) + { + boolean invokeDirect; + GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); + AsynchronousChannelGroupImpl targetGroup = channel.group(); + if (thisGroupAndInvokeCount == null) { + invokeDirect = false; + } else { + invokeDirect = (thisGroupAndInvokeCount.group == targetGroup); + } + try { + if (invokeDirect) { + task.run(); + } else { + targetGroup.executeOnPooledThread(task); + } + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); + } + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java b/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java index 687f79c0095..0089ffd4440 100644 --- a/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,7 +85,7 @@ class MembershipKeyImpl this.sourceAddress = sourceAddress; } - int group() { + int groupAddress() { return groupAddress; } @@ -120,7 +120,7 @@ class MembershipKeyImpl this.sourceAddress = sourceAddress; } - byte[] group() { + byte[] groupAddress() { return groupAddress; } @@ -142,28 +142,28 @@ class MembershipKeyImpl valid = false; } - public void drop() throws IOException { + public void drop() { // delegate to channel ((DatagramChannelImpl)ch).drop(this); } @Override - public MulticastChannel getChannel() { + public MulticastChannel channel() { return ch; } @Override - public InetAddress getGroup() { + public InetAddress group() { return group; } @Override - public NetworkInterface getNetworkInterface() { + public NetworkInterface networkInterface() { return interf; } @Override - public InetAddress getSourceAddress() { + public InetAddress sourceAddress() { return source; } @@ -191,9 +191,7 @@ class MembershipKeyImpl } @Override - public MembershipKey unblock(InetAddress toUnblock) - throws IOException - { + public MembershipKey unblock(InetAddress toUnblock) { synchronized (stateLock) { if ((blockedSet == null) || !blockedSet.contains(toUnblock)) throw new IllegalStateException("not blocked"); diff --git a/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java b/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java index 5a2a8ef7447..fc90be39d16 100644 --- a/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java +++ b/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,20 +55,20 @@ class MembershipRegistry { List<MembershipKeyImpl> keys = groups.get(group); if (keys != null) { for (MembershipKeyImpl key: keys) { - if (key.getNetworkInterface().equals(interf)) { + if (key.networkInterface().equals(interf)) { // already a member to receive all packets so return // existing key or detect conflict if (source == null) { - if (key.getSourceAddress() == null) + if (key.sourceAddress() == null) return key; throw new IllegalStateException("Already a member to receive all packets"); } // already have source-specific membership so return key // or detect conflict - if (key.getSourceAddress() == null) + if (key.sourceAddress() == null) throw new IllegalStateException("Already have source-specific membership"); - if (source.equals(key.getSourceAddress())) + if (source.equals(key.sourceAddress())) return key; } } @@ -81,7 +81,7 @@ class MembershipRegistry { * Add membership to the registry, returning a new membership key. */ void add(MembershipKeyImpl key) { - InetAddress group = key.getGroup(); + InetAddress group = key.group(); List<MembershipKeyImpl> keys; if (groups == null) { groups = new HashMap<InetAddress,List<MembershipKeyImpl>>(); @@ -100,7 +100,7 @@ class MembershipRegistry { * Remove a key from the registry */ void remove(MembershipKeyImpl key) { - InetAddress group = key.getGroup(); + InetAddress group = key.group(); List<MembershipKeyImpl> keys = groups.get(group); if (keys != null) { Iterator<MembershipKeyImpl> i = keys.iterator(); @@ -120,9 +120,11 @@ class MembershipRegistry { * Invalidate all keys in the registry */ void invalidateAll() { - for (InetAddress group: groups.keySet()) { - for (MembershipKeyImpl key: groups.get(group)) { - key.invalidate(); + if (groups != null) { + for (InetAddress group: groups.keySet()) { + for (MembershipKeyImpl key: groups.get(group)) { + key.invalidate(); + } } } } diff --git a/jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java b/jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java index 612befcbbd0..a009541d97c 100644 --- a/jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java +++ b/jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ class NativeThreadSet { private long[] elts; private int used = 0; + private boolean waitingToEmpty; NativeThreadSet(int n) { elts = new long[n]; @@ -75,12 +76,14 @@ class NativeThreadSet { synchronized (this) { elts[i] = 0; used--; + if (used == 0 && waitingToEmpty) + notifyAll(); } } // Signals all threads in this set. // - void signal() { + void signalAndWait() { synchronized (this) { int u = used; int n = elts.length; @@ -92,7 +95,12 @@ class NativeThreadSet { if (--u == 0) break; } + waitingToEmpty = true; + while (used > 0) { + try { + wait(); + } catch (InterruptedException ignore) { } + } } } - } diff --git a/jdk/src/share/classes/sun/nio/ch/Net.java b/jdk/src/share/classes/sun/nio/ch/Net.java index ba0ba0bdcde..f910c5db05e 100644 --- a/jdk/src/share/classes/sun/nio/ch/Net.java +++ b/jdk/src/share/classes/sun/nio/ch/Net.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,7 +207,7 @@ class Net { // package-private // -- Socket options static void setSocketOption(FileDescriptor fd, ProtocolFamily family, - SocketOption name, Object value) + SocketOption<?> name, Object value) throws IOException { if (value == null) @@ -262,7 +262,7 @@ class Net { // package-private } static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, - SocketOption name) + SocketOption<?> name) throws IOException { Class<?> type = name.type(); diff --git a/jdk/src/share/classes/sun/nio/ch/OptionKey.java b/jdk/src/share/classes/sun/nio/ch/OptionKey.java index 70ba8a6fa71..88474533587 100644 --- a/jdk/src/share/classes/sun/nio/ch/OptionKey.java +++ b/jdk/src/share/classes/sun/nio/ch/OptionKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/jdk/src/share/classes/sun/nio/ch/PendingFuture.java b/jdk/src/share/classes/sun/nio/ch/PendingFuture.java new file mode 100644 index 00000000000..d88cf233a82 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/PendingFuture.java @@ -0,0 +1,257 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.util.concurrent.*; +import java.io.IOException; + +/** + * A Future for a pending I/O operation. A PendingFuture allows for the + * attachment of an additional arbitrary context object and a timer task. + */ + +final class PendingFuture<V,A> + extends AbstractFuture<V,A> +{ + private static final CancellationException CANCELLED = + new CancellationException(); + + private final CompletionHandler<V,? super A> handler; + + // true if result (or exception) is available + private volatile boolean haveResult; + private volatile V result; + private volatile Throwable exc; + + // latch for waiting (created lazily if needed) + private CountDownLatch latch; + + // optional timer task that is cancelled when result becomes available + private Future<?> timeoutTask; + + // optional context object + private volatile Object context; + + + PendingFuture(AsynchronousChannel channel, + CompletionHandler<V,? super A> handler, + A attachment, + Object context) + { + super(channel, attachment); + this.handler = handler; + this.context = context; + } + + PendingFuture(AsynchronousChannel channel, + CompletionHandler<V,? super A> handler, + A attachment) + { + super(channel, attachment); + this.handler = handler; + } + + CompletionHandler<V,? super A> handler() { + return handler; + } + + void setContext(Object context) { + this.context = context; + } + + Object getContext() { + return context; + } + + void setTimeoutTask(Future<?> task) { + synchronized (this) { + if (haveResult) { + task.cancel(false); + } else { + this.timeoutTask = task; + } + } + } + + // creates latch if required; return true if caller needs to wait + private boolean prepareForWait() { + synchronized (this) { + if (haveResult) { + return false; + } else { + if (latch == null) + latch = new CountDownLatch(1); + return true; + } + } + } + + /** + * Sets the result, or a no-op if the result or exception is already set. + */ + boolean setResult(V res) { + synchronized (this) { + if (haveResult) + return false; + result = res; + haveResult = true; + if (timeoutTask != null) + timeoutTask.cancel(false); + if (latch != null) + latch.countDown(); + return true; + } + } + + /** + * Sets the result, or a no-op if the result or exception is already set. + */ + boolean setFailure(Throwable x) { + if (!(x instanceof IOException) && !(x instanceof SecurityException)) + x = new IOException(x); + synchronized (this) { + if (haveResult) + return false; + exc = x; + haveResult = true; + if (timeoutTask != null) + timeoutTask.cancel(false); + if (latch != null) + latch.countDown(); + return true; + } + } + + @Override + public V get() throws ExecutionException, InterruptedException { + if (!haveResult) { + boolean needToWait = prepareForWait(); + if (needToWait) + latch.await(); + } + if (exc != null) { + if (exc == CANCELLED) + throw new CancellationException(); + throw new ExecutionException(exc); + } + return result; + } + + @Override + public V get(long timeout, TimeUnit unit) + throws ExecutionException, InterruptedException, TimeoutException + { + if (!haveResult) { + boolean needToWait = prepareForWait(); + if (needToWait) + if (!latch.await(timeout, unit)) throw new TimeoutException(); + } + if (exc != null) { + if (exc == CANCELLED) + throw new CancellationException(); + throw new ExecutionException(exc); + } + return result; + } + + @Override + Throwable exception() { + return (exc != CANCELLED) ? exc : null; + } + + @Override + V value() { + return result; + } + + @Override + public boolean isCancelled() { + return (exc == CANCELLED); + } + + @Override + public boolean isDone() { + return haveResult; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + synchronized (this) { + if (haveResult) + return false; // already completed + + // A shutdown of the channel group will close all channels and + // shutdown the executor. To ensure that the completion handler + // is executed we queue the task while holding the lock. + if (handler != null) { + prepareForWait(); + Runnable cancelTask = new Runnable() { + public void run() { + while (!haveResult) { + try { + latch.await(); + } catch (InterruptedException ignore) { } + } + handler.cancelled(attachment()); + } + }; + AsynchronousChannel ch = channel(); + if (ch instanceof Groupable) { + ((Groupable)ch).group().executeOnPooledThread(cancelTask); + } else { + if (ch instanceof AsynchronousFileChannelImpl) { + ((AsynchronousFileChannelImpl)ch).executor().execute(cancelTask); + } else { + throw new AssertionError("Should not get here"); + } + } + } + + // notify channel + if (channel() instanceof Cancellable) + ((Cancellable)channel()).onCancel(this); + + // set result and cancel timer + exc = CANCELLED; + haveResult = true; + if (timeoutTask != null) + timeoutTask.cancel(false); + } + + // close channel if forceful cancel + if (mayInterruptIfRunning) { + try { + channel().close(); + } catch (IOException ignore) { } + } + + // release waiters (this also releases the invoker) + if (latch != null) + latch.countDown(); + return true; + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/Reflect.java b/jdk/src/share/classes/sun/nio/ch/Reflect.java index 913357fcd9e..cc4716eb1ad 100644 --- a/jdk/src/share/classes/sun/nio/ch/Reflect.java +++ b/jdk/src/share/classes/sun/nio/ch/Reflect.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ class Reflect { // package-private { try { Class<?> cl = Class.forName(className); - Constructor c = cl.getDeclaredConstructor(paramTypes); + Constructor<?> c = cl.getDeclaredConstructor(paramTypes); setAccessible(c); return c; } catch (ClassNotFoundException x) { @@ -79,7 +79,7 @@ class Reflect { // package-private static Method lookupMethod(String className, String methodName, - Class[] paramTypes) + Class... paramTypes) { try { Class<?> cl = Class.forName(className); diff --git a/jdk/src/share/classes/sun/nio/ch/SelChImpl.java b/jdk/src/share/classes/sun/nio/ch/SelChImpl.java index 0ef4d357f8d..fb1571d84d2 100644 --- a/jdk/src/share/classes/sun/nio/ch/SelChImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/SelChImpl.java @@ -25,6 +25,7 @@ package sun.nio.ch; +import java.nio.channels.Channel; import java.io.FileDescriptor; import java.io.IOException; @@ -35,7 +36,7 @@ import java.io.IOException; * @since 1.4 */ -interface SelChImpl { +interface SelChImpl extends Channel { FileDescriptor getFD(); diff --git a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index fd532980b0b..0b0e4b6aee2 100644 --- a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,11 @@ package sun.nio.ch; import java.io.FileDescriptor; import java.io.IOException; -import java.lang.reflect.*; import java.net.*; import java.nio.channels.*; import java.nio.channels.spi.*; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.*; +import sun.net.NetHooks; /** @@ -111,19 +109,19 @@ class ServerSocketChannelImpl public SocketAddress getLocalAddress() throws IOException { synchronized (stateLock) { if (!isOpen()) - return null; + throw new ClosedChannelException(); return localAddress; } } @Override - public ServerSocketChannel setOption(SocketOption name, Object value) + public <T> ServerSocketChannel setOption(SocketOption<T> name, T value) throws IOException { if (name == null) throw new NullPointerException(); - if (!options().contains(name)) - throw new IllegalArgumentException("invalid option name"); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); synchronized (stateLock) { if (!isOpen()) @@ -142,8 +140,8 @@ class ServerSocketChannelImpl { if (name == null) throw new NullPointerException(); - if (!options().contains(name)) - throw new IllegalArgumentException("invalid option name"); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); synchronized (stateLock) { if (!isOpen()) @@ -154,7 +152,7 @@ class ServerSocketChannelImpl } } - private static class LazyInitialization { + private static class DefaultOptionsHolder { static final Set<SocketOption<?>> defaultOptions = defaultOptions(); private static Set<SocketOption<?>> defaultOptions() { @@ -166,8 +164,8 @@ class ServerSocketChannelImpl } @Override - public final Set<SocketOption<?>> options() { - return LazyInitialization.defaultOptions; + public final Set<SocketOption<?>> supportedOptions() { + return DefaultOptionsHolder.defaultOptions; } public boolean isBound() { @@ -194,6 +192,7 @@ class ServerSocketChannelImpl SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkListen(isa.getPort()); + NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); Net.bind(fd, isa.getAddress(), isa.getPort()); Net.listen(fd, backlog < 1 ? 50 : backlog); synchronized (stateLock) { diff --git a/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java new file mode 100644 index 00000000000..47c3b2abd29 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java @@ -0,0 +1,612 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.*; +import java.security.AccessController; +import java.security.AccessControlContext; +import java.security.PrivilegedExceptionAction; +import java.security.PrivilegedActionException; + +/** + * A prototype implementation of AsynchronousDatagramChannel, used to aid + * test and spec development. + */ + +class SimpleAsynchronousDatagramChannelImpl + extends AsynchronousDatagramChannel implements Groupable, Cancellable +{ + private final DatagramChannel dc; + private final AsynchronousChannelGroupImpl group; + private final Object attachKey; + private boolean closed; + + // used to coordinate timed and blocking reads + private final Object readLock = new Object(); + + // channel blocking mode (requires readLock) + private boolean isBlocking = true; + + // number of blocking readers (requires readLock) + private int blockingReaderCount; + + // true if timed read attempted while blocking read in progress (requires readLock) + private boolean transitionToNonBlocking; + + // true if a blocking read is cancelled (requires readLock) + private boolean blockingReadKilledByCancel; + + // temporary Selectors used by timed reads (requires readLock) + private Selector firstReader; + private Set<Selector> otherReaders; + + SimpleAsynchronousDatagramChannelImpl(ProtocolFamily family, + AsynchronousChannelGroupImpl group) + throws IOException + { + super(group.provider()); + this.dc = (family == null) ? + DatagramChannel.open() : DatagramChannel.open(family); + this.group = group; + + // attach this channel to the group as foreign channel + boolean registered = false; + try { + if (!(dc instanceof DatagramChannelImpl)) + throw new UnsupportedOperationException(); + attachKey = group + .attachForeignChannel(this, ((DatagramChannelImpl)dc).getFD()); + registered = true; + } finally { + if (!registered) + dc.close(); + } + } + + // throws RuntimeException if blocking read has been cancelled + private void ensureBlockingReadNotKilled() { + assert Thread.holdsLock(readLock); + if (blockingReadKilledByCancel) + throw new RuntimeException("Reading not allowed due to cancellation"); + } + + // invoke prior to non-timed read/receive + private void beginNoTimeoutRead() { + synchronized (readLock) { + ensureBlockingReadNotKilled(); + if (isBlocking) + blockingReaderCount++; + } + } + + // invoke after non-timed read/receive has completed + private void endNoTimeoutRead() { + synchronized (readLock) { + if (isBlocking) { + if (--blockingReaderCount == 0 && transitionToNonBlocking) { + // notify any threads waiting to make channel non-blocking + readLock.notifyAll(); + } + } + } + } + + // invoke prior to timed read + // returns the timeout remaining + private long prepareForTimedRead(PendingFuture<?,?> result, long timeout) + throws IOException + { + synchronized (readLock) { + ensureBlockingReadNotKilled(); + if (isBlocking) { + transitionToNonBlocking = true; + while (blockingReaderCount > 0 && + timeout > 0L && + !result.isCancelled()) + { + long st = System.currentTimeMillis(); + try { + readLock.wait(timeout); + } catch (InterruptedException e) { } + timeout -= System.currentTimeMillis() - st; + } + if (blockingReaderCount == 0) { + // re-check that blocked read wasn't cancelled + ensureBlockingReadNotKilled(); + // no blocking reads so change channel to non-blocking + dc.configureBlocking(false); + isBlocking = false; + } + } + return timeout; + } + } + + // returns a temporary Selector + private Selector getSelector() throws IOException { + Selector sel = Util.getTemporarySelector(dc); + synchronized (readLock) { + if (firstReader == null) { + firstReader = sel; + } else { + if (otherReaders == null) + otherReaders = new HashSet<Selector>(); + otherReaders.add(sel); + } + } + return sel; + } + + // releases a temporary Selector + private void releaseSelector(Selector sel) throws IOException { + synchronized (readLock) { + if (firstReader == sel) { + firstReader = null; + } else { + otherReaders.remove(sel); + } + } + Util.releaseTemporarySelector(sel); + } + + // wakeup all Selectors currently in use + private void wakeupSelectors() { + synchronized (readLock) { + if (firstReader != null) + firstReader.wakeup(); + if (otherReaders != null) { + for (Selector sel: otherReaders) { + sel.wakeup(); + } + } + } + } + + @Override + public AsynchronousChannelGroupImpl group() { + return group; + } + + @Override + public boolean isOpen() { + return dc.isOpen(); + } + + @Override + public void onCancel(PendingFuture<?,?> task) { + synchronized (readLock) { + if (blockingReaderCount > 0) { + blockingReadKilledByCancel = true; + readLock.notifyAll(); + return; + } + } + wakeupSelectors(); + } + + @Override + public void close() throws IOException { + synchronized (dc) { + if (closed) + return; + closed = true; + } + // detach from group and close underlying channel + group.detachForeignChannel(attachKey); + dc.close(); + + // wakeup any threads blocked in timed read/receives + wakeupSelectors(); + } + + @Override + public AsynchronousDatagramChannel connect(SocketAddress remote) + throws IOException + { + dc.connect(remote); + return this; + } + + @Override + public AsynchronousDatagramChannel disconnect() throws IOException { + dc.disconnect(); + return this; + } + + private static class WrappedMembershipKey extends MembershipKey { + private final MulticastChannel channel; + private final MembershipKey key; + + WrappedMembershipKey(MulticastChannel channel, MembershipKey key) { + this.channel = channel; + this.key = key; + } + + @Override + public boolean isValid() { + return key.isValid(); + } + + @Override + public void drop() { + key.drop(); + } + + @Override + public MulticastChannel channel() { + return channel; + } + + @Override + public InetAddress group() { + return key.group(); + } + + @Override + public NetworkInterface networkInterface() { + return key.networkInterface(); + } + + @Override + public InetAddress sourceAddress() { + return key.sourceAddress(); + } + + @Override + public MembershipKey block(InetAddress toBlock) throws IOException { + key.block(toBlock); + return this; + } + + @Override + public MembershipKey unblock(InetAddress toUnblock) { + key.unblock(toUnblock); + return this; + } + + @Override + public String toString() { + return key.toString(); + } + } + + @Override + public MembershipKey join(InetAddress group, + NetworkInterface interf) + throws IOException + { + MembershipKey key = ((MulticastChannel)dc).join(group, interf); + return new WrappedMembershipKey(this, key); + } + + @Override + public MembershipKey join(InetAddress group, + NetworkInterface interf, + InetAddress source) + throws IOException + { + MembershipKey key = ((MulticastChannel)dc).join(group, interf, source); + return new WrappedMembershipKey(this, key); + } + + @Override + public <A> Future<Integer> send(ByteBuffer src, + SocketAddress target, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + if (timeout < 0L) + throw new IllegalArgumentException("Negative timeout"); + if (unit == null) + throw new NullPointerException(); + + CompletedFuture<Integer,A> result; + try { + int n = dc.send(src, target); + result = CompletedFuture.withResult(this, n, attachment); + } catch (IOException ioe) { + result = CompletedFuture.withFailure(this, ioe, attachment); + } + Invoker.invoke(handler, result); + return result; + } + + @Override + public <A> Future<Integer> write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + if (timeout < 0L) + throw new IllegalArgumentException("Negative timeout"); + if (unit == null) + throw new NullPointerException(); + + CompletedFuture<Integer,A> result; + try { + int n = dc.write(src); + result = CompletedFuture.withResult(this, n, attachment); + } catch (IOException ioe) { + result = CompletedFuture.withFailure(this, ioe, attachment); + } + Invoker.invoke(handler, result); + return result; + } + + /** + * Receive into the given buffer with privileges enabled and restricted by + * the given AccessControlContext (can be null). + */ + private SocketAddress doRestrictedReceive(final ByteBuffer dst, + AccessControlContext acc) + throws IOException + { + if (acc == null) { + return dc.receive(dst); + } else { + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction<SocketAddress>() { + public SocketAddress run() throws IOException { + return dc.receive(dst); + }}, acc); + } catch (PrivilegedActionException pae) { + Exception cause = pae.getException(); + if (cause instanceof SecurityException) + throw (SecurityException)cause; + throw (IOException)cause; + } + } + } + + @Override + public <A> Future<SocketAddress> receive(final ByteBuffer dst, + final long timeout, + final TimeUnit unit, + A attachment, + final CompletionHandler<SocketAddress,? super A> handler) + { + if (dst.isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + if (timeout < 0L) + throw new IllegalArgumentException("Negative timeout"); + if (unit == null) + throw new NullPointerException(); + + // complete immediately if channel closed + if (!isOpen()) { + CompletedFuture<SocketAddress,A> result = CompletedFuture.withFailure(this, + new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + final AccessControlContext acc = (System.getSecurityManager() == null) ? + null : AccessController.getContext(); + final PendingFuture<SocketAddress,A> result = + new PendingFuture<SocketAddress,A>(this, handler, attachment); + Runnable task = new Runnable() { + public void run() { + try { + SocketAddress remote = null; + long to; + if (timeout == 0L) { + beginNoTimeoutRead(); + try { + remote = doRestrictedReceive(dst, acc); + } finally { + endNoTimeoutRead(); + } + to = 0L; + } else { + to = prepareForTimedRead(result, unit.toMillis(timeout)); + if (to <= 0L) + throw new InterruptedByTimeoutException(); + remote = doRestrictedReceive(dst, acc); + } + if (remote == null) { + Selector sel = getSelector(); + SelectionKey sk = null; + try { + sk = dc.register(sel, SelectionKey.OP_READ); + for (;;) { + if (!dc.isOpen()) + throw new AsynchronousCloseException(); + if (result.isCancelled()) + break; + long st = System.currentTimeMillis(); + int ns = sel.select(to); + if (ns > 0) { + remote = doRestrictedReceive(dst, acc); + if (remote != null) + break; + } + sel.selectedKeys().remove(sk); + if (timeout != 0L) { + to -= System.currentTimeMillis() - st; + if (to <= 0) + throw new InterruptedByTimeoutException(); + } + } + } finally { + if (sk != null) + sk.cancel(); + releaseSelector(sel); + } + } + result.setResult(remote); + } catch (Throwable x) { + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + result.setFailure(x); + } + Invoker.invokeUnchecked(handler, result); + } + }; + try { + group.executeOnPooledThread(task); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); + } + return result; + } + + @Override + public <A> Future<Integer> read(final ByteBuffer dst, + final long timeout, + final TimeUnit unit, + A attachment, + final CompletionHandler<Integer,? super A> handler) + { + if (dst.isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + if (timeout < 0L) + throw new IllegalArgumentException("Negative timeout"); + if (unit == null) + throw new NullPointerException(); + // another thread may disconnect before read is initiated + if (!dc.isConnected()) + throw new NotYetConnectedException(); + + // complete immediately if channel closed + if (!isOpen()) { + CompletedFuture<Integer,A> result = CompletedFuture.withFailure(this, + new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + final PendingFuture<Integer,A> result = + new PendingFuture<Integer,A>(this, handler, attachment); + Runnable task = new Runnable() { + public void run() { + try { + int n = 0; + long to; + if (timeout == 0L) { + beginNoTimeoutRead(); + try { + n = dc.read(dst); + } finally { + endNoTimeoutRead(); + } + to = 0L; + } else { + to = prepareForTimedRead(result, unit.toMillis(timeout)); + if (to <= 0L) + throw new InterruptedByTimeoutException(); + n = dc.read(dst); + } + if (n == 0) { + Selector sel = getSelector(); + SelectionKey sk = null; + try { + sk = dc.register(sel, SelectionKey.OP_READ); + for (;;) { + if (!dc.isOpen()) + throw new AsynchronousCloseException(); + if (result.isCancelled()) + break; + long st = System.currentTimeMillis(); + int ns = sel.select(to); + if (ns > 0) { + if ((n = dc.read(dst)) != 0) + break; + } + sel.selectedKeys().remove(sk); + if (timeout != 0L) { + to -= System.currentTimeMillis() - st; + if (to <= 0) + throw new InterruptedByTimeoutException(); + } + } + } finally { + if (sk != null) + sk.cancel(); + releaseSelector(sel); + } + } + result.setResult(n); + } catch (Throwable x) { + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + result.setFailure(x); + } + Invoker.invokeUnchecked(handler, result); + } + }; + try { + group.executeOnPooledThread(task); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); + } + return result; + } + + @Override + public AsynchronousDatagramChannel bind(SocketAddress local) + throws IOException + { + dc.bind(local); + return this; + } + + @Override + public SocketAddress getLocalAddress() throws IOException { + return dc.getLocalAddress(); + } + + @Override + public <T> AsynchronousDatagramChannel setOption(SocketOption<T> name, T value) + throws IOException + { + dc.setOption(name, value); + return this; + } + + @Override + public <T> T getOption(SocketOption<T> name) throws IOException { + return dc.getOption(name); + } + + @Override + public Set<SocketOption<?>> supportedOptions() { + return dc.supportedOptions(); + } + + @Override + public SocketAddress getRemoteAddress() throws IOException { + return dc.getRemoteAddress(); + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java new file mode 100644 index 00000000000..52fe5a2802f --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java @@ -0,0 +1,426 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.util.concurrent.*; +import java.nio.ByteBuffer; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * "Portable" implementation of AsynchronousFileChannel for use on operating + * systems that don't support asynchronous file I/O. + */ + +public class SimpleAsynchronousFileChannelImpl + extends AsynchronousFileChannelImpl +{ + // lazy initialization of default thread pool for file I/O + private static class DefaultExecutorHolder { + static final ExecutorService defaultExecutor = + ThreadPool.createDefault().executor(); + } + + // Used to make native read and write calls + private static final FileDispatcher nd = new FileDispatcherImpl(); + + // indicates if the associated thread pool is the default thread pool + private final boolean isDefaultExecutor; + + // Thread-safe set of IDs of native threads, for signalling + private final NativeThreadSet threads = new NativeThreadSet(2); + + + SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj, + boolean reading, + boolean writing, + ExecutorService executor, + boolean isDefaultexecutor) + { + super(fdObj, reading, writing, executor); + this.isDefaultExecutor = isDefaultexecutor; + } + + public static AsynchronousFileChannel open(FileDescriptor fdo, + boolean reading, + boolean writing, + ThreadPool pool) + { + // Executor is either default or based on pool parameters + ExecutorService executor; + boolean isDefaultexecutor; + if (pool == null) { + executor = DefaultExecutorHolder.defaultExecutor; + isDefaultexecutor = true; + } else { + executor = pool.executor(); + isDefaultexecutor = false; + } + return new SimpleAsynchronousFileChannelImpl(fdo, + reading, writing, executor, isDefaultexecutor); + } + + @Override + public void close() throws IOException { + // mark channel as closed + synchronized (fdObj) { + if (closed) + return; // already closed + closed = true; + // from this point on, if another thread invokes the begin() method + // then it will throw ClosedChannelException + } + + // signal any threads blocked on this channel + nd.preClose(fdObj); + threads.signalAndWait(); + + // wait until all async I/O operations have completely gracefully + closeLock.writeLock().lock(); + try { + // do nothing + } finally { + closeLock.writeLock().unlock(); + } + + // Invalidate and release any locks that we still hold + invalidateAllLocks(); + + // close file + nd.close(fdObj); + + // shutdown executor if specific to this channel + if (!isDefaultExecutor) { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + executor.shutdown(); + return null; + } + }); + } + } + + @Override + public long size() throws IOException { + int ti = threads.add(); + try { + long n = 0L; + try { + begin(); + do { + n = nd.size(fdObj); + } while ((n == IOStatus.INTERRUPTED) && isOpen()); + return n; + } finally { + end(n >= 0L); + } + } finally { + threads.remove(ti); + } + } + + @Override + public AsynchronousFileChannel truncate(long size) throws IOException { + if (size < 0L) + throw new IllegalArgumentException("Negative size"); + if (!writing) + throw new NonWritableChannelException(); + int ti = threads.add(); + try { + long n = 0L; + try { + begin(); + do { + n = nd.size(fdObj); + } while ((n == IOStatus.INTERRUPTED) && isOpen()); + + // truncate file if 'size' less than current size + if (size < n && isOpen()) { + do { + n = nd.truncate(fdObj, size); + } while ((n == IOStatus.INTERRUPTED) && isOpen()); + } + return this; + } finally { + end(n > 0); + } + } finally { + threads.remove(ti); + } + } + + @Override + public void force(boolean metaData) throws IOException { + int ti = threads.add(); + try { + int n = 0; + try { + begin(); + do { + n = nd.force(fdObj, metaData); + } while ((n == IOStatus.INTERRUPTED) && isOpen()); + } finally { + end(n >= 0); + } + } finally { + threads.remove(ti); + } + } + + @Override + public <A> Future<FileLock> lock(final long position, + final long size, + final boolean shared, + A attachment, + final CompletionHandler<FileLock,? super A> handler) + { + if (shared && !reading) + throw new NonReadableChannelException(); + if (!shared && !writing) + throw new NonWritableChannelException(); + + // add to lock table + final FileLockImpl fli = addToFileLockTable(position, size, shared); + if (fli == null) { + CompletedFuture<FileLock,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invokeIndirectly(handler, result, executor); + return result; + } + + final PendingFuture<FileLock,A> result = + new PendingFuture<FileLock,A>(this, handler, attachment); + Runnable task = new Runnable() { + public void run() { + int ti = threads.add(); + try { + int n; + try { + begin(); + do { + n = nd.lock(fdObj, true, position, size, shared); + } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); + if (n == FileDispatcher.LOCKED) { + result.setResult(fli); + } else { + if (n != FileDispatcher.INTERRUPTED) + throw new AssertionError(); + throw new AsynchronousCloseException(); + } + } catch (IOException x) { + removeFromFileLockTable(fli); + if (!isOpen()) + x = new AsynchronousCloseException(); + result.setFailure(x); + } finally { + end(); + } + } finally { + threads.remove(ti); + } + Invoker.invokeUnchecked(handler, result); + } + }; + try { + executor.execute(task); + } catch (RejectedExecutionException ree) { + // rollback + removeFromFileLockTable(fli); + throw new ShutdownChannelGroupException(); + } + return result; + } + + @Override + public FileLock tryLock(long position, long size, boolean shared) + throws IOException + { + if (shared && !reading) + throw new NonReadableChannelException(); + if (!shared && !writing) + throw new NonWritableChannelException(); + + // add to lock table + FileLockImpl fli = addToFileLockTable(position, size, shared); + if (fli == null) + throw new ClosedChannelException(); + + int ti = threads.add(); + boolean gotLock = false; + try { + begin(); + int n; + do { + n = nd.lock(fdObj, false, position, size, shared); + } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); + if (n != FileDispatcher.LOCKED) { + if (n == FileDispatcher.NO_LOCK) + return null; // locked by someone else + if (n == FileDispatcher.INTERRUPTED) + throw new AsynchronousCloseException(); + // should not get here + throw new AssertionError(); + } + gotLock = true; + return fli; + } finally { + if (!gotLock) + removeFromFileLockTable(fli); + end(); + threads.remove(ti); + } + } + + @Override + void release(FileLockImpl fli) throws IOException { + try { + begin(); + nd.release(fdObj, fli.position(), fli.size()); + removeFromFileLockTable(fli); + } finally { + end(); + } + } + + @Override + public <A> Future<Integer> read(final ByteBuffer dst, + final long position, + A attachment, + final CompletionHandler<Integer,? super A> handler) + { + if (position < 0) + throw new IllegalArgumentException("Negative position"); + if (!reading) + throw new NonReadableChannelException(); + if (dst.isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + + // complete immediately if channel closed or no space remaining + if (!isOpen() || (dst.remaining() == 0)) { + CompletedFuture<Integer,A> result; + if (isOpen()) { + result = CompletedFuture.withResult(this, 0, attachment); + } else { + result = CompletedFuture.withFailure(this, + new ClosedChannelException(), attachment); + } + Invoker.invokeIndirectly(handler, result, executor); + return result; + } + + final PendingFuture<Integer,A> result = + new PendingFuture<Integer,A>(this, handler, attachment); + Runnable task = new Runnable() { + public void run() { + int ti = threads.add(); + try { + begin(); + int n; + do { + n = IOUtil.read(fdObj, dst, position, nd, null); + } while ((n == IOStatus.INTERRUPTED) && isOpen()); + if (n < 0 && !isOpen()) + throw new AsynchronousCloseException(); + result.setResult(n); + } catch (IOException x) { + if (!isOpen()) + x = new AsynchronousCloseException(); + result.setFailure(x); + } finally { + end(); + threads.remove(ti); + } + Invoker.invokeUnchecked(handler, result); + } + }; + try { + executor.execute(task); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); + } + return result; + } + + @Override + public <A> Future<Integer> write(final ByteBuffer src, + final long position, + A attachment, + final CompletionHandler<Integer,? super A> handler) + { + if (position < 0) + throw new IllegalArgumentException("Negative position"); + if (!writing) + throw new NonWritableChannelException(); + + // complete immediately if channel is closed or no bytes remaining + if (!isOpen() || (src.remaining() == 0)) { + CompletedFuture<Integer,A> result; + if (isOpen()) { + result = CompletedFuture.withResult(this, 0, attachment); + } else { + result = CompletedFuture.withFailure(this, + new ClosedChannelException(), attachment); + } + Invoker.invokeIndirectly(handler, result, executor); + return result; + } + + final PendingFuture<Integer,A> result = + new PendingFuture<Integer,A>(this, handler, attachment); + Runnable task = new Runnable() { + public void run() { + int ti = threads.add(); + try { + begin(); + int n; + do { + n = IOUtil.write(fdObj, src, position, nd, null); + } while ((n == IOStatus.INTERRUPTED) && isOpen()); + if (n < 0 && !isOpen()) + throw new AsynchronousCloseException(); + result.setResult(n); + } catch (IOException x) { + if (!isOpen()) + x = new AsynchronousCloseException(); + result.setFailure(x); + } finally { + end(); + threads.remove(ti); + } + Invoker.invokeUnchecked(handler, result); + } + }; + try { + executor.execute(task); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); + } + return result; + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java index 11567ba2ab7..ec4f8f5754b 100644 --- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; +import sun.net.NetHooks; /** @@ -128,28 +129,28 @@ class SocketChannelImpl public SocketAddress getLocalAddress() throws IOException { synchronized (stateLock) { if (!isOpen()) - return null; + throw new ClosedChannelException(); return localAddress; } } @Override - public SocketAddress getConnectedAddress() throws IOException { + public SocketAddress getRemoteAddress() throws IOException { synchronized (stateLock) { if (!isOpen()) - return null; + throw new ClosedChannelException(); return remoteAddress; } } @Override - public SocketChannel setOption(SocketOption name, Object value) + public <T> SocketChannel setOption(SocketOption<T> name, T value) throws IOException { if (name == null) throw new NullPointerException(); - if (!options().contains(name)) - throw new IllegalArgumentException("Invalid option name"); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); synchronized (stateLock) { if (!isOpen()) @@ -175,8 +176,8 @@ class SocketChannelImpl { if (name == null) throw new NullPointerException(); - if (!options().contains(name)) - throw new IllegalArgumentException("Invalid option name"); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); synchronized (stateLock) { if (!isOpen()) @@ -193,7 +194,7 @@ class SocketChannelImpl } } - private static class LazyInitialization { + private static class DefaultOptionsHolder { static final Set<SocketOption<?>> defaultOptions = defaultOptions(); private static Set<SocketOption<?>> defaultOptions() { @@ -212,8 +213,8 @@ class SocketChannelImpl } @Override - public final Set<SocketOption<?>> options() { - return LazyInitialization.defaultOptions; + public final Set<SocketOption<?>> supportedOptions() { + return DefaultOptionsHolder.defaultOptions; } private boolean ensureReadOpen() throws ClosedChannelException { @@ -526,6 +527,7 @@ class SocketChannelImpl throw new AlreadyBoundException(); InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : Net.checkAddress(local); + NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); Net.bind(fd, isa.getAddress(), isa.getPort()); localAddress = Net.localAddress(fd); } @@ -577,6 +579,12 @@ class SocketChannelImpl if (!isOpen()) { return false; } + // notify hook only if unbound + if (localAddress == null) { + NetHooks.beforeTcpConnect(fd, + isa.getAddress(), + isa.getPort()); + } readerThread = NativeThread.current(); } for (;;) { diff --git a/jdk/src/share/classes/sun/nio/ch/ThreadPool.java b/jdk/src/share/classes/sun/nio/ch/ThreadPool.java new file mode 100644 index 00000000000..37e6a80a0ba --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/ThreadPool.java @@ -0,0 +1,176 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.util.concurrent.*; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; +import sun.security.action.GetIntegerAction; + +/** + * Encapsulates a thread pool associated with a channel group. + */ + +public class ThreadPool { + private static final String DEFAULT_THREAD_POOL_THREAD_FACTORY = + "java.nio.channels.DefaultThreadPool.threadFactory"; + private static final String DEFAULT_THREAD_POOL_INITIAL_SIZE = + "java.nio.channels.DefaultThreadPool.initialSize"; + private static final ThreadFactory defaultThreadFactory = new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setDaemon(true); + return t; + } + }; + + private final ExecutorService executor; + + // indicates if thread pool is fixed size + private final boolean isFixed; + + // indicates the pool size (for a fixed thread pool configuratin this is + // the maximum pool size; for other thread pools it is the initial size) + private final int poolSize; + + private ThreadPool(ExecutorService executor, + boolean isFixed, + int poolSize) + { + this.executor = executor; + this.isFixed = isFixed; + this.poolSize = poolSize; + } + + ExecutorService executor() { + return executor; + } + + boolean isFixedThreadPool() { + return isFixed; + } + + int poolSize() { + return poolSize; + } + + static ThreadFactory defaultThreadFactory() { + return defaultThreadFactory; + } + + private static class DefaultThreadPoolHolder { + final static ThreadPool defaultThreadPool = createDefault(); + } + + // return the default (system-wide) thread pool + static ThreadPool getDefault() { + return DefaultThreadPoolHolder.defaultThreadPool; + } + + // create thread using default settings (configured by system properties) + static ThreadPool createDefault() { + // default the number of fixed threads to the hardware core count + int initialSize = getDefaultThreadPoolInitialSize(); + if (initialSize < 0) + initialSize = Runtime.getRuntime().availableProcessors(); + // default to thread factory that creates daemon threads + ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory(); + if (threadFactory == null) + threadFactory = defaultThreadFactory; + // create thread pool + ExecutorService executor = + new ThreadPoolExecutor(0, Integer.MAX_VALUE, + Long.MAX_VALUE, TimeUnit.MILLISECONDS, + new SynchronousQueue<Runnable>(), + threadFactory); + return new ThreadPool(executor, false, initialSize); + } + + // create using given parameters + static ThreadPool create(int nThreads, ThreadFactory factory) { + if (nThreads <= 0) + throw new IllegalArgumentException("'nThreads' must be > 0"); + ExecutorService executor = Executors.newFixedThreadPool(nThreads, factory); + return new ThreadPool(executor, true, nThreads); + } + + // wrap a user-supplied executor + public static ThreadPool wrap(ExecutorService executor, int initialSize) { + if (executor == null) + throw new NullPointerException("'executor' is null"); + // attempt to check if cached thread pool + if (executor instanceof ThreadPoolExecutor) { + int max = ((ThreadPoolExecutor)executor).getMaximumPoolSize(); + if (max == Integer.MAX_VALUE) { + if (initialSize < 0) { + initialSize = Runtime.getRuntime().availableProcessors(); + } else { + // not a cached thread pool so ignore initial size + initialSize = 0; + } + } + } else { + // some other type of thread pool + if (initialSize < 0) + initialSize = 0; + } + return new ThreadPool(executor, false, initialSize); + } + + private static int getDefaultThreadPoolInitialSize() { + String propValue = AccessController.doPrivileged(new + GetPropertyAction(DEFAULT_THREAD_POOL_INITIAL_SIZE)); + if (propValue != null) { + try { + return Integer.parseInt(propValue); + } catch (NumberFormatException x) { + throw new Error("Value of property '" + DEFAULT_THREAD_POOL_INITIAL_SIZE + + "' is invalid: " + x); + } + } + return -1; + } + + private static ThreadFactory getDefaultThreadPoolThreadFactory() { + String propValue = AccessController.doPrivileged(new + GetPropertyAction(DEFAULT_THREAD_POOL_THREAD_FACTORY)); + if (propValue != null) { + try { + Class<?> c = Class + .forName(propValue, true, ClassLoader.getSystemClassLoader()); + return ((ThreadFactory)c.newInstance()); + } catch (ClassNotFoundException x) { + throw new Error(x); + } catch (InstantiationException x) { + throw new Error(x); + } catch (IllegalAccessException x) { + throw new Error(x); + } + } + return null; + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/Util.java b/jdk/src/share/classes/sun/nio/ch/Util.java index 534548ff778..efdce4a4b9a 100644 --- a/jdk/src/share/classes/sun/nio/ch/Util.java +++ b/jdk/src/share/classes/sun/nio/ch/Util.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.*; -import java.nio.channels.spi.*; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.*; @@ -100,6 +99,9 @@ class Util { return; } } + + // release memory + ((DirectBuffer)buf).cleaner().clean(); } private static class SelectorWrapper { diff --git a/jdk/src/share/classes/sun/nio/cs/ArrayDecoder.java b/jdk/src/share/classes/sun/nio/cs/ArrayDecoder.java new file mode 100644 index 00000000000..daff5ec39d1 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/cs/ArrayDecoder.java @@ -0,0 +1,35 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.cs; + +/* + * FastPath byte[]->char[] decoder, REPLACE on malformed or + * unmappable input. + */ + +public interface ArrayDecoder { + int decode(byte[] src, int off, int len, char[] dst); +} diff --git a/jdk/src/share/classes/sun/nio/cs/ArrayEncoder.java b/jdk/src/share/classes/sun/nio/cs/ArrayEncoder.java new file mode 100644 index 00000000000..1eb4726f70b --- /dev/null +++ b/jdk/src/share/classes/sun/nio/cs/ArrayEncoder.java @@ -0,0 +1,35 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.cs; + +/* + * FastPath char[]->byte[] encoder, REPLACE on malformed input or + * unmappable input. + */ + +public interface ArrayEncoder { + int encode(char[] src, int off, int len, byte[] dst); +} diff --git a/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java b/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java index ad27a1507ac..7eb3b5b8a83 100644 --- a/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java +++ b/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java @@ -23,9 +23,6 @@ * have any questions. */ -/* - */ - package sun.nio.cs; import java.nio.ByteBuffer; @@ -34,10 +31,7 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.MalformedInputException; -import java.nio.charset.UnmappableCharacterException; - +import java.util.Arrays; class ISO_8859_1 extends Charset @@ -65,8 +59,8 @@ class ISO_8859_1 return new Encoder(this); } - private static class Decoder extends CharsetDecoder { - + private static class Decoder extends CharsetDecoder + implements ArrayDecoder { private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); } @@ -127,10 +121,18 @@ class ISO_8859_1 return decodeBufferLoop(src, dst); } + public int decode(byte[] src, int sp, int len, char[] dst) { + if (len > dst.length) + len = dst.length; + int dp = 0; + while (dp < len) + dst[dp++] = (char)(src[sp++] & 0xff); + return dp; + } } - private static class Encoder extends CharsetEncoder { - + private static class Encoder extends CharsetEncoder + implements ArrayEncoder { private Encoder(Charset cs) { super(cs, 1.0f, 1.0f); } @@ -139,6 +141,10 @@ class ISO_8859_1 return c <= '\u00FF'; } + public boolean isLegalReplacement(byte[] repl) { + return (repl.length == 1); // we accept any byte value + } + private final Surrogate.Parser sgp = new Surrogate.Parser(); private CoderResult encodeArrayLoop(CharBuffer src, @@ -208,5 +214,31 @@ class ISO_8859_1 return encodeBufferLoop(src, dst); } + private byte repl = (byte)'?'; + protected void implReplaceWith(byte[] newReplacement) { + repl = newReplacement[0]; + } + + public int encode(char[] src, int sp, int len, byte[] dst) { + int dp = 0; + int sl = sp + Math.min(len, dst.length); + while (sp < sl) { + char c = src[sp++]; + if (c <= '\u00FF') { + dst[dp++] = (byte)c; + continue; + } + if (Surrogate.isHigh(c) && sp < sl && + Surrogate.isLow(src[sp])) { + if (len > dst.length) { + sl++; + len--; + } + sp++; + } + dst[dp++] = repl; + } + return dp; + } } } diff --git a/jdk/src/share/classes/sun/nio/cs/SingleByte.java b/jdk/src/share/classes/sun/nio/cs/SingleByte.java index fdbf4e3c643..9b0531eebd9 100644 --- a/jdk/src/share/classes/sun/nio/cs/SingleByte.java +++ b/jdk/src/share/classes/sun/nio/cs/SingleByte.java @@ -32,6 +32,7 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; +import java.util.Arrays; import static sun.nio.cs.CharsetMapping.*; public class SingleByte @@ -45,7 +46,8 @@ public class SingleByte return cr; } - public static class Decoder extends CharsetDecoder { + final public static class Decoder extends CharsetDecoder + implements ArrayDecoder { private final char[] b2c; public Decoder(Charset cs, char[] b2c) { @@ -108,9 +110,29 @@ public class SingleByte private final char decode(int b) { return b2c[b + 128]; } + + private char repl = '\uFFFD'; + protected void implReplaceWith(String newReplacement) { + repl = newReplacement.charAt(0); + } + + public int decode(byte[] src, int sp, int len, char[] dst) { + if (len > dst.length) + len = dst.length; + int dp = 0; + while (dp < len) { + dst[dp] = decode(src[sp++]); + if (dst[dp] == UNMAPPABLE_DECODING) { + dst[dp] = repl; + } + dp++; + } + return dp; + } } - public static class Encoder extends CharsetEncoder { + final public static class Encoder extends CharsetEncoder + implements ArrayEncoder { private Surrogate.Parser sgp; private final char[] c2b; private final char[] c2bIndex; @@ -125,6 +147,11 @@ public class SingleByte return encode(c) != UNMAPPABLE_ENCODING; } + public boolean isLegalReplacement(byte[] repl) { + return ((repl.length == 1 && repl[0] == (byte)'?') || + super.isLegalReplacement(repl)); + } + private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { char[] sa = src.array(); int sp = src.arrayOffset() + src.position(); @@ -200,6 +227,34 @@ public class SingleByte return UNMAPPABLE_ENCODING; return c2b[index + (ch & 0xff)]; } + + private byte repl = (byte)'?'; + protected void implReplaceWith(byte[] newReplacement) { + repl = newReplacement[0]; + } + + public int encode(char[] src, int sp, int len, byte[] dst) { + int dp = 0; + int sl = sp + Math.min(len, dst.length); + while (sp < sl) { + char c = src[sp++]; + int b = encode(c); + if (b != UNMAPPABLE_ENCODING) { + dst[dp++] = (byte)b; + continue; + } + if (Surrogate.isHigh(c) && sp < sl && + Surrogate.isLow(src[sp])) { + if (len > dst.length) { + sl++; + len--; + } + sp++; + } + dst[dp++] = repl; + } + return dp; + } } // init the c2b and c2bIndex tables from b2c. diff --git a/jdk/src/share/classes/sun/nio/cs/US_ASCII.java b/jdk/src/share/classes/sun/nio/cs/US_ASCII.java index d22fa64e352..fa718450768 100644 --- a/jdk/src/share/classes/sun/nio/cs/US_ASCII.java +++ b/jdk/src/share/classes/sun/nio/cs/US_ASCII.java @@ -31,10 +31,7 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.MalformedInputException; -import java.nio.charset.UnmappableCharacterException; - +import java.util.Arrays; public class US_ASCII extends Charset @@ -61,7 +58,8 @@ public class US_ASCII return new Encoder(this); } - private static class Decoder extends CharsetDecoder { + private static class Decoder extends CharsetDecoder + implements ArrayDecoder { private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); @@ -131,9 +129,27 @@ public class US_ASCII return decodeBufferLoop(src, dst); } + private char repl = '\uFFFD'; + protected void implReplaceWith(String newReplacement) { + repl = newReplacement.charAt(0); + } + + public int decode(byte[] src, int sp, int len, char[] dst) { + int dp = 0; + len = Math.min(len, dst.length); + while (dp < len) { + byte b = src[sp++]; + if (b >= 0) + dst[dp++] = (char)b; + else + dst[dp++] = repl; + } + return dp; + } } - private static class Encoder extends CharsetEncoder { + private static class Encoder extends CharsetEncoder + implements ArrayEncoder { private Encoder(Charset cs) { super(cs, 1.0f, 1.0f); @@ -143,8 +159,11 @@ public class US_ASCII return c < 0x80; } - private final Surrogate.Parser sgp = new Surrogate.Parser(); + public boolean isLegalReplacement(byte[] repl) { + return (repl.length == 1 && repl[0] >= 0); + } + private final Surrogate.Parser sgp = new Surrogate.Parser(); private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { @@ -213,6 +232,32 @@ public class US_ASCII return encodeBufferLoop(src, dst); } + private byte repl = (byte)'?'; + protected void implReplaceWith(byte[] newReplacement) { + repl = newReplacement[0]; + } + + public int encode(char[] src, int sp, int len, byte[] dst) { + int dp = 0; + int sl = sp + Math.min(len, dst.length); + while (sp < sl) { + char c = src[sp++]; + if (c < 0x80) { + dst[dp++] = (byte)c; + continue; + } + if (Surrogate.isHigh(c) && sp < sl && + Surrogate.isLow(src[sp])) { + if (len > dst.length) { + sl++; + len--; + } + sp++; + } + dst[dp++] = repl; + } + return dp; + } } } diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java b/jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java new file mode 100644 index 00000000000..053e3dcfbb0 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java @@ -0,0 +1,110 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; + +/** + * Base implementation of AclFileAttributeView + */ + +abstract class AbstractAclFileAttributeView + implements AclFileAttributeView +{ + private static final String OWNER_NAME = "owner"; + private static final String ACL_NAME = "acl"; + + @Override + public final String name() { + return "acl"; + } + + @Override + public final Object getAttribute(String attribute) throws IOException { + if (attribute.equals(OWNER_NAME)) + return getOwner(); + if (attribute.equals(ACL_NAME)) + return getAcl(); + return null; + } + + @Override + @SuppressWarnings("unchecked") + public final void setAttribute(String attribute, Object value) + throws IOException + { + if (attribute.equals(OWNER_NAME)) { + setOwner((UserPrincipal)value); + return; + } + if (attribute.equals(ACL_NAME)) { + setAcl((List<AclEntry>)value); + return; + } + throw new UnsupportedOperationException(); + } + + @Override + public final Map<String,?> readAttributes(String first, String[] rest) + throws IOException + { + boolean acl = false; + boolean owner = false; + + if (first.equals(ACL_NAME)) acl = true; + else if (first.equals(OWNER_NAME)) owner = true; + else if (first.equals("*")) { + owner = true; + acl = true; + } + + if (!acl || !owner) { + for (String attribute: rest) { + if (attribute.equals("*")) { + owner = true; + acl = true; + break; + } + if (attribute.equals(ACL_NAME)) { + acl = true; + continue; + } + if (attribute.equals(OWNER_NAME)) { + owner = true; + continue; + } + } + } + Map<String,Object> result = new HashMap<String,Object>(2); + if (acl) + result.put(ACL_NAME, getAcl()); + if (owner) + result.put(OWNER_NAME, getOwner()); + return Collections.unmodifiableMap(result); + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java b/jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java new file mode 100644 index 00000000000..18cf00d501c --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java @@ -0,0 +1,208 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * Base implementation of BasicFileAttributeView + */ + +abstract class AbstractBasicFileAttributeView + implements BasicFileAttributeView +{ + private static final String SIZE_NAME = "size"; + private static final String CREATION_TIME_NAME = "creationTime"; + private static final String LAST_ACCESS_TIME_NAME = "lastAccessTime"; + private static final String LAST_MODIFIED_TIME_NAME = "lastModifiedTime"; + private static final String RESOLUTION_NAME = "resolution"; + private static final String FILE_KEY_NAME = "fileKey"; + private static final String LINK_COUNT_NAME = "linkCount"; + private static final String IS_DIRECTORY_NAME = "isDirectory"; + private static final String IS_REGULAR_FILE_NAME = "isRegularFile"; + private static final String IS_SYMBOLIC_LINK_NAME = "isSymbolicLink"; + private static final String IS_OTHER_NAME = "isOther"; + + protected AbstractBasicFileAttributeView() { } + + @Override + public String name() { + return "basic"; + } + + @Override + public Object getAttribute(String attribute) throws IOException { + BasicFileAttributes attrs = readAttributes(); + if (attribute.equals(SIZE_NAME)) + return attrs.size(); + if (attribute.equals(CREATION_TIME_NAME)) + return attrs.creationTime(); + if (attribute.equals(LAST_ACCESS_TIME_NAME)) + return attrs.lastAccessTime(); + if (attribute.equals(LAST_MODIFIED_TIME_NAME)) + return attrs.lastModifiedTime(); + if (attribute.equals(RESOLUTION_NAME)) + return attrs.resolution(); + if (attribute.equals(FILE_KEY_NAME)) + return attrs.fileKey(); + if (attribute.equals(LINK_COUNT_NAME)) + return attrs.linkCount(); + if (attribute.equals(IS_DIRECTORY_NAME)) + return attrs.isDirectory(); + if (attribute.equals(IS_REGULAR_FILE_NAME)) + return attrs.isRegularFile(); + if (attribute.equals(IS_SYMBOLIC_LINK_NAME)) + return attrs.isSymbolicLink(); + if (attribute.equals(IS_OTHER_NAME)) + return attrs.isOther(); + return null; + } + + private Long toTimeValue(Object value) { + if (value == null) + throw new NullPointerException(); + Long time = (Long)value; + if (time < 0L && time != -1L) + throw new IllegalArgumentException("time value cannot be negative"); + return time; + } + + @Override + public void setAttribute(String attribute, Object value) + throws IOException + { + if (attribute.equals(LAST_MODIFIED_TIME_NAME)) { + setTimes(toTimeValue(value), null, null, TimeUnit.MILLISECONDS); + return; + } + if (attribute.equals(LAST_ACCESS_TIME_NAME)) { + setTimes(null, toTimeValue(value), null, TimeUnit.MILLISECONDS); + return; + } + if (attribute.equals(CREATION_TIME_NAME)) { + setTimes(null, null, toTimeValue(value), TimeUnit.MILLISECONDS); + return; + } + throw new UnsupportedOperationException("'" + attribute + + "' is unknown or read-only attribute"); + } + + /** + * + */ + static class AttributesBuilder { + private Set<String> set = new HashSet<String>(); + private Map<String,Object> map = new HashMap<String,Object>(); + private boolean copyAll; + + private AttributesBuilder(String first, String[] rest) { + if (first.equals("*")) { + copyAll = true; + } else { + set.add(first); + // copy names into the given Set bailing out if "*" is found + for (String attribute: rest) { + if (attribute.equals("*")) { + copyAll = true; + break; + } + set.add(attribute); + } + } + } + + /** + * Creates builder to build up a map of the matching attributes + */ + static AttributesBuilder create(String first, String[] rest) { + return new AttributesBuilder(first, rest); + } + + /** + * Returns true if the attribute should be returned in the map + */ + boolean match(String attribute) { + if (copyAll) + return true; + return set.contains(attribute); + } + + void add(String attribute, Object value) { + map.put(attribute, value); + } + + /** + * Returns the map. Discard all references to the AttributesBuilder + * after invoking this method. + */ + Map<String,Object> unmodifiableMap() { + return Collections.unmodifiableMap(map); + } + } + + /** + * Invoked by readAttributes or sub-classes to add all matching basic + * attributes to the builder + */ + final void addBasicAttributesToBuilder(BasicFileAttributes attrs, + AttributesBuilder builder) + { + if (builder.match(SIZE_NAME)) + builder.add(SIZE_NAME, attrs.size()); + if (builder.match(CREATION_TIME_NAME)) + builder.add(CREATION_TIME_NAME, attrs.creationTime()); + if (builder.match(LAST_ACCESS_TIME_NAME)) + builder.add(LAST_ACCESS_TIME_NAME, attrs.lastAccessTime()); + if (builder.match(LAST_MODIFIED_TIME_NAME)) + builder.add(LAST_MODIFIED_TIME_NAME, attrs.lastModifiedTime()); + if (builder.match(RESOLUTION_NAME)) + builder.add(RESOLUTION_NAME, attrs.resolution()); + if (builder.match(FILE_KEY_NAME)) + builder.add(FILE_KEY_NAME, attrs.fileKey()); + if (builder.match(LINK_COUNT_NAME)) + builder.add(LINK_COUNT_NAME, attrs.linkCount()); + if (builder.match(IS_DIRECTORY_NAME)) + builder.add(IS_DIRECTORY_NAME, attrs.isDirectory()); + if (builder.match(IS_REGULAR_FILE_NAME)) + builder.add(IS_REGULAR_FILE_NAME, attrs.isRegularFile()); + if (builder.match(IS_SYMBOLIC_LINK_NAME)) + builder.add(IS_SYMBOLIC_LINK_NAME, attrs.isSymbolicLink()); + if (builder.match(IS_OTHER_NAME)) + builder.add(IS_OTHER_NAME, attrs.isOther()); + } + + @Override + public Map<String,?> readAttributes(String first, String[] rest) + throws IOException + { + AttributesBuilder builder = AttributesBuilder.create(first, rest); + addBasicAttributesToBuilder(readAttributes(), builder); + return builder.unmodifiableMap(); + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractFileStoreSpaceAttributeView.java b/jdk/src/share/classes/sun/nio/fs/AbstractFileStoreSpaceAttributeView.java new file mode 100644 index 00000000000..73c8c2a0db1 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/AbstractFileStoreSpaceAttributeView.java @@ -0,0 +1,119 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; + +/** + * Base implementation of FileStoreSpaceAttributeView + */ + +abstract class AbstractFileStoreSpaceAttributeView + implements FileStoreSpaceAttributeView +{ + private static final String TOTAL_SPACE_NAME = "totalSpace"; + private static final String USABLE_SPACE_NAME = "usableSpace"; + private static final String UNALLOCATED_SPACE_NAME = "unallocatedSpace"; + + @Override + public final String name() { + return "space"; + } + + @Override + public final Object getAttribute(String attribute) throws IOException { + FileStoreSpaceAttributes attrs = readAttributes(); + if (attribute.equals(TOTAL_SPACE_NAME)) + return attrs.totalSpace(); + if (attribute.equals(USABLE_SPACE_NAME)) + return attrs.usableSpace(); + if (attribute.equals(UNALLOCATED_SPACE_NAME)) + return attrs.unallocatedSpace(); + return null; + } + + @Override + public final void setAttribute(String attribute, Object value) + throws IOException + { + if (attribute == null || value == null) + throw new NullPointerException(); + throw new UnsupportedOperationException(); + } + + @Override + public final Map<String,?> readAttributes(String first, String[] rest) + throws IOException + { + boolean total = false; + boolean usable = false; + boolean unallocated = false; + + if (first.equals(TOTAL_SPACE_NAME)) total = true; + else if (first.equals(USABLE_SPACE_NAME)) usable = true; + else if (first.equals(UNALLOCATED_SPACE_NAME)) unallocated = true; + else if (first.equals("*")) { + total = true; + usable = true; + unallocated = true; + } + + if (!total || !usable || !unallocated) { + for (String attribute: rest) { + if (attribute.equals("*")) { + total = true; + usable = true; + unallocated = true; + break; + } + if (attribute.equals(TOTAL_SPACE_NAME)) { + total = true; + continue; + } + if (attribute.equals(USABLE_SPACE_NAME)) { + usable = true; + continue; + } + if (attribute.equals(UNALLOCATED_SPACE_NAME)) { + unallocated = true; + continue; + } + } + } + + FileStoreSpaceAttributes attrs = readAttributes(); + Map<String,Object> result = new HashMap<String,Object>(2); + if (total) + result.put(TOTAL_SPACE_NAME, attrs.totalSpace()); + if (usable) + result.put(USABLE_SPACE_NAME, attrs.usableSpace()); + if (unallocated) + result.put(UNALLOCATED_SPACE_NAME, attrs.unallocatedSpace()); + return Collections.unmodifiableMap(result); + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java b/jdk/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java new file mode 100644 index 00000000000..d8a391b8081 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java @@ -0,0 +1,69 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.FileRef; +import java.nio.file.spi.FileTypeDetector; +import java.io.IOException; +import sun.nio.fs.MimeType; + +/** + * Base implementation of FileTypeDetector + */ + +public abstract class AbstractFileTypeDetector + extends FileTypeDetector +{ + protected AbstractFileTypeDetector() { + super(); + } + + /** + * Invokes the implProbeContentType method to guess the file's content type, + * and this validates that the content type's syntax is valid. + */ + @Override + public final String probeContentType(FileRef file) throws IOException { + if (file == null) + throw new NullPointerException("'file' is null"); + String result = implProbeContentType(file); + if (result != null) { + // check the content type + try { + MimeType.parse(result); + } catch (IllegalArgumentException ignore) { + result = null; + } + } + return result; + } + + /** + * Probes the given file to guess its content type. + */ + protected abstract String implProbeContentType(FileRef file) + throws IOException; +} diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractPoller.java b/jdk/src/share/classes/sun/nio/fs/AbstractPoller.java new file mode 100644 index 00000000000..3ab8af8e13b --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/AbstractPoller.java @@ -0,0 +1,290 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.io.IOException; +import java.util.*; + +/** + * Base implementation of background poller thread used in watch service + * implementations. A poller thread waits on events from the file system and + * also services "requests" from clients to register for new events or cancel + * existing registrations. + */ + +abstract class AbstractPoller implements Runnable { + + // list of requests pending to the poller thread + private final LinkedList<Request> requestList; + + // set to true when shutdown + private boolean shutdown; + + protected AbstractPoller() { + this.requestList = new LinkedList<Request>(); + this.shutdown = false; + } + + /** + * Starts the poller thread + */ + public void start() { + final Runnable thisRunnable = this; + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + Thread thr = new Thread(thisRunnable); + thr.setDaemon(true); + thr.start(); + return null; + } + }); + } + + /** + * Wakeup poller thread so that it can service pending requests + */ + abstract void wakeup() throws IOException; + + /** + * Executed by poller thread to register directory for changes + */ + abstract Object implRegister(Path path, + Set<? extends WatchEvent.Kind<?>> events, + WatchEvent.Modifier... modifiers); + + /** + * Executed by poller thread to cancel key + */ + abstract void implCancelKey(WatchKey key); + + /** + * Executed by poller thread to shutdown and cancel all keys + */ + abstract void implCloseAll(); + + /** + * Requests, and waits on, poller thread to register given file. + */ + final WatchKey register(FileRef dir, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) + throws IOException + { + // validate arguments before request to poller + if (dir == null) + throw new NullPointerException(); + if (events.length == 0) + throw new IllegalArgumentException("No events to register"); + Set<WatchEvent.Kind<?>> eventSet = new HashSet<WatchEvent.Kind<?>>(events.length); + for (WatchEvent.Kind<?> event: events) { + // standard events + if (event == StandardWatchEventKind.ENTRY_CREATE || + event == StandardWatchEventKind.ENTRY_MODIFY || + event == StandardWatchEventKind.ENTRY_DELETE) + { + eventSet.add(event); + continue; + } + + // OVERFLOW is ignored + if (event == StandardWatchEventKind.OVERFLOW) { + if (events.length == 1) + throw new IllegalArgumentException("No events to register"); + continue; + } + + // null/unsupported + if (event == null) + throw new NullPointerException("An element in event set is 'null'"); + throw new UnsupportedOperationException(event.name()); + } + return (WatchKey)invoke(RequestType.REGISTER, dir, eventSet, modifiers); + } + + /** + * Cancels, and waits on, poller thread to cancel given key. + */ + final void cancel(WatchKey key) { + try { + invoke(RequestType.CANCEL, key); + } catch (IOException x) { + // should not happen + throw new AssertionError(x.getMessage()); + } + } + + /** + * Shutdown poller thread + */ + final void close() throws IOException { + invoke(RequestType.CLOSE); + } + + /** + * Types of request that the poller thread must handle + */ + private static enum RequestType { + REGISTER, + CANCEL, + CLOSE; + } + + /** + * Encapsulates a request (command) to the poller thread. + */ + private static class Request { + private final RequestType type; + private final Object[] params; + + private boolean completed = false; + private Object result = null; + + Request(RequestType type, Object... params) { + this.type = type; + this.params = params; + } + + RequestType type() { + return type; + } + + Object[] parameters() { + return params; + } + + void release(Object result) { + synchronized (this) { + this.completed = true; + this.result = result; + notifyAll(); + } + } + + /** + * Await completion of the request. The return value is the result of + * the request. + */ + Object awaitResult() { + synchronized (this) { + while (!completed) { + try { + wait(); + } catch (InterruptedException x) { + // ignore + } + } + return result; + } + } + } + + /** + * Enqueues request to poller thread and waits for result + */ + private Object invoke(RequestType type, Object... params) throws IOException { + // submit request + Request req = new Request(type, params); + synchronized (requestList) { + if (shutdown) { + throw new ClosedWatchServiceException(); + } + requestList.add(req); + } + + // wakeup thread + wakeup(); + + // wait for result + Object result = req.awaitResult(); + + if (result instanceof RuntimeException) + throw (RuntimeException)result; + if (result instanceof IOException ) + throw (IOException)result; + return result; + } + + /** + * Invoked by poller thread to process all pending requests + * + * @return true if poller thread should shutdown + */ + @SuppressWarnings("unchecked") + boolean processRequests() { + synchronized (requestList) { + Request req; + while ((req = requestList.poll()) != null) { + // if in process of shutdown then reject request + if (shutdown) { + req.release(new ClosedWatchServiceException()); + } + + switch (req.type()) { + /** + * Register directory + */ + case REGISTER: { + Object[] params = req.parameters(); + Path path = (Path)params[0]; + Set<? extends WatchEvent.Kind<?>> events = + (Set<? extends WatchEvent.Kind<?>>)params[1]; + WatchEvent.Modifier[] modifiers = + (WatchEvent.Modifier[])params[2]; + req.release(implRegister(path, events, modifiers)); + break; + } + /** + * Cancel existing key + */ + case CANCEL : { + Object[] params = req.parameters(); + WatchKey key = (WatchKey)params[0]; + implCancelKey(key); + req.release(null); + break; + } + /** + * Close watch service + */ + case CLOSE: { + implCloseAll(); + req.release(null); + shutdown = true; + break; + } + + default: + req.release(new IOException("request not recognized")); + } + } + } + return shutdown; + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java b/jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java new file mode 100644 index 00000000000..3ac9b507fc0 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java @@ -0,0 +1,124 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.ByteBuffer; +import java.nio.file.attribute.UserDefinedFileAttributeView; +import java.io.IOException; +import java.util.*; + +/** + * Base implementation of NamedAttributeView + */ + +abstract class AbstractUserDefinedFileAttributeView + implements UserDefinedFileAttributeView +{ + protected AbstractUserDefinedFileAttributeView() { } + + protected void checkAccess(String file, + boolean checkRead, + boolean checkWrite) + { + assert checkRead || checkWrite; + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (checkRead) + sm.checkRead(file); + if (checkWrite) + sm.checkWrite(file); + sm.checkPermission(new RuntimePermission("accessUserDefinedAttributes")); + } + } + + @Override + public final String name() { + return "xattr"; + } + + @Override + public final Object getAttribute(String attribute) throws IOException { + int size; + try { + size = size(attribute); + } catch (IOException e) { + // not found or some other I/O error + if (list().contains(attribute)) + throw e; + return null; + } + byte[] buf = new byte[size]; + int n = read(attribute, ByteBuffer.wrap(buf)); + return (n == size) ? buf : Arrays.copyOf(buf, n); + } + + @Override + public final void setAttribute(String attribute, Object value) + throws IOException + { + ByteBuffer bb; + if (value instanceof byte[]) { + bb = ByteBuffer.wrap((byte[])value); + } else { + bb = (ByteBuffer)value; + } + write(attribute, bb); + } + + @Override + public final Map<String,?> readAttributes(String first, String... rest) + throws IOException + { + // names of attributes to return + List<String> names = new ArrayList<String>(); + + boolean readAll = false; + if (first.equals("*")) { + readAll = true; + } else { + names.add(first); + } + for (String name: rest) { + if (name.equals("*")) { + readAll = true; + } else { + names.add(name); + } + } + if (readAll) + names = list(); + + // read each value and return in map + Map<String,Object> result = new HashMap<String,Object>(); + for (String name: names) { + Object value = getAttribute(name); + if (value != null) + result.put(name, value); + } + + return result; + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java b/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java new file mode 100644 index 00000000000..8e33f81ed84 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java @@ -0,0 +1,180 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.util.*; + +/** + * Base implementation class for watch keys. + */ + +abstract class AbstractWatchKey extends WatchKey { + + /** + * Maximum size of event list (in the future this may be tunable) + */ + static final int MAX_EVENT_LIST_SIZE = 512; + + /** + * Special event to signal overflow + */ + static final Event<Void> OVERFLOW_EVENT = + new Event<Void>(StandardWatchEventKind.OVERFLOW, null); + + /** + * Possible key states + */ + private static enum State { READY, SIGNALLED }; + + // reference to watcher + private final AbstractWatchService watcher; + + // key state + private State state; + + // pending events + private List<WatchEvent<?>> events; + + protected AbstractWatchKey(AbstractWatchService watcher) { + this.watcher = watcher; + this.state = State.READY; + this.events = new ArrayList<WatchEvent<?>>(); + } + + final AbstractWatchService watcher() { + return watcher; + } + + /** + * Enqueues this key to the watch service + */ + final void signal() { + synchronized (this) { + if (state == State.READY) { + state = State.SIGNALLED; + watcher.enqueueKey(this); + } + } + } + + /** + * Adds the event to this key and signals it. + */ + @SuppressWarnings("unchecked") + final void signalEvent(WatchEvent.Kind<?> kind, Object context) { + synchronized (this) { + int size = events.size(); + if (size > 1) { + // don't let list get too big + if (size >= MAX_EVENT_LIST_SIZE) { + kind = StandardWatchEventKind.OVERFLOW; + context = null; + } + + // repeated event + WatchEvent<?> prev = events.get(size-1); + if (kind == prev.kind()) { + boolean isRepeat; + if (context == null) { + isRepeat = (prev.context() == null); + } else { + isRepeat = context.equals(prev.context()); + } + if (isRepeat) { + ((Event<?>)prev).increment(); + return; + } + } + } + + // non-repeated event + events.add(new Event<Object>((WatchEvent.Kind<Object>)kind, context)); + signal(); + } + } + + @Override + public final List<WatchEvent<?>> pollEvents() { + synchronized (this) { + List<WatchEvent<?>> result = events; + events = new ArrayList<WatchEvent<?>>(); + return result; + } + } + + @Override + public final boolean reset() { + synchronized (this) { + if (state == State.SIGNALLED && isValid()) { + if (events.isEmpty()) { + state = State.READY; + } else { + // pending events so re-queue key + watcher.enqueueKey(this); + } + } + return isValid(); + } + } + + /** + * WatchEvent implementation + */ + private static class Event<T> extends WatchEvent<T> { + private final WatchEvent.Kind<T> kind; + private final T context; + + // synchronize on watch key to access/increment count + private int count; + + Event(WatchEvent.Kind<T> type, T context) { + this.kind = type; + this.context = context; + this.count = 1; + } + + @Override + public WatchEvent.Kind<T> kind() { + return kind; + } + + @Override + public T context() { + return context; + } + + @Override + public int count() { + return count; + } + + // for repeated events + void increment() { + count++; + } + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractWatchService.java b/jdk/src/share/classes/sun/nio/fs/AbstractWatchService.java new file mode 100644 index 00000000000..c29d78b59d2 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/AbstractWatchService.java @@ -0,0 +1,161 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.util.concurrent.*; +import java.io.IOException; + +/** + * Base implementation class for watch services. + */ + +abstract class AbstractWatchService extends WatchService { + + // signaled keys waiting to be dequeued + private final LinkedBlockingDeque<WatchKey> pendingKeys = + new LinkedBlockingDeque<WatchKey>(); + + // special key to indicate that watch service is closed + private final WatchKey CLOSE_KEY = + new AbstractWatchKey(null) { + @Override + public boolean isValid() { + return true; + } + + @Override + public void cancel() { + } + }; + + // used when closing watch service + private volatile boolean closed; + private Object closeLock = new Object(); + + protected AbstractWatchService() { + } + + /** + * Register the given object with this watch service + */ + abstract WatchKey register(Path path, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifers) + throws IOException; + + // used by AbstractWatchKey to enqueue key + final void enqueueKey(WatchKey key) { + pendingKeys.offer(key); + } + + /** + * Throws ClosedWatchServiceException if watch service is closed + */ + private void checkOpen() { + if (closed) + throw new ClosedWatchServiceException(); + } + + /** + * Checks the key isn't the special CLOSE_KEY used to unblock threads when + * the watch service is closed. + */ + private void checkKey(WatchKey key) { + if (key == CLOSE_KEY) { + // re-queue in case there are other threads blocked in take/poll + enqueueKey(key); + } + checkOpen(); + } + + @Override + public final WatchKey poll() { + checkOpen(); + WatchKey key = pendingKeys.poll(); + checkKey(key); + return key; + } + + @Override + public final WatchKey poll(long timeout, TimeUnit unit) + throws InterruptedException + { + checkOpen(); + WatchKey key = pendingKeys.poll(timeout, unit); + checkKey(key); + return key; + } + + @Override + public final WatchKey take() + throws InterruptedException + { + checkOpen(); + WatchKey key = pendingKeys.take(); + checkKey(key); + return key; + } + + /** + * Tells whether or not this watch service is open. + */ + final boolean isOpen() { + return !closed; + } + + /** + * Retrieves the object upon which the close method synchronizes. + */ + final Object closeLock() { + return closeLock; + } + + /** + * Closes this watch service. This method is invoked by the close + * method to perform the actual work of closing the watch service. + */ + abstract void implClose() throws IOException; + + @Override + public final void close() + throws IOException + { + synchronized (closeLock) { + // nothing to do if already closed + if (closed) + return; + closed = true; + + implClose(); + + // clear pending keys and queue special key to ensure that any + // threads blocked in take/poll wakeup + pendingKeys.clear(); + pendingKeys.offer(CLOSE_KEY); + } + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/BasicFileAttributesHolder.java b/jdk/src/share/classes/sun/nio/fs/BasicFileAttributesHolder.java new file mode 100644 index 00000000000..28f8691ec73 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/BasicFileAttributesHolder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.BasicFileAttributes; + +/** + * Implemented by objects that may hold or cache the attributes of a file. + */ + +public interface BasicFileAttributesHolder { + /** + * Returns cached attributes (may be null). If file is a symbolic link then + * the attributes are the link attributes and not the final target of the + * file. + */ + BasicFileAttributes get(); + + /** + * Invalidates cached attributes + */ + void invalidate(); +} diff --git a/jdk/src/share/classes/sun/nio/fs/Cancellable.java b/jdk/src/share/classes/sun/nio/fs/Cancellable.java new file mode 100644 index 00000000000..3b40ddd1017 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/Cancellable.java @@ -0,0 +1,137 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import sun.misc.Unsafe; +import java.util.concurrent.ExecutionException; + +/** + * Base implementation of a task (typically native) that polls a memory location + * during execution so that it may be aborted/cancelled before completion. The + * task is executed by invoking the {@link runInterruptibly} method defined + * here and cancelled by invoking Thread.interrupt. + */ + +abstract class Cancellable implements Runnable { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + private final long pollingAddress; + private final Object lock = new Object(); + + // the following require lock when examining or changing + private boolean completed; + private Throwable exception; + + protected Cancellable() { + pollingAddress = unsafe.allocateMemory(4); + unsafe.putIntVolatile(null, pollingAddress, 0); + } + + /** + * Returns the memory address of a 4-byte int that should be polled to + * detect cancellation. + */ + protected long addressToPollForCancel() { + return pollingAddress; + } + + /** + * The value to write to the polled memory location to indicate that the + * task has been cancelled. If this method is not overridden then it + * defaults to MAX_VALUE. + */ + protected int cancelValue() { + return Integer.MAX_VALUE; + } + + /** + * "cancels" the task by writing bits into memory location that it polled + * by the task. + */ + final void cancel() { + synchronized (lock) { + if (!completed) { + unsafe.putIntVolatile(null, pollingAddress, cancelValue()); + } + } + } + + /** + * Returns the exception thrown by the task or null if the task completed + * successfully. + */ + private Throwable exception() { + synchronized (lock) { + return exception; + } + } + + @Override + public final void run() { + try { + implRun(); + } catch (Throwable t) { + synchronized (lock) { + exception = t; + } + } finally { + synchronized (lock) { + completed = true; + unsafe.freeMemory(pollingAddress); + } + } + } + + /** + * The task body. This should periodically poll the memory location + * to check for cancellation. + */ + abstract void implRun() throws Throwable; + + /** + * Invokes the given task in its own thread. If this (meaning the current) + * thread is interrupted then an attempt is make to cancel the background + * thread by writing into the memory location that it polls cooperatively. + */ + static void runInterruptibly(Cancellable task) throws ExecutionException { + Thread t = new Thread(task); + t.start(); + boolean cancelledByInterrupt = false; + while (t.isAlive()) { + try { + t.join(); + } catch (InterruptedException e) { + cancelledByInterrupt = true; + task.cancel(); + } + } + if (cancelledByInterrupt) + Thread.currentThread().interrupt(); + Throwable exc = task.exception(); + if (exc != null) + throw new ExecutionException(exc); + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java b/jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java new file mode 100644 index 00000000000..f40c2a79740 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java @@ -0,0 +1,111 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.util.*; +import java.io.IOException; + +/** + * An implementation of FileOwnerAttributeView that delegates to a given + * PosixFileAttributeView or AclFileAttributeView object. + */ + +final class FileOwnerAttributeViewImpl implements FileOwnerAttributeView { + private static final String OWNER_NAME = "owner"; + + private final FileAttributeView view; + private final boolean isPosixView; + + FileOwnerAttributeViewImpl(PosixFileAttributeView view) { + this.view = view; + this.isPosixView = true; + } + + FileOwnerAttributeViewImpl(AclFileAttributeView view) { + this.view = view; + this.isPosixView = false; + } + + @Override + public String name() { + return "owner"; + } + + @Override + public Object getAttribute(String attribute) throws IOException { + if (attribute.equals(OWNER_NAME)) + return getOwner(); + return null; + } + + @Override + public void setAttribute(String attribute, Object value) + throws IOException + { + if (attribute.equals(OWNER_NAME)) { + setOwner((UserPrincipal)value); + return; + } + throw new UnsupportedOperationException(); + } + + @Override + public Map<String,?> readAttributes(String first, String[] rest) throws IOException { + Map<String,Object> result = new HashMap<String,Object>(); + if (first.equals("*") || first.equals(OWNER_NAME)) { + result.put(OWNER_NAME, getOwner()); + } else { + for (String attribute: rest) { + if (attribute.equals("*") || attribute.equals(OWNER_NAME)) { + result.put(OWNER_NAME, getOwner()); + break; + } + } + } + return result; + } + + @Override + public UserPrincipal getOwner() throws IOException { + if (isPosixView) { + return ((PosixFileAttributeView)view).readAttributes().owner(); + } else { + return ((AclFileAttributeView)view).getOwner(); + } + } + + @Override + public void setOwner(UserPrincipal owner) + throws IOException + { + if (isPosixView) { + ((PosixFileAttributeView)view).setOwner(owner); + } else { + ((AclFileAttributeView)view).setOwner(owner); + } + } + } diff --git a/jdk/src/share/classes/sun/nio/fs/Globs.java b/jdk/src/share/classes/sun/nio/fs/Globs.java new file mode 100644 index 00000000000..33857ea0cdf --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/Globs.java @@ -0,0 +1,217 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.util.regex.PatternSyntaxException; + +public class Globs { + private Globs() { } + + private static final String regexMetaChars = ".^$+{[]|()"; + private static final String globMetaChars = "\\*?[{"; + + private static boolean isRegexMeta(char c) { + return regexMetaChars.indexOf(c) != -1; + } + + private static boolean isGlobMeta(char c) { + return globMetaChars.indexOf(c) != -1; + } + private static char EOL = 0; //TBD + + private static char next(String glob, int i) { + if (i < glob.length()) { + return glob.charAt(i); + } + return EOL; + } + + /** + * Creates a regex pattern from the given glob expression. + * + * @throws PatternSyntaxException + */ + private static String toRegexPattern(String globPattern, boolean isDos) { + boolean inGroup = false; + StringBuilder regex = new StringBuilder("^"); + + int i = 0; + while (i < globPattern.length()) { + char c = globPattern.charAt(i++); + switch (c) { + case '\\': + // escape special characters + if (i == globPattern.length()) { + throw new PatternSyntaxException("No character to escape", + globPattern, i - 1); + } + char next = globPattern.charAt(i++); + if (isGlobMeta(next) || isRegexMeta(next)) { + regex.append('\\'); + } + regex.append(next); + break; + case '/': + if (isDos) { + regex.append("\\\\"); + } else { + regex.append(c); + } + break; + case '[': + // don't match name separator in class + if (isDos) { + regex.append("[[^\\\\]&&["); + } else { + regex.append("[[^/]&&["); + } + if (next(globPattern, i) == '^') { + // escape the regex negation char if it appears + regex.append("\\^"); + i++; + } else { + // negation + if (next(globPattern, i) == '!') { + regex.append('^'); + i++; + } + // hyphen allowed at start + if (next(globPattern, i) == '-') { + regex.append('-'); + i++; + } + } + boolean hasRangeStart = false; + char last = 0; + while (i < globPattern.length()) { + c = globPattern.charAt(i++); + if (c == ']') { + break; + } + if (c == '/' || (isDos && c == '\\')) { + throw new PatternSyntaxException("Explicit 'name separator' in class", + globPattern, i - 1); + } + // TBD: how to specify ']' in a class? + if (c == '\\' || c == '[' || + c == '&' && next(globPattern, i) == '&') { + // escape '\', '[' or "&&" for regex class + regex.append('\\'); + } + regex.append(c); + + if (c == '-') { + if (!hasRangeStart) { + throw new PatternSyntaxException("Invalid range", + globPattern, i - 1); + } + if ((c = next(globPattern, i++)) == EOL || c == ']') { + break; + } + if (c < last) { + throw new PatternSyntaxException("Invalid range", + globPattern, i - 3); + } + regex.append(c); + hasRangeStart = false; + } else { + hasRangeStart = true; + last = c; + } + } + if (c != ']') { + throw new PatternSyntaxException("Missing ']", globPattern, i - 1); + } + regex.append("]]"); + break; + case '{': + if (inGroup) { + throw new PatternSyntaxException("Cannot nest groups", + globPattern, i - 1); + } + regex.append("(?:(?:"); + inGroup = true; + break; + case '}': + if (inGroup) { + regex.append("))"); + inGroup = false; + } else { + regex.append('}'); + } + break; + case ',': + if (inGroup) { + regex.append(")|(?:"); + } else { + regex.append(','); + } + break; + case '*': + if (next(globPattern, i) == '*') { + // crosses directory boundaries + regex.append(".*"); + i++; + } else { + // within directory boundary + if (isDos) { + regex.append("[^\\\\]*"); + } else { + regex.append("[^/]*"); + } + } + break; + case '?': + if (isDos) { + regex.append("[^\\\\]"); + } else { + regex.append("[^/]"); + } + break; + + default: + if (isRegexMeta(c)) { + regex.append('\\'); + } + regex.append(c); + } + } + + if (inGroup) { + throw new PatternSyntaxException("Missing '}", globPattern, i - 1); + } + + return regex.append('$').toString(); + } + + static String toUnixRegexPattern(String globPattern) { + return toRegexPattern(globPattern, false); + } + + static String toWindowsRegexPattern(String globPattern) { + return toRegexPattern(globPattern, true); + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/MimeType.java b/jdk/src/share/classes/sun/nio/fs/MimeType.java new file mode 100644 index 00000000000..053ea44c205 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/MimeType.java @@ -0,0 +1,73 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +/** + * Represents a MIME type for the purposes of validation and matching. For + * now this class is implemented using the javax.activation.MimeType class but + * this dependency can easily be eliminated when required. + */ + +public class MimeType { + private final javax.activation.MimeType type; + + private MimeType(javax.activation.MimeType type) { + this.type = type; + } + + /** + * Parses the given string as a MIME type. + * + * @throws IllegalArgumentException + * If the string is not a valid MIME type + */ + public static MimeType parse(String type) { + try { + return new MimeType(new javax.activation.MimeType(type)); + } catch (javax.activation.MimeTypeParseException x) { + throw new IllegalArgumentException(x); + } + } + + /** + * Returns {@code true} if this MIME type has parameters. + */ + public boolean hasParameters() { + return !type.getParameters().isEmpty(); + } + + /** + * Matches this MIME type against a given MIME type. This method returns + * true if the given string is a MIME type and it matches this type. + */ + public boolean match(String other) { + try { + return type.match(other); + } catch (javax.activation.MimeTypeParseException x) { + return false; + } + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/NativeBuffer.java b/jdk/src/share/classes/sun/nio/fs/NativeBuffer.java new file mode 100644 index 00000000000..975c1c20b2c --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/NativeBuffer.java @@ -0,0 +1,87 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import sun.misc.Unsafe; +import sun.misc.Cleaner; + +/** + * A light-weight buffer in native memory. + */ + +class NativeBuffer { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + private final long address; + private final int size; + private final Cleaner cleaner; + + // optional "owner" to avoid copying + // (only safe for use by thread-local caches) + private Object owner; + + private static class Deallocator implements Runnable { + private final long address; + Deallocator(long address) { + this.address = address; + } + public void run() { + unsafe.freeMemory(address); + } + } + + NativeBuffer(int size) { + this.address = unsafe.allocateMemory(size); + this.size = size; + this.cleaner = Cleaner.create(this, new Deallocator(address)); + } + + void release() { + NativeBuffers.releaseNativeBuffer(this); + } + + long address() { + return address; + } + + int size() { + return size; + } + + Cleaner cleaner() { + return cleaner; + } + + // not synchronized; only safe for use by thread-local caches + void setOwner(Object owner) { + this.owner = owner; + } + + // not synchronized; only safe for use by thread-local caches + Object owner() { + return owner; + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/NativeBuffers.java b/jdk/src/share/classes/sun/nio/fs/NativeBuffers.java new file mode 100644 index 00000000000..fa247a6acc0 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/NativeBuffers.java @@ -0,0 +1,140 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import sun.misc.Unsafe; + +/** + * Factory for native buffers. + */ + +class NativeBuffers { + private NativeBuffers() { } + + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + private static final int TEMP_BUF_POOL_SIZE = 3; + private static ThreadLocal<NativeBuffer[]> threadLocal = + new ThreadLocal<NativeBuffer[]>(); + + /** + * Allocates a native buffer, of at least the given size, from the heap. + */ + static NativeBuffer allocNativeBuffer(int size) { + // Make a new one of at least 2k + if (size < 2048) size = 2048; + return new NativeBuffer(size); + } + + /** + * Returns a native buffer, of at least the given size, from the thread + * local cache. + */ + static NativeBuffer getNativeBufferFromCache(int size) { + // return from cache if possible + NativeBuffer[] buffers = threadLocal.get(); + if (buffers != null) { + for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) { + NativeBuffer buffer = buffers[i]; + if (buffer != null && buffer.size() >= size) { + buffers[i] = null; + return buffer; + } + } + } + return null; + } + + /** + * Returns a native buffer, of at least the given size. The native buffer + * is taken from the thread local cache if possible; otherwise it is + * allocated from the heap. + */ + static NativeBuffer getNativeBuffer(int size) { + NativeBuffer buffer = getNativeBufferFromCache(size); + if (buffer != null) { + buffer.setOwner(null); + return buffer; + } else { + return allocNativeBuffer(size); + } + } + + /** + * Releases the given buffer. If there is space in the thread local cache + * then the buffer goes into the cache; otherwise the memory is deallocated. + */ + static void releaseNativeBuffer(NativeBuffer buffer) { + // create cache if it doesn't exist + NativeBuffer[] buffers = threadLocal.get(); + if (buffers == null) { + buffers = new NativeBuffer[TEMP_BUF_POOL_SIZE]; + buffers[0] = buffer; + threadLocal.set(buffers); + return; + } + // Put it in an empty slot if such exists + for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) { + if (buffers[i] == null) { + buffers[i] = buffer; + return; + } + } + // Otherwise replace a smaller one in the cache if such exists + for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) { + NativeBuffer existing = buffers[i]; + if (existing.size() < buffer.size()) { + existing.cleaner().clean(); + buffers[i] = buffer; + return; + } + } + + // free it + buffer.cleaner().clean(); + } + + /** + * Copies a byte array and zero terminator into a given native buffer. + */ + static void copyCStringToNativeBuffer(byte[] cstr, NativeBuffer buffer) { + long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET; + long len = cstr.length; + assert buffer.size() >= (len + 1); + unsafe.copyMemory(cstr, offset, null, buffer.address(), len); + unsafe.putByte(buffer.address() + len, (byte)0); + } + + /** + * Copies a byte array and zero terminator into a native buffer, returning + * the buffer. + */ + static NativeBuffer asNativeBuffer(byte[] cstr) { + NativeBuffer buffer = getNativeBuffer(cstr.length+1); + copyCStringToNativeBuffer(cstr, buffer); + return buffer; + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/PollingWatchService.java b/jdk/src/share/classes/sun/nio/fs/PollingWatchService.java new file mode 100644 index 00000000000..73a89c27136 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/PollingWatchService.java @@ -0,0 +1,429 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.security.PrivilegedActionException; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.*; +import com.sun.nio.file.SensitivityWatchEventModifier; + +/** + * Simple WatchService implementation that uses periodic tasks to poll + * registered directories for changes. This implementation is for use on + * operating systems that do not have native file change notification support. + */ + +class PollingWatchService + extends AbstractWatchService +{ + // map of registrations + private final Map<Object,PollingWatchKey> map = + new HashMap<Object,PollingWatchKey>(); + + // used to execute the periodic tasks that poll for changes + private final ScheduledExecutorService scheduledExecutor; + + PollingWatchService() { + // TBD: Make the number of threads configurable + scheduledExecutor = Executors + .newSingleThreadScheduledExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setDaemon(true); + return t; + }}); + } + + /** + * Register the given file with this watch service + */ + @Override + WatchKey register(final Path path, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) + throws IOException + { + // check events - CCE will be thrown if there are invalid elements + if (events.length == 0) + throw new IllegalArgumentException("No events to register"); + final Set<WatchEvent.Kind<?>> eventSet = + new HashSet<WatchEvent.Kind<?>>(events.length); + for (WatchEvent.Kind<?> event: events) { + // standard events + if (event == StandardWatchEventKind.ENTRY_CREATE || + event == StandardWatchEventKind.ENTRY_MODIFY || + event == StandardWatchEventKind.ENTRY_DELETE) + { + eventSet.add(event); + continue; + } + + // OVERFLOW is ignored + if (event == StandardWatchEventKind.OVERFLOW) { + if (events.length == 1) + throw new IllegalArgumentException("No events to register"); + continue; + } + + // null/unsupported + if (event == null) + throw new NullPointerException("An element in event set is 'null'"); + throw new UnsupportedOperationException(event.name()); + } + + // A modifier may be used to specify the sensitivity level + SensitivityWatchEventModifier sensivity = SensitivityWatchEventModifier.MEDIUM; + if (modifiers.length > 0) { + for (WatchEvent.Modifier modifier: modifiers) { + if (modifier == null) + throw new NullPointerException(); + if (modifier instanceof SensitivityWatchEventModifier) { + sensivity = (SensitivityWatchEventModifier)modifier; + continue; + } + throw new UnsupportedOperationException("Modifier not supported"); + } + } + + // check if watch service is closed + if (!isOpen()) + throw new ClosedWatchServiceException(); + + // registration is done in privileged block as it requires the + // attributes of the entries in the directory. + try { + final SensitivityWatchEventModifier s = sensivity; + return AccessController.doPrivileged( + new PrivilegedExceptionAction<PollingWatchKey>() { + @Override + public PollingWatchKey run() throws IOException { + return doPrivilegedRegister(path, eventSet, s); + } + }); + } catch (PrivilegedActionException pae) { + Throwable cause = pae.getCause(); + if (cause != null && cause instanceof IOException) + throw (IOException)cause; + throw new AssertionError(pae); + } + } + + // registers directory returning a new key if not already registered or + // existing key if already registered + private PollingWatchKey doPrivilegedRegister(Path path, + Set<? extends WatchEvent.Kind<?>> events, + SensitivityWatchEventModifier sensivity) + throws IOException + { + // check file is a directory and get its file key if possible + BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path); + if (!attrs.isDirectory()) { + throw new NotDirectoryException(path.toString()); + } + Object fileKey = attrs.fileKey(); + if (fileKey == null) + throw new AssertionError("File keys must be supported"); + + // grab close lock to ensure that watch service cannot be closed + synchronized (closeLock()) { + if (!isOpen()) + throw new ClosedWatchServiceException(); + + PollingWatchKey watchKey; + synchronized (map) { + watchKey = map.get(fileKey); + if (watchKey == null) { + // new registration + watchKey = new PollingWatchKey(this, path, fileKey); + map.put(fileKey, watchKey); + } else { + // update to existing registration + watchKey.disable(); + } + } + watchKey.enable(events, sensivity.sensitivityValueInSeconds()); + return watchKey; + } + + } + + @Override + void implClose() throws IOException { + synchronized (map) { + for (Map.Entry<Object,PollingWatchKey> entry: map.entrySet()) { + PollingWatchKey watchKey = entry.getValue(); + watchKey.disable(); + watchKey.invalidate(); + } + map.clear(); + } + AccessController.doPrivileged(new PrivilegedAction<Void>() { + @Override + public Void run() { + scheduledExecutor.shutdown(); + return null; + } + }); + } + + /** + * Entry in directory cache to record file last-modified-time and tick-count + */ + private static class CacheEntry { + private long lastModified; + private int lastTickCount; + + CacheEntry(long lastModified, int lastTickCount) { + this.lastModified = lastModified; + this.lastTickCount = lastTickCount; + } + + int lastTickCount() { + return lastTickCount; + } + + long lastModified() { + return lastModified; + } + + void update(long lastModified, int tickCount) { + this.lastModified = lastModified; + this.lastTickCount = tickCount; + } + } + + /** + * WatchKey implementation that encapsulates a map of the entries of the + * entries in the directory. Polling the key causes it to re-scan the + * directory and queue keys when entries are added, modified, or deleted. + */ + private class PollingWatchKey extends AbstractWatchKey { + private final Path dir; + private final Object fileKey; + + // current event set + private Set<? extends WatchEvent.Kind<?>> events; + + // the result of the periodic task that causes this key to be polled + private ScheduledFuture<?> poller; + + // indicates if the key is valid + private volatile boolean valid; + + // used to detect files that have been deleted + private int tickCount; + + // map of entries in directory + private Map<Path,CacheEntry> entries; + + PollingWatchKey(PollingWatchService watcher, + Path dir, + Object fileKey) + throws IOException + { + super(watcher); + this.dir = dir; + this.fileKey = fileKey; + this.valid = true; + this.tickCount = 0; + this.entries = new HashMap<Path,CacheEntry>(); + + // get the initial entries in the directory + DirectoryStream<Path> stream = dir.newDirectoryStream(); + try { + for (Path entry: stream) { + // don't follow links + long lastModified = Attributes + .readBasicFileAttributes(entry, LinkOption.NOFOLLOW_LINKS) + .lastModifiedTime(); + entries.put(entry.getName(), + new CacheEntry(lastModified, tickCount)); + } + } catch (ConcurrentModificationException cme) { + // thrown if directory iteration fails + Throwable cause = cme.getCause(); + if (cause != null && cause instanceof IOException) + throw (IOException)cause; + throw new AssertionError(cme); + } finally { + stream.close(); + } + } + + FileRef directory() { + return dir; + } + + Object fileKey() { + return fileKey; + } + + @Override + public boolean isValid() { + return valid; + } + + void invalidate() { + valid = false; + } + + // enables periodic polling + void enable(Set<? extends WatchEvent.Kind<?>> events, long period) { + synchronized (this) { + // update the events + this.events = events; + + // create the periodic task + Runnable thunk = new Runnable() { public void run() { poll(); }}; + this.poller = scheduledExecutor + .scheduleAtFixedRate(thunk, period, period, TimeUnit.SECONDS); + } + } + + // disables periodic polling + void disable() { + synchronized (this) { + if (poller != null) + poller.cancel(false); + } + } + + @Override + public void cancel() { + valid = false; + synchronized (map) { + map.remove(fileKey()); + } + disable(); + } + + /** + * Polls the directory to detect for new files, modified files, or + * deleted files. + */ + synchronized void poll() { + if (!valid) { + return; + } + + // update tick + tickCount++; + + // open directory + DirectoryStream<Path> stream = null; + try { + stream = dir.newDirectoryStream(); + } catch (IOException x) { + // directory is no longer accessible so cancel key + cancel(); + signal(); + return; + } + + // iterate over all entries in directory + try { + for (Path entry: stream) { + long lastModified = 0L; + try { + lastModified = Attributes + .readBasicFileAttributes(entry, LinkOption.NOFOLLOW_LINKS) + .lastModifiedTime(); + } catch (IOException x) { + // unable to get attributes of entry. If file has just + // been deleted then we'll report it as deleted on the + // next poll + continue; + } + + // lookup cache + CacheEntry e = entries.get(entry.getName()); + if (e == null) { + // new file found + entries.put(entry.getName(), + new CacheEntry(lastModified, tickCount)); + + // queue ENTRY_CREATE if event enabled + if (events.contains(StandardWatchEventKind.ENTRY_CREATE)) { + signalEvent(StandardWatchEventKind.ENTRY_CREATE, entry.getName()); + continue; + } else { + // if ENTRY_CREATE is not enabled and ENTRY_MODIFY is + // enabled then queue event to avoid missing out on + // modifications to the file immediately after it is + // created. + if (events.contains(StandardWatchEventKind.ENTRY_MODIFY)) { + signalEvent(StandardWatchEventKind.ENTRY_MODIFY, entry.getName()); + } + } + continue; + } + + // check if file has changed + if (e.lastModified != lastModified) { + if (events.contains(StandardWatchEventKind.ENTRY_MODIFY)) { + signalEvent(StandardWatchEventKind.ENTRY_MODIFY, entry.getName()); + } + } + // entry in cache so update poll time + e.update(lastModified, tickCount); + + } + } catch (ConcurrentModificationException x) { + // FIXME - should handle this + } finally { + + // close directory stream + try { + stream.close(); + } catch (IOException x) { + // ignore + } + } + + // iterate over cache to detect entries that have been deleted + Iterator<Map.Entry<Path,CacheEntry>> i = entries.entrySet().iterator(); + while (i.hasNext()) { + Map.Entry<Path,CacheEntry> mapEntry = i.next(); + CacheEntry entry = mapEntry.getValue(); + if (entry.lastTickCount() != tickCount) { + Path name = mapEntry.getKey(); + // remove from map and queue delete event (if enabled) + i.remove(); + if (events.contains(StandardWatchEventKind.ENTRY_DELETE)) { + signalEvent(StandardWatchEventKind.ENTRY_DELETE, name); + } + } + } + } + } +} diff --git a/jdk/src/share/classes/sun/nio/fs/Reflect.java b/jdk/src/share/classes/sun/nio/fs/Reflect.java new file mode 100644 index 00000000000..d425ef2498a --- /dev/null +++ b/jdk/src/share/classes/sun/nio/fs/Reflect.java @@ -0,0 +1,63 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.lang.reflect.*; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Utility class for reflection. + */ + +class Reflect { + private Reflect() {} + + private static void setAccessible(final AccessibleObject ao) { + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + ao.setAccessible(true); + return null; + }}); + } + + /** + * Lookup the field of a given class. + */ + static Field lookupField(String className, String fieldName) { + try { + Class<?> cl = Class.forName(className); + Field f = cl.getDeclaredField(fieldName); + setAccessible(f); + return f; + } catch (ClassNotFoundException x) { + throw new AssertionError(x); + } catch (NoSuchFieldException x) { + throw new AssertionError(x); + } + } +} diff --git a/jdk/src/share/classes/sun/print/ServiceDialog.java b/jdk/src/share/classes/sun/print/ServiceDialog.java index 8b5bd478900..062e6163a6f 100644 --- a/jdk/src/share/classes/sun/print/ServiceDialog.java +++ b/jdk/src/share/classes/sun/print/ServiceDialog.java @@ -2149,55 +2149,51 @@ public class ServiceDialog extends JDialog implements ActionListener { } } } + } - rbPortrait.setEnabled(pSupported); - rbLandscape.setEnabled(lSupported); - rbRevPortrait.setEnabled(rpSupported); - rbRevLandscape.setEnabled(rlSupported); - OrientationRequested or = (OrientationRequested)asCurrent.get(orCategory); - if (or == null || - !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { + rbPortrait.setEnabled(pSupported); + rbLandscape.setEnabled(lSupported); + rbRevPortrait.setEnabled(rpSupported); + rbRevLandscape.setEnabled(rlSupported); - or = (OrientationRequested)psCurrent.getDefaultAttributeValue(orCategory); - // need to validate if default is not supported - if (!psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { - or = null; - values = - psCurrent.getSupportedAttributeValues(orCategory, - docFlavor, - asCurrent); - if (values instanceof OrientationRequested[]) { - OrientationRequested[] orValues = - (OrientationRequested[])values; - if (orValues.length > 1) { - // get the first in the list - or = orValues[0]; - } + OrientationRequested or = (OrientationRequested)asCurrent.get(orCategory); + if (or == null || + !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { + + or = (OrientationRequested)psCurrent.getDefaultAttributeValue(orCategory); + // need to validate if default is not supported + if ((or != null) && + !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { + or = null; + Object values = + psCurrent.getSupportedAttributeValues(orCategory, + docFlavor, + asCurrent); + if (values instanceof OrientationRequested[]) { + OrientationRequested[] orValues = + (OrientationRequested[])values; + if (orValues.length > 1) { + // get the first in the list + or = orValues[0]; } } - - if (or == null) { - or = OrientationRequested.PORTRAIT; - } - asCurrent.add(or); } - if (or == OrientationRequested.PORTRAIT) { - rbPortrait.setSelected(true); - } else if (or == OrientationRequested.LANDSCAPE) { - rbLandscape.setSelected(true); - } else if (or == OrientationRequested.REVERSE_PORTRAIT) { - rbRevPortrait.setSelected(true); - } else { // if (or == OrientationRequested.REVERSE_LANDSCAPE) - rbRevLandscape.setSelected(true); + if (or == null) { + or = OrientationRequested.PORTRAIT; } - } else { - rbPortrait.setEnabled(pSupported); - rbLandscape.setEnabled(lSupported); - rbRevPortrait.setEnabled(rpSupported); - rbRevLandscape.setEnabled(rlSupported); + asCurrent.add(or); + } + if (or == OrientationRequested.PORTRAIT) { + rbPortrait.setSelected(true); + } else if (or == OrientationRequested.LANDSCAPE) { + rbLandscape.setSelected(true); + } else if (or == OrientationRequested.REVERSE_PORTRAIT) { + rbRevPortrait.setSelected(true); + } else { // if (or == OrientationRequested.REVERSE_LANDSCAPE) + rbRevLandscape.setSelected(true); } } } diff --git a/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.java b/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.java index eac123dc605..4bcb0d30542 100644 --- a/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.java @@ -788,4 +788,16 @@ public class AnnotationParser { for (int i = 0; i < length; i++) skipMemberValue(buf); } + + /* + * This method converts the annotation map returned by the parseAnnotations() + * method to an array. It is called by Field.getDeclaredAnnotations(), + * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations(). + * This avoids the reflection classes to load the Annotation class until + * it is needed. + */ + private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; + public static Annotation[] toArray(Map<Class, Annotation> annotations) { + return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY); + } } diff --git a/jdk/src/share/classes/sun/security/jca/ProviderConfig.java b/jdk/src/share/classes/sun/security/jca/ProviderConfig.java index 9b40307b166..576c6803204 100644 --- a/jdk/src/share/classes/sun/security/jca/ProviderConfig.java +++ b/jdk/src/share/classes/sun/security/jca/ProviderConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,37 +60,6 @@ final class ProviderConfig { // use by doLoadProvider() private final static Class[] CL_STRING = { String.class }; - // lock to use while loading a provider. it ensures that each provider - // is loaded only once and that we can detect recursion. - // NOTE that because of 4944382 we use the system classloader as lock. - // By using the same lock to load classes as to load providers we avoid - // deadlock due to lock ordering. However, this class may be initialized - // early in the startup when the system classloader has not yet been set - // up. Use a temporary lock object if that is the case. - // Any of this may break if the class loading implementation is changed. - private static volatile Object LOCK = new Object(); - - private static Object getLock() { - Object o = LOCK; - // check if lock is already set to the class loader - if (o instanceof ClassLoader) { - return o; - } - Object cl = AccessController.doPrivileged( - new PrivilegedAction<Object>() { - public Object run() { - return ClassLoader.getSystemClassLoader(); - } - }); - // check if class loader initialized now (non-null) - if (cl != null) { - LOCK = cl; - o = cl; - } - return o; - } - - // name of the provider class private final String className; @@ -194,7 +163,7 @@ final class ProviderConfig { /** * Get the provider object. Loads the provider if it is not already loaded. */ - Provider getProvider() { + synchronized Provider getProvider() { // volatile variable load Provider p = provider; if (p != null) { @@ -203,30 +172,23 @@ final class ProviderConfig { if (shouldLoad() == false) { return null; } - synchronized (getLock()) { - p = provider; - if (p != null) { - // loaded by another thread while we were blocked on lock - return p; + if (isLoading) { + // because this method is synchronized, this can only + // happen if there is recursion. + if (debug != null) { + debug.println("Recursion loading provider: " + this); + new Exception("Call trace").printStackTrace(); } - if (isLoading) { - // because this method is synchronized, this can only - // happen if there is recursion. - if (debug != null) { - debug.println("Recursion loading provider: " + this); - new Exception("Call trace").printStackTrace(); - } - return null; - } - try { - isLoading = true; - tries++; - p = doLoadProvider(); - } finally { - isLoading = false; - } - provider = p; + return null; } + try { + isLoading = true; + tries++; + p = doLoadProvider(); + } finally { + isLoading = false; + } + provider = p; return p; } diff --git a/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java b/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java index 6003cdfaeab..9bb77fd7a1d 100644 --- a/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java +++ b/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,11 +66,11 @@ public class NegTokenInit extends SpNegoToken { private byte[] mechTypes = null; private Oid[] mechTypeList = null; - private byte[] reqFlags = null; + private BitArray reqFlags = null; private byte[] mechToken = null; private byte[] mechListMIC = null; - NegTokenInit(byte[] mechTypes, byte[] flags, + NegTokenInit(byte[] mechTypes, BitArray flags, byte[] token, byte[] mechListMIC) { super(NEG_TOKEN_INIT_ID); @@ -101,7 +101,7 @@ public class NegTokenInit extends SpNegoToken { // write context flags with CONTEXT 01 if (reqFlags != null) { DerOutputStream flags = new DerOutputStream(); - flags.putBitString(reqFlags); + flags.putUnalignedBitString(reqFlags); initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x01), flags); } @@ -237,7 +237,7 @@ public class NegTokenInit extends SpNegoToken { return mechTypeList; } - byte[] getReqFlags() { + BitArray getReqFlags() { return reqFlags; } diff --git a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java index 7185b0e08a7..a84e8a26001 100644 --- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java +++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,13 +53,6 @@ public class SpNegoContext implements GSSContextSpi { private int state = STATE_NEW; - private static final int CHECKSUM_DELEG_FLAG = 1; - private static final int CHECKSUM_MUTUAL_FLAG = 2; - private static final int CHECKSUM_REPLAY_FLAG = 4; - private static final int CHECKSUM_SEQUENCE_FLAG = 8; - private static final int CHECKSUM_CONF_FLAG = 16; - private static final int CHECKSUM_INTEG_FLAG = 32; - /* * Optional features that the application can set and their default * values. @@ -697,25 +690,17 @@ public class SpNegoContext implements GSSContextSpi { /** * get the context flags */ - private byte[] getContextFlags() { - int flags = 0; + private BitArray getContextFlags() { + BitArray out = new BitArray(7); - if (getCredDelegState()) - flags |= CHECKSUM_DELEG_FLAG; - if (getMutualAuthState()) - flags |= CHECKSUM_MUTUAL_FLAG; - if (getReplayDetState()) - flags |= CHECKSUM_REPLAY_FLAG; - if (getSequenceDetState()) - flags |= CHECKSUM_SEQUENCE_FLAG; - if (getIntegState()) - flags |= CHECKSUM_INTEG_FLAG; - if (getConfState()) - flags |= CHECKSUM_CONF_FLAG; + if (getCredDelegState()) out.set(0, true); + if (getMutualAuthState()) out.set(1, true); + if (getReplayDetState()) out.set(2, true); + if (getSequenceDetState()) out.set(3, true); + if (getConfState()) out.set(5, true); + if (getIntegState()) out.set(6, true); - byte[] temp = new byte[1]; - temp[0] = (byte)(flags & 0xff); - return temp; + return out; } private void setContextFlags() { diff --git a/jdk/src/share/classes/sun/security/krb5/Realm.java b/jdk/src/share/classes/sun/security/krb5/Realm.java index 1dbffe26445..bf57e7a54ce 100644 --- a/jdk/src/share/classes/sun/security/krb5/Realm.java +++ b/jdk/src/share/classes/sun/security/krb5/Realm.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,6 @@ import sun.security.krb5.RealmException; import sun.security.krb5.internal.Krb5; import sun.security.util.*; import java.io.IOException; -import java.io.OutputStream; import java.util.StringTokenizer; import java.util.Vector; import java.util.Stack; @@ -364,7 +363,6 @@ public class Realm implements Cloneable { } String tempTarget = null, tempRealm = null; - StringTokenizer strTok = null; Stack<String> iStack = new Stack<String> (); /* @@ -382,7 +380,7 @@ public class Realm implements Cloneable { tempTarget = sRealm; } - do { + out: do { if (DEBUG) { count++; System.out.println(">>> Realm parseCapaths: loop " + @@ -400,15 +398,21 @@ public class Realm implements Cloneable { /* * We have one or more space-separated intermediary realms. - * Stack them. + * Stack them. A null is always added between intermedies of + * different targets. When this null is popped, it means none + * of the intermedies for this target is useful (because of + * infinite loop), the target is then removed from the partial + * tempList, and the next possible intermediary is tried. */ - strTok = new StringTokenizer(intermediaries, " "); - while (strTok.hasMoreTokens()) + iStack.push(null); + String[] ints = intermediaries.split("\\s+"); + for (int i = ints.length-1; i>=0; i--) { - tempRealm = strTok.nextToken(); - if (!tempRealm.equals(PrincipalName. - REALM_COMPONENT_SEPARATOR_STR) && - !iStack.contains(tempRealm)) { + tempRealm = ints[i]; + if (tempRealm.equals(PrincipalName.REALM_COMPONENT_SEPARATOR_STR)) { + break out; + } + if (!tempList.contains(tempRealm)) { iStack.push(tempRealm); if (DEBUG) { System.out.println(">>> Realm parseCapaths: loop " + @@ -418,16 +422,18 @@ public class Realm implements Cloneable { } } else if (DEBUG) { System.out.println(">>> Realm parseCapaths: loop " + - count + ": ignoring realm: [" + tempRealm + "]"); } } - } else if (DEBUG) { - System.out.println(">>> Realm parseCapaths: loop " + - count + - ": no intermediaries"); + } else { + if (DEBUG) { + System.out.println(">>> Realm parseCapaths: loop " + + count + + ": no intermediaries"); + } + break; } /* @@ -435,7 +441,12 @@ public class Realm implements Cloneable { */ try { - tempTarget = iStack.pop(); + while ((tempTarget = iStack.pop()) == null) { + tempList.removeElementAt(tempList.size()-1); + if (DEBUG) { + System.out.println(">>> Realm parseCapaths: backtrack, remove tail"); + } + } } catch (EmptyStackException exc) { tempTarget = null; } diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11Key.java b/jdk/src/share/classes/sun/security/pkcs11/P11Key.java index 8949826b19e..c70642d3531 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11Key.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11Key.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package sun.security.pkcs11; import java.io.*; +import java.lang.ref.*; import java.math.BigInteger; import java.util.*; @@ -67,9 +68,6 @@ abstract class P11Key implements Key { // type of key, one of (PUBLIC, PRIVATE, SECRET) final String type; - // session in which the key was created, relevant for session objects - final Session session; - // token instance final Token token; @@ -85,10 +83,12 @@ abstract class P11Key implements Key { // flags indicating whether the key is a token object, sensitive, extractable final boolean tokenObject, sensitive, extractable; + // weak reference notification clean up for session keys + private final SessionKeyRef sessionKeyRef; + P11Key(String type, Session session, long keyID, String algorithm, int keyLength, CK_ATTRIBUTE[] attributes) { this.type = type; - this.session = session; this.token = session.token; this.keyID = keyID; this.algorithm = algorithm; @@ -111,7 +111,9 @@ abstract class P11Key implements Key { this.sensitive = sensitive; this.extractable = extractable; if (tokenObject == false) { - session.addObject(); + sessionKeyRef = new SessionKeyRef(this, keyID, session); + } else { + sessionKeyRef = null; } } @@ -236,24 +238,6 @@ abstract class P11Key implements Key { } } - protected void finalize() throws Throwable { - if (tokenObject || (token.isValid() == false)) { - super.finalize(); - return; - } - Session newSession = null; - try { - newSession = token.getOpSession(); - token.p11.C_DestroyObject(newSession.id(), keyID); - } catch (PKCS11Exception e) { - // ignore - } finally { - token.releaseSession(newSession); - session.removeObject(); - super.finalize(); - } - } - private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0]; private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID, @@ -1055,5 +1039,65 @@ abstract class P11Key implements Key { + "\n parameters: " + params; } } - +} + +final class SessionKeyRef extends WeakReference<P11Key> + implements Comparable<SessionKeyRef> { + private static ReferenceQueue<P11Key> refQueue = + new ReferenceQueue<P11Key>(); + private static Set<SessionKeyRef> refList = + Collections.synchronizedSortedSet(new TreeSet<SessionKeyRef>()); + + static ReferenceQueue<P11Key> referenceQueue() { + return refQueue; + } + + static final private int MAX_ITERATIONS = 2; + + private static void drainRefQueueBounded() { + int iterations = 0; + while (iterations < MAX_ITERATIONS) { + SessionKeyRef next = (SessionKeyRef) refQueue.poll(); + if (next != null) next.dispose(); + ++iterations; + } + } + + // handle to the native key + private long keyID; + private Session session; + + SessionKeyRef(P11Key key , long keyID, Session session) { + super(key, refQueue); + this.keyID = keyID; + this.session = session; + this.session.addObject(); + refList.add(this); + // TBD: run at some interval and not every time? + drainRefQueueBounded(); + } + + void dispose() { + refList.remove(this); + if (session.token.isValid()) { + Session newSession = null; + try { + newSession = session.token.getOpSession(); + session.token.p11.C_DestroyObject(newSession.id(), keyID); + } catch (PKCS11Exception e) { + // ignore + } finally { + session.token.releaseSession(newSession); + session.removeObject(); + } + } + } + + public int compareTo(SessionKeyRef other) { + if (this.keyID == other.keyID) { + return 0; + } else { + return (this.keyID < other.keyID) ? -1 : 1; + } + } } diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java index 3b8244cc413..c3709ad5b13 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,7 +191,9 @@ final class P11RSACipher extends CipherSpi { throw new InvalidKeyException ("Unwrap has to be used with private keys"); } - encrypt = false; + // No further setup needed for C_Unwrap(). We'll initialize later + // if we can't use C_Unwrap(). + return; } else { throw new InvalidKeyException("Unsupported mode: " + opmode); } @@ -452,7 +454,7 @@ final class P11RSACipher extends CipherSpi { long keyID = token.p11.C_UnwrapKey(s.id(), new CK_MECHANISM(mechanism), p11Key.keyID, wrappedKey, attributes); - return P11Key.secretKey(session, keyID, algorithm, 48 << 3, + return P11Key.secretKey(s, keyID, algorithm, 48 << 3, attributes); } catch (PKCS11Exception e) { throw new InvalidKeyException("unwrap() failed", e); @@ -461,6 +463,7 @@ final class P11RSACipher extends CipherSpi { } } // XXX implement unwrap using C_Unwrap() for all keys + implInit(Cipher.DECRYPT_MODE, p11Key); if (wrappedKey.length > maxInputSize) { throw new InvalidKeyException("Key is too long for unwrapping"); } diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java b/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java index 59b59237a6f..d607900d651 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java @@ -151,7 +151,7 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi { session = token.getObjSession(); long newKeyID = token.p11.C_CopyObject(session.id(), p11Key.keyID, extraAttrs); - p11Key = (P11Key) (P11Key.secretKey(p11Key.session, + p11Key = (P11Key) (P11Key.secretKey(session, newKeyID, p11Key.algorithm, p11Key.keyLength, extraAttrs)); } catch (PKCS11Exception p11e) { diff --git a/jdk/src/share/classes/sun/security/provider/SeedGenerator.java b/jdk/src/share/classes/sun/security/provider/SeedGenerator.java index 3695e7c3cb9..dd345676a12 100644 --- a/jdk/src/share/classes/sun/security/provider/SeedGenerator.java +++ b/jdk/src/share/classes/sun/security/provider/SeedGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,6 +68,9 @@ import java.io.*; import java.util.Properties; import java.util.Enumeration; import java.net.*; +import java.nio.file.DirectoryStream; +import java.nio.file.Path; +import java.util.Random; import sun.security.util.Debug; abstract class SeedGenerator { @@ -180,10 +183,27 @@ abstract class SeedGenerator { // The temporary dir File f = new File(p.getProperty("java.io.tmpdir")); - String[] sa = f.list(); - for(int i = 0; i < sa.length; i++) - md.update(sa[i].getBytes()); - + int count = 0; + DirectoryStream<Path> ds + = f.toPath().newDirectoryStream(); + try { + // We use a Random object to choose what file names + // should be used. Otherwise on a machine with too + // many files, the same first 1024 files always get + // used. Any, We make sure the first 512 files are + // always used. + Random r = new Random(); + for (Path path: ds) { + if (count < 512 || r.nextBoolean()) { + md.update(path.getName().toString().getBytes()); + } + if (count++ > 1024) { + break; + } + } + } finally { + ds.close(); + } } catch (Exception ex) { md.update((byte)ex.hashCode()); } diff --git a/jdk/src/share/classes/sun/security/provider/X509Factory.java b/jdk/src/share/classes/sun/security/provider/X509Factory.java index 8fc755cc83d..ce0d120ae8d 100644 --- a/jdk/src/share/classes/sun/security/provider/X509Factory.java +++ b/jdk/src/share/classes/sun/security/provider/X509Factory.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -638,10 +638,15 @@ is) // First read all of the data that is found between // the "-----BEGIN" and "-----END" boundaries into a buffer. String temp; - if ((temp=readLine(br))==null || !temp.startsWith("-----BEGIN")) { - throw new IOException("Unsupported encoding"); - } else { + while (true) { + temp=readLine(br); + if (temp == null) { + throw new IOException("Unsupported encoding"); + } len += temp.length(); + if (temp.startsWith("-----BEGIN")) { + break; + } } StringBuffer strBuf = new StringBuffer(); while ((temp=readLine(br))!=null && !temp.startsWith("-----END")) { @@ -683,22 +688,11 @@ is) * Determines if input is binary or Base64 encoded. */ private boolean isBase64(InputStream is) throws IOException { - if (is.available() >= 10) { - is.mark(10); + if (is.available() >= 1) { + is.mark(1); int c1 = is.read(); - int c2 = is.read(); - int c3 = is.read(); - int c4 = is.read(); - int c5 = is.read(); - int c6 = is.read(); - int c7 = is.read(); - int c8 = is.read(); - int c9 = is.read(); - int c10 = is.read(); is.reset(); - if (c1 == '-' && c2 == '-' && c3 == '-' && c4 == '-' - && c5 == '-' && c6 == 'B' && c7 == 'E' && c8 == 'G' - && c9 == 'I' && c10 == 'N') { + if (c1 != DerValue.tag_Sequence) { return true; } else { return false; diff --git a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java index 20bac34f2cc..62cd4288ed0 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,6 @@ package sun.security.provider.certpath; import java.io.*; import java.math.BigInteger; import java.security.*; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; import java.security.cert.CertPathValidatorException; import java.security.cert.CRLReason; import java.security.cert.X509Certificate; @@ -335,7 +333,7 @@ class OCSPResponse { // Check whether the cert returned by the responder is trusted if (x509Certs != null && x509Certs[0] != null) { - X509Certificate cert = x509Certs[0]; + X509CertImpl cert = x509Certs[0]; // First check if the cert matches the responder cert which // was set locally. @@ -344,8 +342,8 @@ class OCSPResponse { // Next check if the cert was issued by the responder cert // which was set locally. - } else if (cert.getIssuerDN().equals( - responderCert.getSubjectDN())) { + } else if (cert.getIssuerX500Principal().equals( + responderCert.getSubjectX500Principal())) { // Check for the OCSPSigning key purpose List<String> keyPurposes = cert.getExtendedKeyUsage(); @@ -360,6 +358,43 @@ class OCSPResponse { "OCSP responses"); } + // check the validity + try { + Date dateCheckedAgainst = params.getDate(); + if (dateCheckedAgainst == null) { + cert.checkValidity(); + } else { + cert.checkValidity(dateCheckedAgainst); + } + } catch (GeneralSecurityException e) { + if (DEBUG != null) { + DEBUG.println("Responder's certificate is not " + + "within the validity period."); + } + throw new CertPathValidatorException( + "Responder's certificate not within the " + + "validity period"); + } + + // check for revocation + // + // A CA may specify that an OCSP client can trust a + // responder for the lifetime of the responder's + // certificate. The CA does so by including the + // extension id-pkix-ocsp-nocheck. + // + Extension noCheck = + cert.getExtension(PKIXExtensions.OCSPNoCheck_Id); + if (noCheck != null) { + if (DEBUG != null) { + DEBUG.println("Responder's certificate includes " + + "the extension id-pkix-ocsp-nocheck."); + } + } else { + // we should do the revocating checking of the + // authorized responder in a future update. + } + // verify the signature try { cert.verify(responderCert.getPublicKey()); @@ -369,6 +404,14 @@ class OCSPResponse { } catch (GeneralSecurityException e) { responderCert = null; } + } else { + if (DEBUG != null) { + DEBUG.println("Responder's certificate is not " + + "authorized to sign OCSP responses."); + } + throw new CertPathValidatorException( + "Responder's certificate not authorized to sign " + + "OCSP responses"); } } diff --git a/jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java b/jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java index d5f12168dda..7c3bfc37843 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,11 +143,15 @@ class PKIXMasterCertPathValidator { } } catch (CertPathValidatorException cpve) { - // Throw the saved OCSP exception - // (when the CRL check has also failed) + // Throw the saved OCSP exception unless the CRL + // checker has determined that the cert is revoked if (ocspCause != null && - currChecker instanceof CrlRevocationChecker) { - throw ocspCause; + currChecker instanceof CrlRevocationChecker) { + if (cpve.getReason() == BasicReason.REVOKED) { + throw cpve; + } else { + throw ocspCause; + } } /* * Handle failover from OCSP to CRLs diff --git a/jdk/src/share/classes/sun/security/ssl/AppInputStream.java b/jdk/src/share/classes/sun/security/ssl/AppInputStream.java index d638b8f46e9..2ca889593c0 100644 --- a/jdk/src/share/classes/sun/security/ssl/AppInputStream.java +++ b/jdk/src/share/classes/sun/security/ssl/AppInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,14 @@ class AppInputStream extends InputStream { */ public synchronized int read(byte b[], int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + if (c.checkEOF()) { return -1; } diff --git a/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java b/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java index d039cacb8b2..d8c78a8eb50 100644 --- a/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java +++ b/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,18 +58,25 @@ class AppOutputStream extends OutputStream { */ synchronized public void write(byte b[], int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + // check if the Socket is invalid (error or closed) c.checkWrite(); - // + // Always flush at the end of each application level record. // This lets application synchronize read and write streams // however they like; if we buffered here, they couldn't. - // - // NOTE: *must* call c.writeRecord() even for len == 0 try { do { int howmuch = Math.min(len, r.availableDataBytes()); + // NOTE: *must* call c.writeRecord() even for howmuch == 0 if (howmuch > 0) { r.write(b, off, howmuch); off += howmuch; diff --git a/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java b/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java index 9c484d87ed3..d69e2bfdc54 100644 --- a/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java +++ b/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,8 +89,7 @@ class ByteBufferInputStream extends InputStream { if (b == null) { throw new NullPointerException(); - } else if ((off < 0) || (off > b.length) || (len < 0) || - ((off + len) > b.length) || ((off + len) < 0)) { + } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java index c98f1cc2c26..3aeef2d8eee 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,88 +41,112 @@ import javax.net.ssl.SSLSessionBindingEvent; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; -import sun.misc.Cache; +import sun.security.util.Cache; -final class SSLSessionContextImpl implements SSLSessionContext -{ - private Cache sessionCache = new Cache(); - private Cache sessionHostPortCache = new Cache(); - private int cacheLimit; - private long timeoutMillis; +final class SSLSessionContextImpl implements SSLSessionContext { + private Cache sessionCache; // session cache, session id as key + private Cache sessionHostPortCache; // session cache, "host:port" as key + private int cacheLimit; // the max cache size + private int timeout; // timeout in seconds + private static final Debug debug = Debug.getInstance("ssl"); - // file private - SSLSessionContextImpl() - { - cacheLimit = getCacheLimit(); - timeoutMillis = 86400000; // default, 24 hours + // package private + SSLSessionContextImpl() { + cacheLimit = getDefaultCacheLimit(); // default cache size + timeout = 86400; // default, 24 hours + + // use soft reference + sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout); + sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout); } /** - * Returns the SSL session object associated with the - * specific session ID passed. + * Returns the <code>SSLSession</code> bound to the specified session id. */ - public SSLSession getSession(byte[] id) - { - SSLSession sess = (SSLSession) sessionCache.get( - new SessionId(id)); - return checkTimeValidity(sess); + public SSLSession getSession(byte[] sessionId) { + if (sessionId == null) { + throw new NullPointerException("session id cannot be null"); + } + + SSLSessionImpl sess = + (SSLSessionImpl)sessionCache.get(new SessionId(sessionId)); + if (!isTimedout(sess)) { + return sess; + } + + return null; } /** * Returns an enumeration of the active SSL sessions. */ public Enumeration<byte[]> getIds() { - Vector<byte[]> v = new Vector<byte[]>(sessionCache.size()); - SessionId sessId; + SessionCacheVisitor scVisitor = new SessionCacheVisitor(); + sessionCache.accept(scVisitor); - for (Enumeration e = sessionCache.keys(); e.hasMoreElements(); ) { - sessId = (SessionId) e.nextElement(); - if (!isTimedout((SSLSession)sessionCache.get(sessId))) - v.addElement(sessId.getId()); - } - return v.elements(); + return scVisitor.getSessionIds(); } + /** + * Sets the timeout limit for cached <code>SSLSession</code> objects + * + * Note that after reset the timeout, the cached session before + * should be timed within the shorter one of the old timeout and the + * new timeout. + */ public void setSessionTimeout(int seconds) throws IllegalArgumentException { - if (seconds < 0) + if (seconds < 0) { throw new IllegalArgumentException(); - timeoutMillis = seconds * 1000L; + } + + if (timeout != seconds) { + sessionCache.setTimeout(seconds); + sessionHostPortCache.setTimeout(seconds); + timeout = seconds; + } } + /** + * Gets the timeout limit for cached <code>SSLSession</code> objects + */ public int getSessionTimeout() { - return (int) (timeoutMillis / 1000); + return timeout; } + /** + * Sets the size of the cache used for storing + * <code>SSLSession</code> objects. + */ public void setSessionCacheSize(int size) throws IllegalArgumentException { if (size < 0) throw new IllegalArgumentException(); - cacheLimit = size; - /** - * If cache size limit is reduced, when the cache is full to its - * previous limit, trim the cache before its contents - * are used. - */ - if ((cacheLimit != 0) && (sessionCache.size() > cacheLimit)) - adjustCacheSizeTo(cacheLimit); + if (cacheLimit != size) { + sessionCache.setCapacity(size); + sessionHostPortCache.setCapacity(size); + cacheLimit = size; + } } + /** + * Gets the size of the cache used for storing + * <code>SSLSession</code> objects. + */ public int getSessionCacheSize() { return cacheLimit; } + + // package-private method, used ONLY by ServerHandshaker SSLSessionImpl get(byte[] id) { - return (SSLSessionImpl) getSession(id); + return (SSLSessionImpl)getSession(id); } - /** - * Returns the SSL session object associated with the - * specific host name and port number passed. - */ + // package-private method, used ONLY by ClientHandshaker SSLSessionImpl get(String hostname, int port) { /* * If no session caching info is available, we won't @@ -131,96 +155,51 @@ final class SSLSessionContextImpl implements SSLSessionContext if (hostname == null && port == -1) { return null; } - SSLSession sess = (SSLSessionImpl) sessionHostPortCache - .get(getKey(hostname, port)); - return (SSLSessionImpl) checkTimeValidity(sess); + + SSLSessionImpl sess = + (SSLSessionImpl)sessionHostPortCache.get(getKey(hostname, port)); + if (!isTimedout(sess)) { + return sess; + } + + return null; } private String getKey(String hostname, int port) { - return (hostname + ":" + String.valueOf(port)) - .toLowerCase(); + return (hostname + ":" + String.valueOf(port)).toLowerCase(); } + // cache a SSLSession + // + // In SunJSSE implementation, a session is created while getting a + // client hello or a server hello message, and cached while the + // handshaking finished. + // Here we time the session from the time it cached instead of the + // time it created, which is a little longer than the expected. So + // please do check isTimedout() while getting entry from the cache. void put(SSLSessionImpl s) { - // make space for the new session to be added - if ((cacheLimit != 0) && (sessionCache.size() >= cacheLimit)) - adjustCacheSizeTo(cacheLimit - 1); - - /* - * Can always add the session id. - */ sessionCache.put(s.getSessionId(), s); - /* - * If no hostname/port info is available, don't add this one. - */ + // If no hostname/port info is available, don't add this one. if ((s.getPeerHost() != null) && (s.getPeerPort() != -1)) { sessionHostPortCache.put( getKey(s.getPeerHost(), s.getPeerPort()), s); } + s.setContext(this); } - private void adjustCacheSizeTo(int targetSize) { - - int cacheSize = sessionCache.size(); - - if (targetSize < 0) - return; - - while (cacheSize > targetSize) { - SSLSessionImpl lru = null; - SSLSessionImpl s = null; - Enumeration e; - - if (debug != null && Debug.isOn("sessioncache")) { - System.out.println("exceeded cache limit of " + cacheLimit); - } - - /* - * Count the number of elements in the cache. The size() method - * does not reflect the cache entries that are no longer available, - * i.e entries that are garbage collected (the cache entries are - * held using soft references and are garbage collected when not - * in use). - */ - int count; - for (count = 0, e = sessionCache.elements(); - e.hasMoreElements(); count++) { - try { - s = (SSLSessionImpl)e.nextElement(); - } catch (NoSuchElementException nsee) { - break; - } - if (isTimedout(s)) { - lru = s; - break; - } else if ((lru == null) || (s.getLastAccessedTime() - < lru.getLastAccessedTime())) { - lru = s; - } - } - if ((lru != null) && (count > targetSize)) { - if (debug != null && Debug.isOn("sessioncache")) { - System.out.println("uncaching " + lru); - } - lru.invalidate(); - count--; // element removed from the cache - } - cacheSize = count; + // package-private method, remove a cached SSLSession + void remove(SessionId key) { + SSLSessionImpl s = (SSLSessionImpl)sessionCache.get(key); + if (s != null) { + sessionCache.remove(key); + sessionHostPortCache.remove( + getKey(s.getPeerHost(), s.getPeerPort())); } } - // file private - void remove(SessionId key) - { - SSLSessionImpl s = (SSLSessionImpl) sessionCache.get(key); - sessionCache.remove(key); - sessionHostPortCache.remove(getKey(s.getPeerHost(), - s.getPeerPort())); - } - - private int getCacheLimit() { + private int getDefaultCacheLimit() { int cacheLimit = 0; try { String s = java.security.AccessController.doPrivileged( @@ -237,21 +216,40 @@ final class SSLSessionContextImpl implements SSLSessionContext return (cacheLimit > 0) ? cacheLimit : 0; } - SSLSession checkTimeValidity(SSLSession sess) { - if (isTimedout(sess)) { - sess.invalidate(); - return null; - } else - return sess; - } - boolean isTimedout(SSLSession sess) { - if (timeoutMillis == 0) + if (timeout == 0) { return false; - if ((sess != null) && - ((sess.getCreationTime() + timeoutMillis) - <= (System.currentTimeMillis()))) + } + + if ((sess != null) && ((sess.getCreationTime() + timeout * 1000L) + <= (System.currentTimeMillis()))) { + sess.invalidate(); return true; + } + return false; } + + final class SessionCacheVisitor + implements sun.security.util.Cache.CacheVisitor { + Vector<byte[]> ids = null; + + // public void visit(java.util.Map<Object, Object> map) {} + public void visit(java.util.Map<Object, Object> map) { + ids = new Vector<byte[]>(map.size()); + + for (Object key : map.keySet()) { + SSLSessionImpl value = (SSLSessionImpl)map.get(key); + if (!isTimedout(value)) { + ids.addElement(((SessionId)key).getId()); + } + } + } + + public Enumeration<byte[]> getSessionIds() { + return ids != null ? ids.elements() : + new Vector<byte[]>().elements(); + } + } + } diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java index 7974f1b13b4..820954f9613 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -368,7 +368,9 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { super(); this.host = host; init(context, false); - SocketAddress socketAddress = new InetSocketAddress(host, port); + SocketAddress socketAddress = + host != null ? new InetSocketAddress(host, port) : + new InetSocketAddress(InetAddress.getByName(null), port); connect(socketAddress, 0); } @@ -409,7 +411,9 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { this.host = host; init(context, false); bind(new InetSocketAddress(localAddr, localPort)); - SocketAddress socketAddress = new InetSocketAddress(host, port); + SocketAddress socketAddress = + host != null ? new InetSocketAddress(host, port) : + new InetSocketAddress(InetAddress.getByName(null), port); connect(socketAddress, 0); } @@ -1829,7 +1833,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { } synchronized String getHost() { - if (host == null) { + // Note that the host may be null or empty for localhost. + if (host == null || host.length() == 0) { host = getInetAddress().getHostName(); } return host; diff --git a/jdk/src/share/classes/sun/security/tools/JarSigner.java b/jdk/src/share/classes/sun/security/tools/JarSigner.java index d8d1ee3d517..2de2e52b08a 100644 --- a/jdk/src/share/classes/sun/security/tools/JarSigner.java +++ b/jdk/src/share/classes/sun/security/tools/JarSigner.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,28 +32,44 @@ import java.util.jar.*; import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.SocketTimeoutException; import java.text.Collator; import java.text.MessageFormat; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; import java.security.*; import java.lang.reflect.Constructor; import com.sun.jarsigner.ContentSigner; import com.sun.jarsigner.ContentSignerParameters; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.util.Map.Entry; import sun.security.x509.*; import sun.security.util.*; import sun.misc.BASE64Encoder; + /** * <p>The jarsigner utility. * + * The exit codes for the main method are: + * + * 0: success + * 1: any error that the jar cannot be signed or verified, including: + * keystore loading error + * TSP communciation error + * jarsigner command line error... + * otherwise: error codes from -strict + * * @author Roland Schemers * @author Jan Luehe */ @@ -84,8 +100,6 @@ public class JarSigner { // Attention: // This is the entry that get launched by the security tool jarsigner. - // It's marked as exported private per AppServer Team's request. - // See http://ccc.sfbay/6428446 public static void main(String args[]) throws Exception { JarSigner js = new JarSigner(); js.run(args); @@ -93,31 +107,32 @@ public class JarSigner { static final String VERSION = "1.0"; - static final int IN_KEYSTORE = 0x01; + static final int IN_KEYSTORE = 0x01; // signer is in keystore static final int IN_SCOPE = 0x02; + static final int NOT_ALIAS = 0x04; // alias list is NOT empty and + // signer is not in alias list + static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list - // signer's certificate chain (when composing) - X509Certificate[] certChain; - - /* - * private key - */ - PrivateKey privateKey; - KeyStore store; + X509Certificate[] certChain; // signer's cert chain (when composing) + PrivateKey privateKey; // private key + KeyStore store; // the keystore specified by -keystore + // or the default keystore, never null IdentityScope scope; String keystore; // key store file boolean nullStream = false; // null keystore input stream (NONE) boolean token = false; // token-based keystore - String jarfile; // jar file to sign + String jarfile; // jar file to sign or verify String alias; // alias to sign jar with + List<String> ckaliases = new ArrayList<String>(); // aliases in -verify char[] storepass; // keystore password boolean protectedPath; // protected authentication path String storetype; // keystore type String providerName; // provider name Vector<String> providers = null; // list of providers - HashMap<String,String> providerArgs = new HashMap<String, String>(); // arguments for provider constructors + // arguments for provider constructors + HashMap<String,String> providerArgs = new HashMap<String, String>(); char[] keypass; // private key password String sigfile; // name of .SF file String sigalg; // name of signature algorithm @@ -125,12 +140,14 @@ public class JarSigner { String signedjar; // output filename String tsaUrl; // location of the Timestamping Authority String tsaAlias; // alias for the Timestamping Authority's certificate + String altCertChain; // file to read alternative cert chain from boolean verify = false; // verify the jar - boolean verbose = false; // verbose output when signing/verifying + String verbose = null; // verbose output when signing/verifying boolean showcerts = false; // show certs when verifying boolean debug = false; // debug boolean signManifest = true; // "sign" the whole manifest boolean externalSF = true; // leave the .SF out of the PKCS7 block + boolean strict = false; // treat warnings as error // read zip entry raw bytes private ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); @@ -139,14 +156,22 @@ public class JarSigner { private String altSignerClass = null; private String altSignerClasspath = null; private ZipFile zipFile = null; + private boolean hasExpiredCert = false; private boolean hasExpiringCert = false; private boolean notYetValidCert = false; - + private boolean chainNotValidated = false; + private boolean notSignedByAlias = false; + private boolean aliasNotInStore = false; + private boolean hasUnsignedEntry = false; private boolean badKeyUsage = false; private boolean badExtendedKeyUsage = false; private boolean badNetscapeCertType = false; + CertificateFactory certificateFactory; + CertPathValidator validator; + PKIXParameters pkixParameters; + public void run(String args[]) { try { parseArgs(args); @@ -184,14 +209,6 @@ public class JarSigner { } } - hasExpiredCert = false; - hasExpiringCert = false; - notYetValidCert = false; - - badKeyUsage = false; - badExtendedKeyUsage = false; - badNetscapeCertType = false; - if (verify) { try { loadKeyStore(keystore, false); @@ -238,6 +255,29 @@ public class JarSigner { storepass = null; } } + + if (strict) { + int exitCode = 0; + if (hasExpiringCert) { + exitCode |= 2; + } + if (chainNotValidated) { + // hasExpiredCert and notYetValidCert included in this case + exitCode |= 4; + } + if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) { + exitCode |= 8; + } + if (hasUnsignedEntry) { + exitCode |= 16; + } + if (notSignedByAlias || aliasNotInStore) { + exitCode |= 32; + } + if (exitCode != 0) { + System.exit(exitCode); + } + } } /* @@ -247,25 +287,26 @@ public class JarSigner { /* parse flags */ int n = 0; - for (n=0; (n < args.length) && args[n].startsWith("-"); n++) { + if (args.length == 0) fullusage(); + for (n=0; n < args.length; n++) { String flags = args[n]; if (collator.compare(flags, "-keystore") == 0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); keystore = args[n]; } else if (collator.compare(flags, "-storepass") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); storepass = args[n].toCharArray(); } else if (collator.compare(flags, "-storetype") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); storetype = args[n]; } else if (collator.compare(flags, "-providerName") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); providerName = args[n]; } else if ((collator.compare(flags, "-provider") == 0) || (collator.compare(flags, "-providerClass") == 0)) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); if (providers == null) { providers = new Vector<String>(3); } @@ -274,35 +315,38 @@ public class JarSigner { if (args.length > (n+1)) { flags = args[n+1]; if (collator.compare(flags, "-providerArg") == 0) { - if (args.length == (n+2)) usage(); + if (args.length == (n+2)) usageNoArg(); providerArgs.put(args[n], args[n+2]); n += 2; } } } else if (collator.compare(flags, "-protected") ==0) { protectedPath = true; + } else if (collator.compare(flags, "-certchain") ==0) { + if (++n == args.length) usageNoArg(); + altCertChain = args[n]; } else if (collator.compare(flags, "-debug") ==0) { debug = true; } else if (collator.compare(flags, "-keypass") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); keypass = args[n].toCharArray(); } else if (collator.compare(flags, "-sigfile") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); sigfile = args[n]; } else if (collator.compare(flags, "-signedjar") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); signedjar = args[n]; } else if (collator.compare(flags, "-tsa") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); tsaUrl = args[n]; } else if (collator.compare(flags, "-tsacert") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); tsaAlias = args[n]; } else if (collator.compare(flags, "-altsigner") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); altSignerClass = args[n]; } else if (collator.compare(flags, "-altsignerpath") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); altSignerClasspath = args[n]; } else if (collator.compare(flags, "-sectionsonly") ==0) { signManifest = false; @@ -311,30 +355,56 @@ public class JarSigner { } else if (collator.compare(flags, "-verify") ==0) { verify = true; } else if (collator.compare(flags, "-verbose") ==0) { - verbose = true; + verbose = "all"; + } else if (collator.compare(flags, "-verbose:all") ==0) { + verbose = "all"; + } else if (collator.compare(flags, "-verbose:summary") ==0) { + verbose = "summary"; + } else if (collator.compare(flags, "-verbose:grouped") ==0) { + verbose = "grouped"; } else if (collator.compare(flags, "-sigalg") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); sigalg = args[n]; } else if (collator.compare(flags, "-digestalg") ==0) { - if (++n == args.length) usage(); + if (++n == args.length) usageNoArg(); digestalg = args[n]; } else if (collator.compare(flags, "-certs") ==0) { showcerts = true; + } else if (collator.compare(flags, "-strict") ==0) { + strict = true; } else if (collator.compare(flags, "-h") == 0 || collator.compare(flags, "-help") == 0) { - usage(); + fullusage(); } else { - System.err.println(rb.getString("Illegal option: ") + flags); - usage(); + if (!flags.startsWith("-")) { + if (jarfile == null) { + jarfile = flags; + } else { + alias = flags; + ckaliases.add(alias); + } + } else { + System.err.println( + rb.getString("Illegal option: ") + flags); + usage(); + } } } - if (n == args.length) usage(); - jarfile = args[n++]; + // -certs must always be specified with -verbose + if (verbose == null) showcerts = false; - if (!verify) { - if (n == args.length) usage(); - alias = args[n++]; + if (jarfile == null) { + System.err.println(rb.getString("Please specify jarfile name")); + usage(); + } + if (!verify && alias == null) { + System.err.println(rb.getString("Please specify alias name")); + usage(); + } + if (!verify && ckaliases.size() > 1) { + System.err.println(rb.getString("Only one alias can be specified")); + usage(); } if (storetype == null) { @@ -357,7 +427,6 @@ public class JarSigner { if (token && !nullStream) { System.err.println(MessageFormat.format(rb.getString ("-keystore must be NONE if -storetype is {0}"), storetype)); - System.err.println(); usage(); } @@ -365,7 +434,6 @@ public class JarSigner { System.err.println(MessageFormat.format(rb.getString ("-keypass can not be specified " + "if -storetype is {0}"), storetype)); - System.err.println(); usage(); } @@ -374,7 +442,6 @@ public class JarSigner { System.err.println(rb.getString ("If -protected is specified, " + "then -storepass and -keypass must not be specified")); - System.err.println(); usage(); } } @@ -383,17 +450,27 @@ public class JarSigner { System.err.println(rb.getString ("If keystore is not password protected, " + "then -storepass and -keypass must not be specified")); - System.err.println(); usage(); } } } + void usageNoArg() { + System.out.println(rb.getString("Option lacks argument")); + usage(); + } + void usage() { + System.out.println(); + System.out.println(rb.getString("Please type jarsigner -help for usage")); + System.exit(1); + } + + void fullusage() { System.out.println(rb.getString ("Usage: jarsigner [options] jar-file alias")); System.out.println(rb.getString - (" jarsigner -verify [options] jar-file")); + (" jarsigner -verify [options] jar-file [alias...]")); System.out.println(); System.out.println(rb.getString ("[-keystore <url>] keystore location")); @@ -407,6 +484,9 @@ public class JarSigner { System.out.println(rb.getString ("[-keypass <password>] password for private key (if different)")); System.out.println(); + System.out.println(rb.getString + ("[-certchain <file>] name of alternative certchain file")); + System.out.println(); System.out.println(rb.getString ("[-sigfile <file>] name of .SF/.DSA file")); System.out.println(); @@ -423,7 +503,9 @@ public class JarSigner { ("[-verify] verify a signed JAR file")); System.out.println(); System.out.println(rb.getString - ("[-verbose] verbose output when signing/verifying")); + ("[-verbose[:suboptions]] verbose output when signing/verifying.")); + System.out.println(rb.getString + (" suboptions can be all, grouped or summary")); System.out.println(); System.out.println(rb.getString ("[-certs] display certificates when verbose and verifying")); @@ -457,15 +539,17 @@ public class JarSigner { System.out.println(rb.getString (" [-providerArg <arg>]] ... master class file and constructor argument")); System.out.println(); + System.out.println(rb.getString + ("[-strict] treat warnings as errors")); + System.out.println(); - System.exit(1); + System.exit(0); } void verifyJar(String jarName) throws Exception { - boolean anySigned = false; - boolean hasUnsignedEntry = false; + boolean anySigned = false; // if there exists entry inside jar signed JarFile jf = null; try { @@ -494,11 +578,18 @@ public class JarSigner { Manifest man = jf.getManifest(); + // The map to record display info, only used when -verbose provided + // key: signer info string + // value: the list of files with common key + Map<String,List<String>> output = + new LinkedHashMap<String,List<String>>(); + if (man != null) { - if (verbose) System.out.println(); + if (verbose != null) System.out.println(); Enumeration<JarEntry> e = entriesVec.elements(); long now = System.currentTimeMillis(); + String tab = rb.getString(" "); while (e.hasMoreElements()) { JarEntry je = e.nextElement(); @@ -509,77 +600,118 @@ public class JarSigner { hasUnsignedEntry |= !je.isDirectory() && !isSigned && !signatureRelated(name); - if (verbose) { - int inStoreOrScope = inKeyStore(signers); - boolean inStore = (inStoreOrScope & IN_KEYSTORE) != 0; - boolean inScope = (inStoreOrScope & IN_SCOPE) != 0; + int inStoreOrScope = inKeyStore(signers); + + boolean inStore = (inStoreOrScope & IN_KEYSTORE) != 0; + boolean inScope = (inStoreOrScope & IN_SCOPE) != 0; + + notSignedByAlias |= (inStoreOrScope & NOT_ALIAS) != 0; + aliasNotInStore |= isSigned && (!inStore && !inScope); + + // Only used when -verbose provided + StringBuffer sb = null; + if (verbose != null) { + sb = new StringBuffer(); boolean inManifest = ((man.getAttributes(name) != null) || (man.getAttributes("./"+name) != null) || (man.getAttributes("/"+name) != null)); - System.out.print( + sb.append( (isSigned ? rb.getString("s") : rb.getString(" ")) + (inManifest ? rb.getString("m") : rb.getString(" ")) + (inStore ? rb.getString("k") : rb.getString(" ")) + (inScope ? rb.getString("i") : rb.getString(" ")) + - rb.getString(" ")); - StringBuffer sb = new StringBuffer(); + ((inStoreOrScope & NOT_ALIAS) != 0 ?"X":" ") + + rb.getString(" ")); + sb.append("|"); + } + + // When -certs provided, display info has extra empty + // lines at the beginning and end. + if (isSigned) { + if (showcerts) sb.append('\n'); + for (CodeSigner signer: signers) { + // signerInfo() must be called even if -verbose + // not provided. The method updates various + // warning flags. + String si = signerInfo(signer, tab, now); + if (showcerts) { + sb.append(si); + sb.append('\n'); + } + } + } else if (showcerts && !verbose.equals("all")) { + // Print no info for unsigned entries when -verbose:all, + // to be consistent with old behavior. + if (signatureRelated(name)) { + sb.append("\n" + tab + rb.getString( + "(Signature related entries)") + "\n\n"); + } else { + sb.append("\n" + tab + rb.getString( + "(Unsigned entries)") + "\n\n"); + } + } + + if (verbose != null) { + String label = sb.toString(); + if (signatureRelated(name)) { + // Entries inside META-INF and other unsigned + // entries are grouped separately. + label = "-" + label.substring(1); + } + + // The label finally contains 2 parts separated by '|': + // The legend displayed before the entry names, and + // the cert info (if -certs specfied). + + if (!output.containsKey(label)) { + output.put(label, new ArrayList<String>()); + } + + StringBuffer fb = new StringBuffer(); String s = Long.toString(je.getSize()); for (int i = 6 - s.length(); i > 0; --i) { - sb.append(' '); - } - sb.append(s).append(' '). - append(new Date(je.getTime()).toString()); - sb.append(' ').append(je.getName()); - System.out.println(sb.toString()); - - if (signers != null && showcerts) { - String tab = rb.getString(" "); - for (int i = 0; i < signers.length; i++) { - System.out.println(); - List<? extends Certificate> certs = - signers[i].getSignerCertPath() - .getCertificates(); - // display the signature timestamp, if present - Timestamp timestamp = signers[i].getTimestamp(); - if (timestamp != null) { - System.out.println( - printTimestamp(tab, timestamp)); - } - // display the certificate(s) - for (Certificate c : certs) { - System.out.println( - printCert(tab, c, true, now)); - } - } - System.out.println(); + fb.append(' '); } + fb.append(s).append(' '). + append(new Date(je.getTime()).toString()); + fb.append(' ').append(name); + output.get(label).add(fb.toString()); } - if (isSigned) { - for (int i = 0; i < signers.length; i++) { - Certificate cert = - signers[i].getSignerCertPath() - .getCertificates().get(0); - if (cert instanceof X509Certificate) { - checkCertUsage((X509Certificate)cert, null); - if (!showcerts) { - long notAfter = ((X509Certificate)cert) - .getNotAfter().getTime(); - - if (notAfter < now) { - hasExpiredCert = true; - } else if (notAfter < now + SIX_MONTHS) { - hasExpiringCert = true; - } - } - } - } - } - } } - if (verbose) { + if (verbose != null) { + for (Entry<String,List<String>> s: output.entrySet()) { + List<String> files = s.getValue(); + String key = s.getKey(); + if (key.charAt(0) == '-') { // the signature-related group + key = ' ' + key.substring(1); + } + int pipe = key.indexOf('|'); + if (verbose.equals("all")) { + for (String f: files) { + System.out.println(key.substring(0, pipe) + f); + System.out.printf(key.substring(pipe+1)); + } + } else { + if (verbose.equals("grouped")) { + for (String f: files) { + System.out.println(key.substring(0, pipe) + f); + } + } else if (verbose.equals("summary")) { + System.out.print(key.substring(0, pipe)); + if (files.size() > 1) { + System.out.println(files.get(0) + " " + + String.format(rb.getString( + "(and %d more)"), files.size()-1)); + } else { + System.out.println(files.get(0)); + } + } + System.out.printf(key.substring(pipe+1)); + } + } System.out.println(); System.out.println(rb.getString( " s = signature was verified ")); @@ -589,9 +721,12 @@ public class JarSigner { " k = at least one certificate was found in keystore")); System.out.println(rb.getString( " i = at least one certificate was found in identity scope")); + if (ckaliases.size() > 0) { + System.out.println(( + " X = not signed by specified alias(es)")); + } System.out.println(); } - if (man == null) System.out.println(rb.getString("no manifest.")); @@ -602,7 +737,8 @@ public class JarSigner { System.out.println(rb.getString("jar verified.")); if (hasUnsignedEntry || hasExpiredCert || hasExpiringCert || badKeyUsage || badExtendedKeyUsage || badNetscapeCertType || - notYetValidCert) { + notYetValidCert || chainNotValidated || + aliasNotInStore || notSignedByAlias) { System.out.println(); System.out.println(rb.getString("Warning: ")); @@ -638,14 +774,27 @@ public class JarSigner { "This jar contains entries whose signer certificate is not yet valid. ")); } - if (! (verbose && showcerts)) { + if (chainNotValidated) { + System.out.println( + rb.getString("This jar contains entries whose certificate chain is not validated.")); + } + + if (notSignedByAlias) { + System.out.println( + rb.getString("This jar contains signed entries which is not signed by the specified alias(es).")); + } + + if (aliasNotInStore) { + System.out.println(rb.getString("This jar contains signed entries that's not signed by alias in this keystore.")); + } + if (! (verbose != null && showcerts)) { System.out.println(); System.out.println(rb.getString( "Re-run with the -verbose and -certs options for more details.")); } } } - System.exit(0); + return; } catch (Exception e) { System.out.println(rb.getString("jarsigner: ") + e); if (debug) { @@ -660,15 +809,6 @@ public class JarSigner { System.exit(1); } - /* - * Display some details about a certificate: - * - * <cert-type> [", " <subject-DN>] [" (" <keystore-entry-alias> ")"] - */ - String printCert(Certificate c) { - return printCert("", c, false, 0); - } - private static MessageFormat validityTimeForm = null; private static MessageFormat notYetTimeForm = null; private static MessageFormat expiredTimeForm = null; @@ -679,6 +819,8 @@ public class JarSigner { * * [<tab>] <cert-type> [", " <subject-DN>] [" (" <keystore-entry-alias> ")"] * [<validity-period> | <expiry-warning>] + * + * Note: no newline character at the end */ String printCert(String tab, Certificate c, boolean checkValidityPeriod, long now) { @@ -788,54 +930,75 @@ public class JarSigner { .append(signTimeForm.format(source)).append("]").toString(); } + private Map<CodeSigner,Integer> cacheForInKS = + new IdentityHashMap<CodeSigner,Integer>(); + + private int inKeyStoreForOneSigner(CodeSigner signer) { + if (cacheForInKS.containsKey(signer)) { + return cacheForInKS.get(signer); + } + + boolean found = false; + int result = 0; + List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates(); + for (Certificate c : certs) { + String alias = storeHash.get(c); + if (alias != null) { + if (alias.startsWith("(")) { + result |= IN_KEYSTORE; + } else if (alias.startsWith("[")) { + result |= IN_SCOPE; + } + if (ckaliases.contains(alias.substring(1, alias.length() - 1))) { + result |= SIGNED_BY_ALIAS; + } + } else { + if (store != null) { + try { + alias = store.getCertificateAlias(c); + } catch (KeyStoreException kse) { + // never happens, because keystore has been loaded + } + if (alias != null) { + storeHash.put(c, "(" + alias + ")"); + found = true; + result |= IN_KEYSTORE; + } + } + if (!found && (scope != null)) { + Identity id = scope.getIdentity(c.getPublicKey()); + if (id != null) { + result |= IN_SCOPE; + storeHash.put(c, "[" + id.getName() + "]"); + } + } + if (ckaliases.contains(alias)) { + result |= SIGNED_BY_ALIAS; + } + } + } + cacheForInKS.put(signer, result); + return result; + } + Hashtable<Certificate, String> storeHash = new Hashtable<Certificate, String>(); int inKeyStore(CodeSigner[] signers) { - int result = 0; if (signers == null) return 0; - boolean found = false; + int output = 0; - for (int i = 0; i < signers.length; i++) { - found = false; - List<? extends Certificate> certs = - signers[i].getSignerCertPath().getCertificates(); - - for (Certificate c : certs) { - String alias = storeHash.get(c); - - if (alias != null) { - if (alias.startsWith("(")) - result |= IN_KEYSTORE; - else if (alias.startsWith("[")) - result |= IN_SCOPE; - } else { - if (store != null) { - try { - alias = store.getCertificateAlias(c); - } catch (KeyStoreException kse) { - // never happens, because keystore has been loaded - } - if (alias != null) { - storeHash.put(c, "("+alias+")"); - found = true; - result |= IN_KEYSTORE; - } - } - if (!found && (scope != null)) { - Identity id = scope.getIdentity(c.getPublicKey()); - if (id != null) { - result |= IN_SCOPE; - storeHash.put(c, "["+id.getName()+"]"); - } - } - } - } + for (CodeSigner signer: signers) { + int result = inKeyStoreForOneSigner(signer); + output |= result; } - return result; + if (ckaliases.size() > 0 && (output & SIGNED_BY_ALIAS) == 0) { + output |= NOT_ALIAS; + } + return output; } void signJar(String jarName, String alias, String[] args) @@ -1025,7 +1188,7 @@ public class JarSigner { // manifest file has new length mfFile = new ZipEntry(JarFile.MANIFEST_NAME); } - if (verbose) { + if (verbose != null) { if (mfCreated) { System.out.println(rb.getString(" adding: ") + mfFile.getName()); @@ -1076,7 +1239,7 @@ public class JarSigner { // signature file zos.putNextEntry(sfFile); sf.write(zos); - if (verbose) { + if (verbose != null) { if (zipFile.getEntry(sfFilename) != null) { System.out.println(rb.getString(" updating: ") + sfFilename); @@ -1086,7 +1249,7 @@ public class JarSigner { } } - if (verbose) { + if (verbose != null) { if (tsaUrl != null || tsaCert != null) { System.out.println( rb.getString("requesting a signature timestamp")); @@ -1101,8 +1264,8 @@ public class JarSigner { System.out.println(rb.getString("TSA location: ") + certUrl); } - System.out.println( - rb.getString("TSA certificate: ") + printCert(tsaCert)); + System.out.println(rb.getString("TSA certificate: ") + + printCert("", tsaCert, false, 0)); } if (signingMechanism != null) { System.out.println( @@ -1113,7 +1276,7 @@ public class JarSigner { // signature block file zos.putNextEntry(bkFile); block.write(zos); - if (verbose) { + if (verbose != null) { if (zipFile.getEntry(bkFilename) != null) { System.out.println(rb.getString(" updating: ") + bkFilename); @@ -1140,7 +1303,7 @@ public class JarSigner { ZipEntry ze = enum_.nextElement(); if (!ze.getName().startsWith(META_INF)) { - if (verbose) { + if (verbose != null) { if (manifest.getAttributes(ze.getName()) != null) System.out.println(rb.getString(" signing: ") + ze.getName()); @@ -1194,7 +1357,8 @@ public class JarSigner { } if (hasExpiredCert || hasExpiringCert || notYetValidCert - || badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) { + || badKeyUsage || badExtendedKeyUsage + || badNetscapeCertType || chainNotValidated) { System.out.println(); System.out.println(rb.getString("Warning: ")); @@ -1223,6 +1387,11 @@ public class JarSigner { System.out.println( rb.getString("The signer certificate is not yet valid.")); } + + if (chainNotValidated) { + System.out.println( + rb.getString("The signer's certificate chain is not validated.")); + } } // no IOException thrown in the above try clause, so disable @@ -1274,6 +1443,40 @@ public class JarSigner { return false; } + Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<CodeSigner,String>(); + + /** + * Returns a string of singer info, with a newline at the end + */ + private String signerInfo(CodeSigner signer, String tab, long now) { + if (cacheForSignerInfo.containsKey(signer)) { + return cacheForSignerInfo.get(signer); + } + StringBuffer s = new StringBuffer(); + List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates(); + // display the signature timestamp, if present + Timestamp timestamp = signer.getTimestamp(); + if (timestamp != null) { + s.append(printTimestamp(tab, timestamp)); + } + // display the certificate(s) + for (Certificate c : certs) { + s.append(printCert(tab, c, true, now)); + s.append('\n'); + } + try { + CertPath cp = certificateFactory.generateCertPath(certs); + validator.validate(cp, pkixParameters); + } catch (Exception e) { + chainNotValidated = true; + s.append(tab + rb.getString("[CertPath not validated: ") + + e.getLocalizedMessage() + "]\n"); // TODO + } + String result = s.toString(); + cacheForSignerInfo.put(signer, result); + return result; + } + private void writeEntry(ZipFile zf, ZipOutputStream os, ZipEntry ze) throws IOException { @@ -1360,6 +1563,48 @@ public class JarSigner { } } } + Set<TrustAnchor> tas = new HashSet<TrustAnchor>(); + try { + KeyStore caks = KeyTool.getCacertsKeyStore(); + if (caks != null) { + Enumeration<String> aliases = caks.aliases(); + while (aliases.hasMoreElements()) { + String a = aliases.nextElement(); + try { + tas.add(new TrustAnchor((X509Certificate)caks.getCertificate(a), null)); + } catch (Exception e2) { + // ignore, when a SecretkeyEntry does not include a cert + } + } + } + } catch (Exception e) { + // Ignore, if cacerts cannot be loaded + } + if (store != null) { + Enumeration<String> aliases = store.aliases(); + while (aliases.hasMoreElements()) { + String a = aliases.nextElement(); + try { + X509Certificate c = (X509Certificate)store.getCertificate(a); + // Only add TrustedCertificateEntry and self-signed + // PrivateKeyEntry + if (store.isCertificateEntry(a) || + c.getSubjectDN().equals(c.getIssuerDN())) { + tas.add(new TrustAnchor(c, null)); + } + } catch (Exception e2) { + // ignore, when a SecretkeyEntry does not include a cert + } + } + } + certificateFactory = CertificateFactory.getInstance("X.509"); + validator = CertPathValidator.getInstance("PKIX"); + try { + pkixParameters = new PKIXParameters(tas); + pkixParameters.setRevocationEnabled(false); + } catch (InvalidAlgorithmParameterException ex) { + // Only if tas is empty + } } catch (IOException ioe) { throw new RuntimeException(rb.getString("keystore load: ") + ioe.getMessage()); @@ -1408,7 +1653,8 @@ public class JarSigner { void checkCertUsage(X509Certificate userCert, boolean[] bad) { // Can act as a signer? - // 1. if KeyUsage, then [0] should be true + // 1. if KeyUsage, then [0:digitalSignature] or + // [1:nonRepudiation] should be true // 2. if ExtendedKeyUsage, then should contains ANY or CODE_SIGNING // 3. if NetscapeCertType, then should contains OBJECT_SIGNING // 1,2,3 must be true @@ -1419,10 +1665,10 @@ public class JarSigner { boolean[] keyUsage = userCert.getKeyUsage(); if (keyUsage != null) { - if (keyUsage.length < 1 || !keyUsage[0]) { + keyUsage = Arrays.copyOf(keyUsage, 9); + if (!keyUsage[0] && !keyUsage[1]) { if (bad != null) { bad[0] = true; - } else { badKeyUsage = true; } } @@ -1435,7 +1681,6 @@ public class JarSigner { && !xKeyUsage.contains("1.3.6.1.5.5.7.3.3")) { // codeSigning if (bad != null) { bad[1] = true; - } else { badExtendedKeyUsage = true; } } @@ -1462,7 +1707,6 @@ public class JarSigner { if (!val) { if (bad != null) { bad[2] = true; - } else { badNetscapeCertType = true; } } @@ -1477,19 +1721,36 @@ public class JarSigner { Key key = null; try { - java.security.cert.Certificate[] cs = null; - - try { - cs = store.getCertificateChain(alias); - } catch (KeyStoreException kse) { - // this never happens, because keystore has been loaded + if (altCertChain != null) { + try { + cs = CertificateFactory.getInstance("X.509"). + generateCertificates(new FileInputStream(altCertChain)). + toArray(new Certificate[0]); + } catch (CertificateException ex) { + error(rb.getString("Cannot restore certchain from file specified")); + } catch (FileNotFoundException ex) { + error(rb.getString("File specified by -certchain does not exist")); + } + } else { + try { + cs = store.getCertificateChain(alias); + } catch (KeyStoreException kse) { + // this never happens, because keystore has been loaded + } } - if (cs == null) { - MessageFormat form = new MessageFormat(rb.getString - ("Certificate chain not found for: alias. alias must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.")); - Object[] source = {alias, alias}; - error(form.format(source)); + if (cs == null || cs.length == 0) { + if (altCertChain != null) { + error(rb.getString + ("Certificate chain not found in the file specified.")); + } else { + MessageFormat form = new MessageFormat(rb.getString + ("Certificate chain not found for: alias. alias must" + + " reference a valid KeyStore key entry containing a" + + " private key and corresponding public key certificate chain.")); + Object[] source = {alias, alias}; + error(form.format(source)); + } } certChain = new X509Certificate[cs.length]; @@ -1501,56 +1762,15 @@ public class JarSigner { certChain[i] = (X509Certificate)cs[i]; } - // order the cert chain if necessary (put user cert first, - // root-cert last in the chain) - X509Certificate userCert - = (X509Certificate)store.getCertificate(alias); + // We don't meant to print anything, the next call + // checks validity and keyUsage etc + printCert("", certChain[0], true, 0); - // check validity of signer certificate try { - userCert.checkValidity(); - - if (userCert.getNotAfter().getTime() < - System.currentTimeMillis() + SIX_MONTHS) { - - hasExpiringCert = true; - } - } catch (CertificateExpiredException cee) { - hasExpiredCert = true; - - } catch (CertificateNotYetValidException cnyve) { - notYetValidCert = true; - } - - checkCertUsage(userCert, null); - - if (!userCert.equals(certChain[0])) { - // need to order ... - X509Certificate[] certChainTmp - = new X509Certificate[certChain.length]; - certChainTmp[0] = userCert; - Principal issuer = userCert.getIssuerDN(); - for (int i=1; i<certChain.length; i++) { - int j; - // look for the cert whose subject corresponds to the - // given issuer - for (j=0; j<certChainTmp.length; j++) { - if (certChainTmp[j] == null) - continue; - Principal subject = certChainTmp[j].getSubjectDN(); - if (issuer.equals(subject)) { - certChain[i] = certChainTmp[j]; - issuer = certChainTmp[j].getIssuerDN(); - certChainTmp[j] = null; - break; - } - } - if (j == certChainTmp.length) { - error(rb.getString("incomplete certificate chain")); - } - - } - certChain = certChainTmp; // ordered + CertPath cp = certificateFactory.generateCertPath(Arrays.asList(certChain)); + validator.validate(cp, pkixParameters); + } catch (Exception e) { + chainNotValidated = true; } try { diff --git a/jdk/src/share/classes/sun/security/tools/JarSignerResources.java b/jdk/src/share/classes/sun/security/tools/JarSignerResources.java index 473ea3b035d..7e259e8e8fe 100644 --- a/jdk/src/share/classes/sun/security/tools/JarSignerResources.java +++ b/jdk/src/share/classes/sun/security/tools/JarSignerResources.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,8 +54,8 @@ public class JarSignerResources extends java.util.ListResourceBundle { "If keystore is not password protected, then -storepass and -keypass must not be specified"}, {"Usage: jarsigner [options] jar-file alias", "Usage: jarsigner [options] jar-file alias"}, - {" jarsigner -verify [options] jar-file", - " jarsigner -verify [options] jar-file"}, + {" jarsigner -verify [options] jar-file [alias...]", + " jarsigner -verify [options] jar-file [alias...]"}, {"[-keystore <url>] keystore location", "[-keystore <url>] keystore location"}, {"[-storepass <password>] password for keystore integrity", @@ -64,6 +64,8 @@ public class JarSignerResources extends java.util.ListResourceBundle { "[-storetype <type>] keystore type"}, {"[-keypass <password>] password for private key (if different)", "[-keypass <password>] password for private key (if different)"}, + {"[-certchain <file>] name of alternative certchain file", + "[-certchain <file>] name of alternative certchain file"}, {"[-sigfile <file>] name of .SF/.DSA file", "[-sigfile <file>] name of .SF/.DSA file"}, {"[-signedjar <file>] name of signed JAR file", @@ -74,8 +76,10 @@ public class JarSignerResources extends java.util.ListResourceBundle { "[-sigalg <algorithm>] name of signature algorithm"}, {"[-verify] verify a signed JAR file", "[-verify] verify a signed JAR file"}, - {"[-verbose] verbose output when signing/verifying", - "[-verbose] verbose output when signing/verifying"}, + {"[-verbose[:suboptions]] verbose output when signing/verifying.", + "[-verbose[:suboptions]] verbose output when signing/verifying."}, + {" suboptions can be all, grouped or summary", + " suboptions can be all, grouped or summary"}, {"[-certs] display certificates when verbose and verifying", "[-certs] display certificates when verbose and verifying"}, {"[-tsa <url>] location of the Timestamping Authority", @@ -98,10 +102,22 @@ public class JarSignerResources extends java.util.ListResourceBundle { "[-providerClass <class> name of cryptographic service provider's"}, {" [-providerArg <arg>]] ... master class file and constructor argument", " [-providerArg <arg>]] ... master class file and constructor argument"}, + {"[-strict] treat warnings as errors", + "[-strict] treat warnings as errors"}, + {"Option lacks argument", "Option lacks argument"}, + {"Please type jarsigner -help for usage", "Please type jarsigner -help for usage"}, + {"Please specify jarfile name", "Please specify jarfile name"}, + {"Please specify alias name", "Please specify alias name"}, + {"Only one alias can be specified", "Only one alias can be specified"}, + {"This jar contains signed entries which is not signed by the specified alias(es).", + "This jar contains signed entries which is not signed by the specified alias(es)."}, + {"This jar contains signed entries that's not signed by alias in this keystore.", + "This jar contains signed entries that's not signed by alias in this keystore."}, {"s", "s"}, {"m", "m"}, {"k", "k"}, {"i", "i"}, + {"(and %d more)", "(and %d more)"}, {" s = signature was verified ", " s = signature was verified "}, {" m = entry is listed in manifest", @@ -110,7 +126,11 @@ public class JarSignerResources extends java.util.ListResourceBundle { " k = at least one certificate was found in keystore"}, {" i = at least one certificate was found in identity scope", " i = at least one certificate was found in identity scope"}, + {" X = not signed by specified alias(es)", + " X = not signed by specified alias(es)"}, {"no manifest.", "no manifest."}, + {"(Signature related entries)","(Signature related entries)"}, + {"(Unsigned entries)", "(Unsigned entries)"}, {"jar is unsigned. (signatures missing or not parsable)", "jar is unsigned. (signatures missing or not parsable)"}, {"jar verified.", "jar verified."}, @@ -134,6 +154,12 @@ public class JarSignerResources extends java.util.ListResourceBundle { "unable to instantiate keystore class: "}, {"Certificate chain not found for: alias. alias must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.", "Certificate chain not found for: {0}. {1} must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain."}, + {"File specified by -certchain does not exist", + "File specified by -certchain does not exist"}, + {"Cannot restore certchain from file specified", + "Cannot restore certchain from file specified"}, + {"Certificate chain not found in the file specified.", + "Certificate chain not found in the file specified."}, {"found non-X.509 certificate in signer's chain", "found non-X.509 certificate in signer's chain"}, {"incomplete certificate chain", "incomplete certificate chain"}, @@ -149,6 +175,7 @@ public class JarSignerResources extends java.util.ListResourceBundle { {"certificate is not valid until", "certificate is not valid until {0}"}, {"certificate will expire on", "certificate will expire on {0}"}, + {"[CertPath not validated: ", "[CertPath not validated: "}, {"requesting a signature timestamp", "requesting a signature timestamp"}, {"TSA location: ", "TSA location: "}, @@ -189,14 +216,18 @@ public class JarSignerResources extends java.util.ListResourceBundle { "The signer certificate's ExtendedKeyUsage extension doesn't allow code signing."}, {"The signer certificate's NetscapeCertType extension doesn't allow code signing.", "The signer certificate's NetscapeCertType extension doesn't allow code signing."}, - {"This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing.", - "This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing."}, - {"This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing.", - "This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing."}, - {"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing.", - "This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing."}, + {"This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing.", + "This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing."}, + {"This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing.", + "This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing."}, + {"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing.", + "This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing."}, {"[{0} extension does not support code signing]", "[{0} extension does not support code signing]"}, + {"The signer's certificate chain is not validated.", + "The signer's certificate chain is not validated."}, + {"This jar contains entries whose certificate chain is not validated.", + "This jar contains entries whose certificate chain is not validated."}, }; /** diff --git a/jdk/src/share/classes/sun/security/tools/KeyTool.java b/jdk/src/share/classes/sun/security/tools/KeyTool.java index 220dbd033b1..9b4b16fa11d 100644 --- a/jdk/src/share/classes/sun/security/tools/KeyTool.java +++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,6 +69,10 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import sun.misc.BASE64Decoder; +import sun.security.pkcs.PKCS10Attribute; +import sun.security.pkcs.PKCS9Attribute; +import sun.security.util.DerValue; import sun.security.x509.*; import static java.security.KeyStore.*; @@ -85,7 +89,6 @@ import static java.security.KeyStore.*; * * @since 1.2 */ - public final class KeyTool { private boolean debug = false; @@ -100,6 +103,8 @@ public final class KeyTool { private String dname = null; private String dest = null; private String filename = null; + private String infilename = null; + private String outfilename = null; private String srcksfname = null; // User-specified providers are added before any command is called. @@ -117,7 +122,6 @@ public final class KeyTool { private char[] storePassNew = null; private char[] keyPass = null; private char[] keyPassNew = null; - private char[] oldPass = null; private char[] newPass = null; private char[] destKeyPass = null; private char[] srckeyPass = null; @@ -140,6 +144,8 @@ public final class KeyTool { private Set<char[]> passwords = new HashSet<char[]> (); private String startDate = null; + private List <String> v3ext = new ArrayList <String> (); + private static final int CERTREQ = 1; private static final int CHANGEALIAS = 2; private static final int DELETE = 3; @@ -156,6 +162,8 @@ public final class KeyTool { private static final int PRINTCERT = 13; private static final int SELFCERT = 14; private static final int STOREPASSWD = 15; + private static final int GENCERT = 16; + private static final int PRINTCERTREQ = 17; private static final Class[] PARAM_STRING = { String.class }; @@ -184,7 +192,9 @@ public final class KeyTool { private void run(String[] args, PrintStream out) throws Exception { try { parseArgs(args); - doCommands(out); + if (command != -1) { + doCommands(out); + } } catch (Exception e) { System.out.println(rb.getString("keytool error: ") + e); if (verbose) { @@ -214,7 +224,10 @@ public final class KeyTool { */ void parseArgs(String[] args) { - if (args.length == 0) usage(); + if (args.length == 0) { + usage(); + return; + } int i=0; @@ -260,6 +273,10 @@ public final class KeyTool { command = IMPORTKEYSTORE; } else if (collator.compare(flags, "-genseckey") == 0) { command = GENSECKEY; + } else if (collator.compare(flags, "-gencert") == 0) { + command = GENCERT; + } else if (collator.compare(flags, "-printcertreq") == 0) { + command = PRINTCERTREQ; } /* @@ -337,9 +354,18 @@ public final class KeyTool { } else if (collator.compare(flags, "-validity") == 0) { if (++i == args.length) errorNeedArgument(flags); validity = Long.parseLong(args[i]); + } else if (collator.compare(flags, "-ext") == 0) { + if (++i == args.length) errorNeedArgument(flags); + v3ext.add(args[i]); } else if (collator.compare(flags, "-file") == 0) { if (++i == args.length) errorNeedArgument(flags); filename = args[i]; + } else if (collator.compare(flags, "-infile") == 0) { + if (++i == args.length) errorNeedArgument(flags); + infilename = args[i]; + } else if (collator.compare(flags, "-outfile") == 0) { + if (++i == args.length) errorNeedArgument(flags); + outfilename = args[i]; } else if (collator.compare(flags, "-sslserver") == 0) { if (++i == args.length) errorNeedArgument(flags); sslserver = args[i]; @@ -364,7 +390,7 @@ public final class KeyTool { } } providers.add( - new Pair<String, String>(providerClass, providerArg)); + Pair.of(providerClass, providerArg)); } /* @@ -404,6 +430,10 @@ public final class KeyTool { } } + boolean isKeyStoreRelated(int cmd) { + return cmd != PRINTCERT && cmd != PRINTCERTREQ; + } + /** * Execute the commands. */ @@ -568,7 +598,7 @@ public final class KeyTool { // the default, which is located in $HOME/.keystore. // If the command is "genkey", "identitydb", "import", or "printcert", // it is OK not to have a keystore. - if (command != PRINTCERT) { + if (isKeyStoreRelated(command)) { if (ksfname == null) { ksfname = System.getProperty("user.home") + File.separator + ".keystore"; @@ -721,7 +751,7 @@ public final class KeyTool { } } else if (!protectedPath && !KeyStoreUtil.isWindowsKeyStore(storetype) - && !(command == PRINTCERT)) { + && isKeyStoreRelated(command)) { // here we have EXPORTCERT and LIST (info valid until STOREPASSWD) System.err.print(rb.getString("Enter keystore password: ")); System.err.flush(); @@ -763,7 +793,7 @@ public final class KeyTool { // Create a certificate factory if (command == PRINTCERT || command == IMPORTCERT - || command == IDENTITYDB) { + || command == IDENTITYDB) { cf = CertificateFactory.getInstance("X509"); } @@ -845,6 +875,18 @@ public final class KeyTool { if (filename != null) { inStream = new FileInputStream(filename); } + // Read the full stream before feeding to X509Factory, + // otherwise, keytool -gencert | keytool -importcert + // might not work properly, since -gencert is slow + // and there's no data in the pipe at the beginning. + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + byte[] b = new byte[4096]; + while (true) { + int len = inStream.read(b); + if (len < 0) break; + bout.write(b, 0, len); + } + inStream = new ByteArrayInputStream(bout.toByteArray()); try { String importAlias = (alias!=null)?alias:keyAlias; if (keyStore.entryInstanceOf(importAlias, KeyStore.PrivateKeyEntry.class)) { @@ -930,6 +972,41 @@ public final class KeyTool { storePassNew = getNewPasswd("keystore password", storePass); } kssave = true; + } else if (command == GENCERT) { + if (alias == null) { + alias = keyAlias; + } + InputStream inStream = System.in; + if (infilename != null) { + inStream = new FileInputStream(infilename); + } + PrintStream ps = null; + if (outfilename != null) { + ps = new PrintStream(new FileOutputStream(outfilename)); + out = ps; + } + try { + doGenCert(alias, sigAlgName, inStream, out); + } finally { + if (inStream != System.in) { + inStream.close(); + } + if (ps != null) { + ps.close(); + } + } + } else if (command == PRINTCERTREQ) { + InputStream inStream = System.in; + if (filename != null) { + inStream = new FileInputStream(filename); + } + try { + doPrintCertReq(inStream, out); + } finally { + if (inStream != System.in) { + inStream.close(); + } + } } // If we need to save the keystore, do so. @@ -961,6 +1038,91 @@ public final class KeyTool { } } + /** + * Generate a certificate: Read PKCS10 request from in, and print + * certificate to out. Use alias as CA, sigAlgName as the signature + * type. + */ + private void doGenCert(String alias, String sigAlgName, InputStream in, PrintStream out) + throws Exception { + + + Certificate signerCert = keyStore.getCertificate(alias); + byte[] encoded = signerCert.getEncoded(); + X509CertImpl signerCertImpl = new X509CertImpl(encoded); + X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + X500Name owner = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." + + CertificateSubjectName.DN_NAME); + + Date firstDate = getStartDate(startDate); + Date lastDate = new Date(); + lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); + CertificateValidity interval = new CertificateValidity(firstDate, + lastDate); + + PrivateKey privateKey = (PrivateKey)recoverKey(alias, storePass, keyPass).fst; + if (sigAlgName == null) { + sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm()); + } + Signature signature = Signature.getInstance(sigAlgName); + signature.initSign(privateKey); + + X500Signer signer = new X500Signer(signature, owner); + + X509CertInfo info = new X509CertInfo(); + info.set(X509CertInfo.VALIDITY, interval); + info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( + new java.util.Random().nextInt() & 0x7fffffff)); + info.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + info.set(X509CertInfo.ALGORITHM_ID, + new CertificateAlgorithmId(signer.getAlgorithmId())); + info.set(X509CertInfo.ISSUER, + new CertificateIssuerName(signer.getSigner())); + + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + boolean canRead = false; + StringBuffer sb = new StringBuffer(); + while (true) { + String s = reader.readLine(); + if (s == null) break; + // OpenSSL does not use NEW + //if (s.startsWith("-----BEGIN NEW CERTIFICATE REQUEST-----")) { + if (s.startsWith("-----BEGIN") && s.indexOf("REQUEST") >= 0) { + canRead = true; + //} else if (s.startsWith("-----END NEW CERTIFICATE REQUEST-----")) { + } else if (s.startsWith("-----END") && s.indexOf("REQUEST") >= 0) { + break; + } else if (canRead) { + sb.append(s); + } + } + byte[] rawReq = new BASE64Decoder().decodeBuffer(new String(sb)); + PKCS10 req = new PKCS10(rawReq); + + info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo())); + info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(req.getSubjectName())); + CertificateExtensions reqex = null; + Iterator<PKCS10Attribute> attrs = req.getAttributes().getAttributes().iterator(); + while (attrs.hasNext()) { + PKCS10Attribute attr = attrs.next(); + if (attr.getAttributeId().equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) { + reqex = (CertificateExtensions)attr.getAttributeValue(); + } + } + CertificateExtensions ext = createV3Extensions( + reqex, + null, + v3ext, + req.getSubjectPublicKeyInfo(), + signerCert.getPublicKey()); + info.set(X509CertInfo.EXTENSIONS, ext); + X509CertImpl cert = new X509CertImpl(info); + cert.sign(privateKey, sigAlgName); + dumpCert(cert, out); + } + /** * Creates a PKCS#10 cert signing request, corresponding to the * keys (and name) associated with a given alias. @@ -972,10 +1134,10 @@ public final class KeyTool { alias = keyAlias; } - Object[] objs = recoverKey(alias, storePass, keyPass); - PrivateKey privKey = (PrivateKey)objs[0]; + Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass); + PrivateKey privKey = (PrivateKey)objs.fst; if (keyPass == null) { - keyPass = (char[])objs[1]; + keyPass = objs.snd; } Certificate cert = keyStore.getCertificate(alias); @@ -986,21 +1148,14 @@ public final class KeyTool { throw new Exception(form.format(source)); } PKCS10 request = new PKCS10(cert.getPublicKey()); + CertificateExtensions ext = createV3Extensions(null, null, v3ext, cert.getPublicKey(), null); + // Attribute name is not significant + request.getAttributes().setAttribute(X509CertInfo.EXTENSIONS, + new PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID, ext)); // Construct an X500Signer object, so that we can sign the request if (sigAlgName == null) { - // If no signature algorithm was specified at the command line, - // we choose one that is compatible with the selected private key - String keyAlgName = privKey.getAlgorithm(); - if ("DSA".equalsIgnoreCase(keyAlgName) - || "DSS".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithDSA"; - } else if ("RSA".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithRSA"; - } else { - throw new Exception(rb.getString - ("Cannot derive signature algorithm")); - } + sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm()); } Signature signature = Signature.getInstance(sigAlgName); @@ -1152,6 +1307,23 @@ public final class KeyTool { keyStore.setKeyEntry(alias, secKey, keyPass, null); } + /** + * If no signature algorithm was specified at the command line, + * we choose one that is compatible with the selected private key + */ + private static String getCompatibleSigAlgName(String keyAlgName) + throws Exception { + if ("DSA".equalsIgnoreCase(keyAlgName)) { + return "SHA1WithDSA"; + } else if ("RSA".equalsIgnoreCase(keyAlgName)) { + return "SHA1WithRSA"; + } else if ("EC".equalsIgnoreCase(keyAlgName)) { + return "SHA1withECDSA"; + } else { + throw new Exception(rb.getString + ("Cannot derive signature algorithm")); + } + } /** * Creates a new key pair and self-signed certificate. */ @@ -1179,16 +1351,7 @@ public final class KeyTool { } if (sigAlgName == null) { - if ("DSA".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithDSA"; - } else if ("RSA".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithRSA"; - } else if ("EC".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1withECDSA"; - } else { - throw new Exception(rb.getString - ("Cannot derive signature algorithm")); - } + sigAlgName = getCompatibleSigAlgName(keyAlgName); } CertAndKeyGen keypair = new CertAndKeyGen(keyAlgName, sigAlgName, providerName); @@ -1225,6 +1388,9 @@ public final class KeyTool { keyPass = promptForKeyPass(alias, null, storePass); } keyStore.setKeyEntry(alias, privKey, keyPass, chain); + + // resign so that -ext are applied. + doSelfCert(alias, null, sigAlgName); } /** @@ -1247,9 +1413,9 @@ public final class KeyTool { throw new Exception(form.format(source)); } - Object[] objs = recoverEntry(keyStore, orig, storePass, keyPass); - Entry entry = (Entry)objs[0]; - keyPass = (char[])objs[1]; + Pair<Entry,char[]> objs = recoverEntry(keyStore, orig, storePass, keyPass); + Entry entry = objs.fst; + keyPass = objs.snd; PasswordProtection pp = null; @@ -1275,10 +1441,10 @@ public final class KeyTool { if (alias == null) { alias = keyAlias; } - Object[] objs = recoverKey(alias, storePass, keyPass); - Key privKey = (Key)objs[0]; + Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass); + Key privKey = objs.fst; if (keyPass == null) { - keyPass = (char[])objs[1]; + keyPass = objs.snd; } if (keyPassNew == null) { @@ -1629,8 +1795,8 @@ public final class KeyTool { } } - Object[] objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass); - Entry entry = (Entry)objs[0]; + Pair<Entry,char[]> objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass); + Entry entry = objs.fst; PasswordProtection pp = null; @@ -1640,8 +1806,8 @@ public final class KeyTool { // so always try to protect with destKeyPass. if (destKeyPass != null) { pp = new PasswordProtection(destKeyPass); - } else if (objs[1] != null) { - pp = new PasswordProtection((char[])objs[1]); + } else if (objs.snd != null) { + pp = new PasswordProtection(objs.snd); } try { @@ -1726,9 +1892,52 @@ public final class KeyTool { } } + private void doPrintCertReq(InputStream in, PrintStream out) + throws Exception { + + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuffer sb = new StringBuffer(); + boolean started = false; + while (true) { + String s = reader.readLine(); + if (s == null) break; + if (!started) { + if (s.startsWith("-----")) { + started = true; + } + } else { + if (s.startsWith("-----")) { + break; + } + sb.append(s); + } + } + PKCS10 req = new PKCS10(new BASE64Decoder().decodeBuffer(new String(sb))); + + PublicKey pkey = req.getSubjectPublicKeyInfo(); + out.printf(rb.getString("PKCS #10 Certificate Request (Version 1.0)\n" + + "Subject: %s\nPublic Key: %s format %s key\n"), + req.getSubjectName(), pkey.getFormat(), pkey.getAlgorithm()); + for (PKCS10Attribute attr: req.getAttributes().getAttributes()) { + ObjectIdentifier oid = attr.getAttributeId(); + if (oid.equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) { + CertificateExtensions exts = (CertificateExtensions)attr.getAttributeValue(); + if (exts != null) { + printExtensions(rb.getString("Extension Request:"), exts, out); + } + } else { + out.println(attr.getAttributeId()); + out.println(attr.getAttributeValue()); + } + } + if (debug) { + out.println(req); // Just to see more, say, public key length... + } + } + /** * Reads a certificate (or certificate chain) and prints its contents in - * a human readbable format. + * a human readable format. */ private void printCertFromStream(InputStream in, PrintStream out) throws Exception @@ -1840,7 +2049,18 @@ public final class KeyTool { inStream = new FileInputStream(filename); } try { - printCertFromStream(inStream, out); + // Read the full stream before feeding to X509Factory, + // otherwise, keytool -gencert | keytool -printcert + // might not work properly, since -gencert is slow + // and there's no data in the pipe at the beginning. + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + byte[] b = new byte[4096]; + while (true) { + int len = inStream.read(b); + if (len < 0) break; + bout.write(b, 0, len); + } + printCertFromStream(new ByteArrayInputStream(bout.toByteArray()), out); } finally { if (inStream != System.in) { inStream.close(); @@ -1859,27 +2079,14 @@ public final class KeyTool { alias = keyAlias; } - Object[] objs = recoverKey(alias, storePass, keyPass); - PrivateKey privKey = (PrivateKey)objs[0]; + Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass); + PrivateKey privKey = (PrivateKey)objs.fst; if (keyPass == null) - keyPass = (char[])objs[1]; + keyPass = objs.snd; // Determine the signature algorithm if (sigAlgName == null) { - // If no signature algorithm was specified at the command line, - // we choose one that is compatible with the selected private key - String keyAlgName = privKey.getAlgorithm(); - if ("DSA".equalsIgnoreCase(keyAlgName) - || "DSS".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithDSA"; - } else if ("RSA".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithRSA"; - } else if ("EC".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1withECDSA"; - } else { - throw new Exception - (rb.getString("Cannot derive signature algorithm")); - } + sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm()); } // Get the old certificate @@ -1914,8 +2121,8 @@ public final class KeyTool { certInfo.set(X509CertInfo.VALIDITY, interval); // Make new serial number - certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber - ((int)(firstDate.getTime()/1000))); + certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( + new java.util.Random().nextInt() & 0x7fffffff)); // Set owner and issuer fields X500Name owner; @@ -1943,11 +2150,16 @@ public final class KeyTool { certInfo.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, sigAlgid); - // first upgrade to version 3 - certInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); + CertificateExtensions ext = createV3Extensions( + null, + (CertificateExtensions)certInfo.get(X509CertInfo.EXTENSIONS), + v3ext, + oldCert.getPublicKey(), + null); + certInfo.set(X509CertInfo.EXTENSIONS, ext); // Sign the new certificate newCert = new X509CertImpl(certInfo); newCert.sign(privKey, sigAlgName); @@ -1985,10 +2197,10 @@ public final class KeyTool { alias = keyAlias; } - Object[] objs = recoverKey(alias, storePass, keyPass); - PrivateKey privKey = (PrivateKey)objs[0]; + Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass); + PrivateKey privKey = (PrivateKey)objs.fst; if (keyPass == null) { - keyPass = (char[])objs[1]; + keyPass = objs.snd; } Certificate userCert = keyStore.getCertificate(alias); @@ -2290,36 +2502,42 @@ public final class KeyTool { }; out.println(form.format(source)); - int extnum = 0; if (cert instanceof X509CertImpl) { X509CertImpl impl = (X509CertImpl)cert; - if (cert.getCriticalExtensionOIDs() != null) { - for (String extOID : cert.getCriticalExtensionOIDs()) { - if (extnum == 0) { - out.println(); - out.println(rb.getString("Extensions: ")); - out.println(); - } - out.println("#"+(++extnum)+": "+ - impl.getExtension(new ObjectIdentifier(extOID))); - } - } - if (cert.getNonCriticalExtensionOIDs() != null) { - for (String extOID : cert.getNonCriticalExtensionOIDs()) { - if (extnum == 0) { - out.println(); - out.println(rb.getString("Extensions: ")); - out.println(); - } - Extension ext = impl.getExtension(new ObjectIdentifier(extOID)); - if (ext != null) { - out.println("#"+(++extnum)+": "+ ext); - } else { - out.println("#"+(++extnum)+": "+ - impl.getUnparseableExtension(new ObjectIdentifier(extOID))); - } + X509CertInfo certInfo = (X509CertInfo)impl.get(X509CertImpl.NAME + + "." + + X509CertImpl.INFO); + CertificateExtensions exts = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + if (exts != null) { + printExtensions(rb.getString("Extensions: "), exts, out); + } + } + } + + private static void printExtensions(String title, CertificateExtensions exts, PrintStream out) + throws Exception { + int extnum = 0; + Iterator<Extension> i1 = exts.getAllExtensions().iterator(); + Iterator<Extension> i2 = exts.getUnparseableExtensions().values().iterator(); + while (i1.hasNext() || i2.hasNext()) { + Extension ext = i1.hasNext()?i1.next():i2.next(); + if (extnum == 0) { + out.println(); + out.println(title); + out.println(); + } + out.print("#"+(++extnum)+": "+ ext); + if (ext.getClass() == Extension.class) { + byte[] v = ext.getExtensionValue(); + if (v.length == 0) { + out.println(rb.getString("(Empty value)")); + } else { + new sun.misc.HexDumpEncoder().encode(ext.getExtensionValue(), out); + out.println(); } } + out.println(); } } @@ -2327,7 +2545,19 @@ public final class KeyTool { * Returns true if the certificate is self-signed, false otherwise. */ private boolean isSelfSigned(X509Certificate cert) { - return cert.getSubjectDN().equals(cert.getIssuerDN()); + return signedBy(cert, cert); + } + + private boolean signedBy(X509Certificate end, X509Certificate ca) { + if (!ca.getSubjectDN().equals(end.getIssuerDN())) { + return false; + } + try { + end.verify(ca.getPublicKey()); + return true; + } catch (Exception e) { + return false; + } } /** @@ -2470,7 +2700,7 @@ public final class KeyTool { * recovered private key, and the 2nd element is the password used to * recover it. */ - private Object[] recoverKey(String alias, char[] storePass, + private Pair<Key,char[]> recoverKey(String alias, char[] storePass, char[] keyPass) throws Exception { @@ -2510,7 +2740,7 @@ public final class KeyTool { key = keyStore.getKey(alias, keyPass); } - return new Object[] {key, keyPass}; + return Pair.of(key, keyPass); } /** @@ -2520,7 +2750,7 @@ public final class KeyTool { * recovered entry, and the 2nd element is the password used to * recover it (null if no password). */ - private Object[] recoverEntry(KeyStore ks, + private Pair<Entry,char[]> recoverEntry(KeyStore ks, String alias, char[] pstore, char[] pkey) throws Exception { @@ -2585,7 +2815,7 @@ public final class KeyTool { } } - return new Object[] {entry, pkey}; + return Pair.of(entry, pkey); } /** * Gets the requested finger print of the certificate. @@ -2651,20 +2881,18 @@ public final class KeyTool { Certificate tmpCert = replyCerts[0]; replyCerts[0] = replyCerts[i]; replyCerts[i] = tmpCert; - Principal issuer = ((X509Certificate)replyCerts[0]).getIssuerDN(); + + X509Certificate thisCert = (X509Certificate)replyCerts[0]; for (i=1; i < replyCerts.length-1; i++) { - // find a cert in the reply whose "subject" is the same as the - // given "issuer" + // find a cert in the reply who signs thisCert int j; for (j=i; j<replyCerts.length; j++) { - Principal subject; - subject = ((X509Certificate)replyCerts[j]).getSubjectDN(); - if (subject.equals(issuer)) { + if (signedBy(thisCert, (X509Certificate)replyCerts[j])) { tmpCert = replyCerts[i]; replyCerts[i] = replyCerts[j]; replyCerts[j] = tmpCert; - issuer = ((X509Certificate)replyCerts[i]).getIssuerDN(); + thisCert = (X509Certificate)replyCerts[i]; break; } } @@ -2674,18 +2902,6 @@ public final class KeyTool { } } - // now verify each cert in the ordered chain - for (i=0; i<replyCerts.length-1; i++) { - PublicKey pubKey = replyCerts[i+1].getPublicKey(); - try { - replyCerts[i].verify(pubKey); - } catch (Exception e) { - throw new Exception(rb.getString - ("Certificate chain in reply does not verify: ") + - e.getMessage()); - } - } - if (noprompt) { return replyCerts; } @@ -2817,9 +3033,8 @@ public final class KeyTool { private boolean buildChain(X509Certificate certToVerify, Vector<Certificate> chain, Hashtable<Principal, Vector<Certificate>> certs) { - Principal subject = certToVerify.getSubjectDN(); Principal issuer = certToVerify.getIssuerDN(); - if (subject.equals(issuer)) { + if (isSelfSigned(certToVerify)) { // reached self-signed root cert; // no verification needed because it's trusted. chain.addElement(certToVerify); @@ -2890,7 +3105,7 @@ public final class KeyTool { /** * Returns the keystore with the configured CA certificates. */ - private KeyStore getCacertsKeyStore() + public static KeyStore getCacertsKeyStore() throws Exception { String sep = File.separator; @@ -3026,6 +3241,443 @@ public final class KeyTool { return c.getTime(); } + /** + * Match a command (may be abbreviated) with a command set. + * @param s the command provided + * @param list the legal command set + * @return the position of a single match, or -1 if none matched + * @throws Exception if s is ambiguous + */ + private static int oneOf(String s, String... list) throws Exception { + int[] match = new int[list.length]; + int nmatch = 0; + for (int i = 0; i<list.length; i++) { + String one = list[i]; + if (one.toLowerCase().startsWith(s.toLowerCase())) { + match[nmatch++] = i; + } else { + StringBuffer sb = new StringBuffer(); + boolean first = true; + for (char c: one.toCharArray()) { + if (first) { + sb.append(c); + first = false; + } else { + if (!Character.isLowerCase(c)) { + sb.append(c); + } + } + } + if (sb.toString().equalsIgnoreCase(s)) { + match[nmatch++] = i; + } + } + } + if (nmatch == 0) return -1; + if (nmatch == 1) return match[0]; + StringBuffer sb = new StringBuffer(); + MessageFormat form = new MessageFormat(rb.getString + ("command {0} is ambiguous:")); + Object[] source = {s}; + sb.append(form.format(source) +"\n "); + for (int i=0; i<nmatch; i++) { + sb.append(" " + list[match[i]]); + } + throw new Exception(sb.toString()); + } + + /** + * Create a GeneralName object from known types + * @param t one of 5 known types + * @param v value + * @return which one + */ + private GeneralName createGeneralName(String t, String v) + throws Exception { + GeneralNameInterface gn; + int p = oneOf(t, "EMAIL", "URI", "DNS", "IP", "OID"); + if (p < 0) { + throw new Exception(rb.getString( + "Unrecognized GeneralName type: ") + t); + } + switch (p) { + case 0: gn = new RFC822Name(v); break; + case 1: gn = new URIName(v); break; + case 2: gn = new DNSName(v); break; + case 3: gn = new IPAddressName(v); break; + default: gn = new OIDName(v); break; //4 + } + return new GeneralName(gn); + } + + private static final String[] extSupported = { + "BasicConstraints", + "KeyUsage", + "ExtendedKeyUsage", + "SubjectAlternativeName", + "IssuerAlternativeName", + "SubjectInfoAccess", + "AuthorityInfoAccess", + }; + + private ObjectIdentifier findOidForExtName(String type) + throws Exception { + switch (oneOf(type, extSupported)) { + case 0: return PKIXExtensions.BasicConstraints_Id; + case 1: return PKIXExtensions.KeyUsage_Id; + case 2: return PKIXExtensions.ExtendedKeyUsage_Id; + case 3: return PKIXExtensions.SubjectAlternativeName_Id; + case 4: return PKIXExtensions.IssuerAlternativeName_Id; + case 5: return PKIXExtensions.SubjectInfoAccess_Id; + case 6: return PKIXExtensions.AuthInfoAccess_Id; + default: return new ObjectIdentifier(type); + } + } + + /** + * Create X509v3 extensions from a string representation. Note that the + * SubjectKeyIdentifierExtension will always be created non-critical besides + * the extension requested in the <code>extstr</code> argument. + * + * @param reqex the requested extensions, can be null, used for -gencert + * @param ext the original extensions, can be null, used for -selfcert + * @param extstrs -ext values, Read keytool doc + * @param pkey the public key for the certificate + * @param akey the public key for the authority (issuer) + * @return the created CertificateExtensions + */ + private CertificateExtensions createV3Extensions( + CertificateExtensions reqex, + CertificateExtensions ext, + List <String> extstrs, + PublicKey pkey, + PublicKey akey) throws Exception { + + if (ext != null && reqex != null) { + // This should not happen + throw new Exception("One of request and original should be null."); + } + if (ext == null) ext = new CertificateExtensions(); + try { + // name{:critical}{=value} + // Honoring requested extensions + if (reqex != null) { + for(String extstr: extstrs) { + if (extstr.toLowerCase().startsWith("honored=")) { + List<String> list = Arrays.asList( + extstr.toLowerCase().substring(8).split(",")); + // First check existence of "all" + if (list.contains("all")) { + ext = reqex; // we know ext was null + } + // one by one for others + for (String item: list) { + if (item.equals("all")) continue; + + // add or remove + boolean add = true; + // -1, unchanged, 0 crtical, 1 non-critical + int action = -1; + String type = null; + if (item.startsWith("-")) { + add = false; + type = item.substring(1); + } else { + int colonpos = item.indexOf(':'); + if (colonpos >= 0) { + type = item.substring(0, colonpos); + action = oneOf(item.substring(colonpos+1), + "critical", "non-critical"); + if (action == -1) { + throw new Exception(rb.getString + ("Illegal value: ") + item); + } + } + } + String n = reqex.getNameByOid(findOidForExtName(type)); + if (add) { + Extension e = (Extension)reqex.get(n); + if (!e.isCritical() && action == 0 + || e.isCritical() && action == 1) { + e = Extension.newExtension( + e.getExtensionId(), + !e.isCritical(), + e.getExtensionValue()); + ext.set(n, e); + } + } else { + ext.delete(n); + } + } + break; + } + } + } + for(String extstr: extstrs) { + String name, value; + boolean isCritical = false; + + int eqpos = extstr.indexOf('='); + if (eqpos >= 0) { + name = extstr.substring(0, eqpos); + value = extstr.substring(eqpos+1); + } else { + name = extstr; + value = null; + } + + int colonpos = name.indexOf(':'); + if (colonpos >= 0) { + if (name.substring(colonpos+1).equalsIgnoreCase("critical")) { + isCritical = true; + } + name = name.substring(0, colonpos); + } + + if (name.equalsIgnoreCase("honored")) { + continue; + } + int exttype = oneOf(name, extSupported); + switch (exttype) { + case 0: // BC + int pathLen = -1; + boolean isCA = false; + if (value == null) { + isCA = true; + } else { + try { // the abbr format + pathLen = Integer.parseInt(value); + isCA = true; + } catch (NumberFormatException ufe) { + // ca:true,pathlen:1 + for (String part: value.split(",")) { + String[] nv = part.split(":"); + if (nv.length != 2) { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } else { + if (nv[0].equalsIgnoreCase("ca")) { + isCA = Boolean.parseBoolean(nv[1]); + } else if (nv[0].equalsIgnoreCase("pathlen")) { + pathLen = Integer.parseInt(nv[1]); + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + } + } + } + } + ext.set(BasicConstraintsExtension.NAME, + new BasicConstraintsExtension(isCritical, isCA, + pathLen)); + break; + case 1: // KU + if(value != null) { + boolean[] ok = new boolean[9]; + for (String s: value.split(",")) { + int p = oneOf(s, + "digitalSignature", // (0), + "nonRepudiation", // (1) + "keyEncipherment", // (2), + "dataEncipherment", // (3), + "keyAgreement", // (4), + "keyCertSign", // (5), + "cRLSign", // (6), + "encipherOnly", // (7), + "decipherOnly", // (8) + "contentCommitment" // also (1) + ); + if (p < 0) { + throw new Exception(rb.getString("Unknown keyUsage type: ") + s); + } + if (p == 9) p = 1; + ok[p] = true; + } + KeyUsageExtension kue = new KeyUsageExtension(ok); + // The above KeyUsageExtension constructor does not + // allow isCritical value, so... + ext.set(KeyUsageExtension.NAME, Extension.newExtension( + kue.getExtensionId(), + isCritical, + kue.getExtensionValue())); + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + break; + case 2: // EKU + if(value != null) { + Vector <ObjectIdentifier> v = + new Vector <ObjectIdentifier>(); + for (String s: value.split(",")) { + int p = oneOf(s, + "anyExtendedKeyUsage", + "serverAuth", //1 + "clientAuth", //2 + "codeSigning", //3 + "emailProtection", //4 + "", //5 + "", //6 + "", //7 + "timeStamping", //8 + "OCSPSigning" //9 + ); + if (p < 0) { + try { + v.add(new ObjectIdentifier(s)); + } catch (Exception e) { + throw new Exception(rb.getString( + "Unknown extendedkeyUsage type: ") + s); + } + } else if (p == 0) { + v.add(new ObjectIdentifier("2.5.29.37.0")); + } else { + v.add(new ObjectIdentifier("1.3.6.1.5.5.7.3." + p)); + } + } + ext.set(ExtendedKeyUsageExtension.NAME, + new ExtendedKeyUsageExtension(isCritical, v)); + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + break; + case 3: // SAN + case 4: // IAN + if(value != null) { + String[] ps = value.split(","); + GeneralNames gnames = new GeneralNames(); + for(String item: ps) { + colonpos = item.indexOf(':'); + if (colonpos < 0) { + throw new Exception("Illegal item " + item + " in " + extstr); + } + String t = item.substring(0, colonpos); + String v = item.substring(colonpos+1); + gnames.add(createGeneralName(t, v)); + } + if (exttype == 3) { + ext.set(SubjectAlternativeNameExtension.NAME, + new SubjectAlternativeNameExtension( + isCritical, gnames)); + } else { + ext.set(IssuerAlternativeNameExtension.NAME, + new IssuerAlternativeNameExtension( + isCritical, gnames)); + } + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + break; + case 5: // SIA, always non-critical + case 6: // AIA, always non-critical + if (isCritical) { + throw new Exception(rb.getString( + "This extension cannot be marked as critical. ") + extstr); + } + if(value != null) { + List<AccessDescription> accessDescriptions = + new ArrayList<AccessDescription>(); + String[] ps = value.split(","); + for(String item: ps) { + colonpos = item.indexOf(':'); + int colonpos2 = item.indexOf(':', colonpos+1); + if (colonpos < 0 || colonpos2 < 0) { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + String m = item.substring(0, colonpos); + String t = item.substring(colonpos+1, colonpos2); + String v = item.substring(colonpos2+1); + int p = oneOf(m, + "", + "ocsp", //1 + "caIssuers", //2 + "timeStamping", //3 + "", + "caRepository" //5 + ); + ObjectIdentifier oid; + if (p < 0) { + try { + oid = new ObjectIdentifier(m); + } catch (Exception e) { + throw new Exception(rb.getString( + "Unknown AccessDescription type: ") + m); + } + } else { + oid = new ObjectIdentifier("1.3.6.1.5.5.7.48." + p); + } + accessDescriptions.add(new AccessDescription( + oid, createGeneralName(t, v))); + } + if (exttype == 5) { + ext.set(SubjectInfoAccessExtension.NAME, + new SubjectInfoAccessExtension(accessDescriptions)); + } else { + ext.set(AuthorityInfoAccessExtension.NAME, + new AuthorityInfoAccessExtension(accessDescriptions)); + } + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + break; + case -1: + ObjectIdentifier oid = new ObjectIdentifier(name); + byte[] data = null; + if (value != null) { + data = new byte[value.length() / 2 + 1]; + int pos = 0; + for (char c: value.toCharArray()) { + int hex; + if (c >= '0' && c <= '9') { + hex = c - '0' ; + } else if (c >= 'A' && c <= 'F') { + hex = c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + hex = c - 'a' + 10; + } else { + continue; + } + if (pos % 2 == 0) { + data[pos/2] = (byte)(hex << 4); + } else { + data[pos/2] += hex; + } + pos++; + } + if (pos % 2 != 0) { + throw new Exception(rb.getString( + "Odd number of hex digits found: ") + extstr); + } + data = Arrays.copyOf(data, pos/2); + } else { + data = new byte[0]; + } + ext.set(oid.toString(), new Extension(oid, isCritical, + new DerValue(DerValue.tag_OctetString, data) + .toByteArray())); + break; + } + } + // always non-critical + ext.set(SubjectKeyIdentifierExtension.NAME, + new SubjectKeyIdentifierExtension( + new KeyIdentifier(pkey).getIdentifier())); + if (akey != null && !pkey.equals(akey)) { + ext.set(AuthorityKeyIdentifierExtension.NAME, + new AuthorityKeyIdentifierExtension( + new KeyIdentifier(akey), null, null)); + } + } catch(IOException e) { + throw new RuntimeException(e); + } + return ext; + } + /** * Prints the usage of this tool. */ @@ -3098,6 +3750,32 @@ public final class KeyTool { ("\t [-sigalg <sigalg>] [-dname <dname>]")); System.err.println(rb.getString ("\t [-startdate <startdate>]")); + System.err.println(rb.getString + ("\t [-ext <key>[:critical][=<value>]]...")); + System.err.println(rb.getString + ("\t [-validity <valDays>] [-keypass <keypass>]")); + System.err.println(rb.getString + ("\t [-keystore <keystore>] [-storepass <storepass>]")); + System.err.println(rb.getString + ("\t [-storetype <storetype>] [-providername <name>]")); + System.err.println(rb.getString + ("\t [-providerclass <provider_class_name> [-providerarg <arg>]] ...")); + System.err.println(rb.getString + ("\t [-providerpath <pathlist>]")); + System.err.println(); + + System.err.println(rb.getString + ("-gencert [-v] [-rfc] [-protected]")); + System.err.println(rb.getString + ("\t [-infile <infile>] [-outfile <outfile>]")); + System.err.println(rb.getString + ("\t [-alias <alias>]")); + System.err.println(rb.getString + ("\t [-sigalg <sigalg>]")); + System.err.println(rb.getString + ("\t [-startdate <startdate>]")); + System.err.println(rb.getString + ("\t [-ext <key>[:critical][=<value>]]...")); System.err.println(rb.getString ("\t [-validity <valDays>] [-keypass <keypass>]")); System.err.println(rb.getString @@ -3201,6 +3879,10 @@ public final class KeyTool { ("-printcert [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]")); System.err.println(); + System.err.println(rb.getString + ("-printcertreq [-v] [-file <cert_file>]")); + System.err.println(); + System.err.println(rb.getString ("-storepasswd [-v] [-new <new_storepass>]")); System.err.println(rb.getString @@ -3211,12 +3893,6 @@ public final class KeyTool { ("\t [-providerclass <provider_class_name> [-providerarg <arg>]] ...")); System.err.println(rb.getString ("\t [-providerpath <pathlist>]")); - - if (debug) { - throw new RuntimeException("NO ERROR, SORRY"); - } else { - System.exit(1); - } } private void tinyHelp() { @@ -3270,4 +3946,8 @@ class Pair<A, B> { else if (snd == null) return fst.hashCode() + 2; else return fst.hashCode() * 17 + snd.hashCode(); } + + public static <A,B> Pair<A,B> of(A a, B b) { + return new Pair<A,B>(a,b); + } } diff --git a/jdk/src/share/classes/sun/security/util/Cache.java b/jdk/src/share/classes/sun/security/util/Cache.java index e6eddb6f07d..35d648a5a7f 100644 --- a/jdk/src/share/classes/sun/security/util/Cache.java +++ b/jdk/src/share/classes/sun/security/util/Cache.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,6 +100,21 @@ public abstract class Cache { */ public abstract void remove(Object key); + /** + * Set the maximum size. + */ + public abstract void setCapacity(int size); + + /** + * Set the timeout(in seconds). + */ + public abstract void setTimeout(int timeout); + + /** + * accept a visitor + */ + public abstract void accept(CacheVisitor visitor); + /** * Return a new memory cache with the specified maximum size, unlimited * lifetime for entries, with the values held by SoftReferences. @@ -178,6 +193,10 @@ public abstract class Cache { } } + public interface CacheVisitor { + public void visit(Map<Object, Object> map); + } + } class NullCache extends Cache { @@ -208,6 +227,18 @@ class NullCache extends Cache { // empty } + public void setCapacity(int size) { + // empty + } + + public void setTimeout(int timeout) { + // empty + } + + public void accept(CacheVisitor visitor) { + // empty + } + } class MemoryCache extends Cache { @@ -218,8 +249,8 @@ class MemoryCache extends Cache { private final static boolean DEBUG = false; private final Map<Object, CacheEntry> cacheMap; - private final int maxSize; - private final int lifetime; + private int maxSize; + private long lifetime; private final ReferenceQueue queue; public MemoryCache(boolean soft, int maxSize) { @@ -328,7 +359,7 @@ class MemoryCache extends Cache { oldEntry.invalidate(); return; } - if (cacheMap.size() > maxSize) { + if (maxSize > 0 && cacheMap.size() > maxSize) { expungeExpiredEntries(); if (cacheMap.size() > maxSize) { // still too large? Iterator<CacheEntry> t = cacheMap.values().iterator(); @@ -368,6 +399,55 @@ class MemoryCache extends Cache { } } + public synchronized void setCapacity(int size) { + expungeExpiredEntries(); + if (size > 0 && cacheMap.size() > size) { + Iterator<CacheEntry> t = cacheMap.values().iterator(); + for (int i = cacheMap.size() - size; i > 0; i--) { + CacheEntry lruEntry = t.next(); + if (DEBUG) { + System.out.println("** capacity reset removal " + + lruEntry.getKey() + " | " + lruEntry.getValue()); + } + t.remove(); + lruEntry.invalidate(); + } + } + + maxSize = size > 0 ? size : 0; + + if (DEBUG) { + System.out.println("** capacity reset to " + size); + } + } + + public synchronized void setTimeout(int timeout) { + emptyQueue(); + lifetime = timeout > 0 ? timeout * 1000L : 0L; + + if (DEBUG) { + System.out.println("** lifetime reset to " + timeout); + } + } + + // it is a heavyweight method. + public synchronized void accept(CacheVisitor visitor) { + expungeExpiredEntries(); + Map<Object, Object> cached = getCachedEntries(); + + visitor.visit(cached); + } + + private Map<Object, Object> getCachedEntries() { + Map<Object,Object> kvmap = new HashMap<Object,Object>(cacheMap.size()); + + for (CacheEntry entry : cacheMap.values()) { + kvmap.put(entry.getKey(), entry.getValue()); + } + + return kvmap; + } + protected CacheEntry newEntry(Object key, Object value, long expirationTime, ReferenceQueue queue) { if (queue != null) { diff --git a/jdk/src/share/classes/sun/security/util/DerValue.java b/jdk/src/share/classes/sun/security/util/DerValue.java index 74e59f609b9..114788beb26 100644 --- a/jdk/src/share/classes/sun/security/util/DerValue.java +++ b/jdk/src/share/classes/sun/security/util/DerValue.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ public class DerValue { protected DerInputBuffer buffer; /** - * The DER-encoded data of the value. + * The DER-encoded data of the value, never null */ public final DerInputStream data; @@ -378,8 +378,6 @@ public class DerValue { ("Indefinite length encoding not supported"); length = DerInputStream.getLength(in); } - if (length == 0) - return null; if (fullyBuffered && in.available() != length) throw new IOException("extra data given to DerValue constructor"); @@ -477,6 +475,11 @@ public class DerValue { "DerValue.getOctetString, not an Octet String: " + tag); } bytes = new byte[length]; + // Note: do not tempt to call buffer.read(bytes) at all. There's a + // known bug that it returns -1 instead of 0. + if (length == 0) { + return bytes; + } if (buffer.read(bytes) != length) throw new IOException("short read on DerValue buffer"); if (isConstructed()) { diff --git a/jdk/src/share/classes/sun/security/util/ManifestEntryVerifier.java b/jdk/src/share/classes/sun/security/util/ManifestEntryVerifier.java index c528d95c8b1..b713f16e768 100644 --- a/jdk/src/share/classes/sun/security/util/ManifestEntryVerifier.java +++ b/jdk/src/share/classes/sun/security/util/ManifestEntryVerifier.java @@ -44,8 +44,6 @@ public class ManifestEntryVerifier { private static final Debug debug = Debug.getInstance("jar"); - private static final Provider digestProvider = Providers.getSunProvider(); - /** the created digest objects */ HashMap<String, MessageDigest> createdDigests; @@ -127,7 +125,7 @@ public class ManifestEntryVerifier { try { digest = MessageDigest.getInstance - (algorithm, digestProvider); + (algorithm, Providers.getSunProvider()); createdDigests.put(algorithm, digest); } catch (NoSuchAlgorithmException nsae) { // ignore diff --git a/jdk/src/share/classes/sun/security/util/Resources.java b/jdk/src/share/classes/sun/security/util/Resources.java index e89d6cdfc99..c8c5e386de1 100644 --- a/jdk/src/share/classes/sun/security/util/Resources.java +++ b/jdk/src/share/classes/sun/security/util/Resources.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ public class Resources extends java.util.ListResourceBundle { // keytool {"keytool error: ", "keytool error: "}, {"Illegal option: ", "Illegal option: "}, + {"Illegal value: ", "Illegal value: "}, {"Try keytool -help","Try keytool -help"}, {"Command option <flag> needs an argument.", "Command option {0} needs an argument."}, {"Warning: Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified <command> value.", @@ -281,6 +282,20 @@ public class Resources extends java.util.ListResourceBundle { {"keytool usage:\n", "keytool usage:\n"}, {"Extensions: ", "Extensions: "}, + {"(Empty value)", "(Empty value)"}, + {"Extension Request:", "Extension Request:"}, + {"PKCS #10 Certificate Request (Version 1.0)\n" + + "Subject: %s\nPublic Key: %s format %s key\n", + "PKCS #10 Certificate Request (Version 1.0)\n" + + "Subject: %s\nPublic Key: %s format %s key\n"}, + {"Unknown keyUsage type: ", "Unknown keyUsage type: "}, + {"Unknown extendedkeyUsage type: ", "Unknown extendedkeyUsage type: "}, + {"Unknown AccessDescription type: ", "Unknown AccessDescription type: "}, + {"Unrecognized GeneralName type: ", "Unrecognized GeneralName type: "}, + {"This extension cannot be marked as critical. ", + "This extension cannot be marked as critical. "}, + {"Odd number of hex digits found: ", "Odd number of hex digits found: "}, + {"command {0} is ambiguous:", "command {0} is ambiguous:"}, {"-certreq [-v] [-protected]", "-certreq [-v] [-protected]"}, @@ -322,6 +337,14 @@ public class Resources extends java.util.ListResourceBundle { {"\t [-validity <valDays>] [-keypass <keypass>]", "\t [-validity <valDays>] [-keypass <keypass>]"}, /** rest is same as -certreq starting from -keystore **/ + {"-gencert [-v] [-rfc] [-protected]", + "-gencert [-v] [-rfc] [-protected]"}, + {"\t [-infile <infile>] [-outfile <outfile>]", + "\t [-infile <infile>] [-outfile <outfile>]"}, + {"\t [-sigalg <sigalg>]", + "\t [-sigalg <sigalg>]"}, + {"\t [-ext <key>[:critical][=<value>]]...", + "\t [-ext <key>[:critical][=<value>]]..."}, {"-genseckey [-v] [-protected]", "-genseckey [-v] [-protected]"}, @@ -388,6 +411,8 @@ public class Resources extends java.util.ListResourceBundle { {"-printcert [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]", "-printcert [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]"}, + {"-printcertreq [-v] [-file <cert_file>]", + "-printcertreq [-v] [-file <cert_file>]"}, {"No certificate from the SSL server", "No certificate from the SSL server"}, diff --git a/jdk/src/share/classes/sun/security/util/SecurityConstants.java b/jdk/src/share/classes/sun/security/util/SecurityConstants.java index 95cd1f57070..43e2cd3d792 100644 --- a/jdk/src/share/classes/sun/security/util/SecurityConstants.java +++ b/jdk/src/share/classes/sun/security/util/SecurityConstants.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ public final class SecurityConstants { public static final String FILE_EXECUTE_ACTION = "execute"; public static final String FILE_READ_ACTION = "read"; public static final String FILE_WRITE_ACTION = "write"; + public static final String FILE_READLINK_ACTION = "readlink"; public static final String SOCKET_RESOLVE_ACTION = "resolve"; public static final String SOCKET_CONNECT_ACTION = "connect"; diff --git a/jdk/src/share/classes/sun/security/x509/AccessDescription.java b/jdk/src/share/classes/sun/security/x509/AccessDescription.java index a9ccbb86824..1544ea953be 100644 --- a/jdk/src/share/classes/sun/security/x509/AccessDescription.java +++ b/jdk/src/share/classes/sun/security/x509/AccessDescription.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,17 @@ public final class AccessDescription { public static final ObjectIdentifier Ad_CAISSUERS_Id = ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 2}); + public static final ObjectIdentifier Ad_TIMESTAMPING_Id = + ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 3}); + + public static final ObjectIdentifier Ad_CAREPOSITORY_Id = + ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 5}); + + public AccessDescription(ObjectIdentifier accessMethod, GeneralName accessLocation) { + this.accessMethod = accessMethod; + this.accessLocation = accessLocation; + } + public AccessDescription(DerValue derValue) throws IOException { DerInputStream derIn = derValue.getData(); accessMethod = derIn.getOID(); @@ -90,7 +101,19 @@ public final class AccessDescription { } public String toString() { - return ("accessMethod: " + accessMethod.toString() + - "\n accessLocation: " + accessLocation.toString()); + String method = null; + if (accessMethod.equals(Ad_CAISSUERS_Id)) { + method = "caIssuers"; + } else if (accessMethod.equals(Ad_CAREPOSITORY_Id)) { + method = "caRepository"; + } else if (accessMethod.equals(Ad_TIMESTAMPING_Id)) { + method = "timeStamping"; + } else if (accessMethod.equals(Ad_OCSP_Id)) { + method = "ocsp"; + } else { + method = accessMethod.toString(); + } + return ("accessMethod: " + method + + "\n accessLocation: " + accessLocation.toString() + "\n"); } } diff --git a/jdk/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java b/jdk/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java index 5b0b287fa24..9e332b10c55 100644 --- a/jdk/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java +++ b/jdk/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,8 +43,9 @@ import sun.security.util.DerValue; * certificate that identifies the specific OCSP Responder to use when * performing on-line validation of that certificate. * <p> - * This extension is defined in - * <a href="http://www.ietf.org/rfc/rfc3280.txt">Internet X.509 PKI Certificate and Certificate Revocation List (CRL) Profile</a>. The profile permits + * This extension is defined in <a href="http://www.ietf.org/rfc/rfc3280.txt"> + * Internet X.509 PKI Certificate and Certificate Revocation List + * (CRL) Profile</a>. The profile permits * the extension to be included in end-entity or CA certificates, * and it must be marked as non-critical. Its ASN.1 definition is as follows: * <pre> diff --git a/jdk/src/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java b/jdk/src/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java index f63dca90a79..b14c8436292 100644 --- a/jdk/src/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java +++ b/jdk/src/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -198,7 +198,7 @@ implements CertAttrSet<String> { public String toString() { String s = super.toString() + "AuthorityKeyIdentifier [\n"; if (id != null) { - s += id.toString() + "\n"; + s += id.toString(); // id already has a newline } if (names != null) { s += names.toString() + "\n"; diff --git a/jdk/src/share/classes/sun/security/x509/BasicConstraintsExtension.java b/jdk/src/share/classes/sun/security/x509/BasicConstraintsExtension.java index 26344ee27f1..c38bb002b08 100644 --- a/jdk/src/share/classes/sun/security/x509/BasicConstraintsExtension.java +++ b/jdk/src/share/classes/sun/security/x509/BasicConstraintsExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,18 +70,15 @@ implements CertAttrSet<String> { // Encode this extension value private void encodeThis() throws IOException { - if (ca == false && pathLen < 0) { - this.extensionValue = null; - return; - } DerOutputStream out = new DerOutputStream(); DerOutputStream tmp = new DerOutputStream(); if (ca) { tmp.putBoolean(ca); - } - if (pathLen >= 0) { - tmp.putInteger(pathLen); + // Only encode pathLen when ca == true + if (pathLen >= 0) { + tmp.putInteger(pathLen); + } } out.write(DerValue.tag_Sequence, tmp); this.extensionValue = out.toByteArray(); @@ -134,7 +131,7 @@ implements CertAttrSet<String> { throw new IOException("Invalid encoding of BasicConstraints"); } - if (val.data == null) { + if (val.data == null || val.data.available() == 0) { // non-CA cert ("cA" field is FALSE by default), return -1 return; } diff --git a/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java b/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java index 0e0800910ea..2cf34c871ec 100644 --- a/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java +++ b/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,8 +265,8 @@ public final class CertAndKeyGen { // Add all mandatory attributes info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); - info.set(X509CertInfo.SERIAL_NUMBER, - new CertificateSerialNumber((int)(firstDate.getTime()/1000))); + info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( + new java.util.Random().nextInt() & 0x7fffffff)); AlgorithmId algID = issuer.getAlgorithmId(); info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algID)); @@ -276,12 +276,6 @@ public final class CertAndKeyGen { info.set(X509CertInfo.ISSUER, new CertificateIssuerName(issuer.getSigner())); - CertificateExtensions ext = new CertificateExtensions(); - ext.set(SubjectKeyIdentifierExtension.NAME, - new SubjectKeyIdentifierExtension( - new KeyIdentifier(publicKey).getIdentifier())); - info.set(X509CertInfo.EXTENSIONS, ext); - cert = new X509CertImpl(info); cert.sign(privateKey, this.sigAlg); diff --git a/jdk/src/share/classes/sun/security/x509/CertificateExtensions.java b/jdk/src/share/classes/sun/security/x509/CertificateExtensions.java index 7049d01e974..cd32e748c74 100644 --- a/jdk/src/share/classes/sun/security/x509/CertificateExtensions.java +++ b/jdk/src/share/classes/sun/security/x509/CertificateExtensions.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -231,6 +231,15 @@ public class CertificateExtensions implements CertAttrSet<Extension> { map.remove(name); } + public String getNameByOid(ObjectIdentifier oid) throws IOException { + for (String name: map.keySet()) { + if (map.get(name).getExtensionId().equals(oid)) { + return name; + } + } + return null; + } + /** * Return an enumeration of names of attributes existing within this * attribute. diff --git a/jdk/src/share/classes/sun/security/x509/IssuerAlternativeNameExtension.java b/jdk/src/share/classes/sun/security/x509/IssuerAlternativeNameExtension.java index aad153b646a..73f3ecd5c93 100644 --- a/jdk/src/share/classes/sun/security/x509/IssuerAlternativeNameExtension.java +++ b/jdk/src/share/classes/sun/security/x509/IssuerAlternativeNameExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,6 +89,22 @@ extends Extension implements CertAttrSet<String> { encodeThis(); } + /** + * Create a IssuerAlternativeNameExtension with the passed criticality + * and GeneralNames. + * + * @param critical true if the extension is to be treated as critical. + * @param names the GeneralNames for the issuer. + * @exception IOException on error. + */ + public IssuerAlternativeNameExtension(Boolean critical, GeneralNames names) + throws IOException { + this.names = names; + this.extensionId = PKIXExtensions.IssuerAlternativeName_Id; + this.critical = critical.booleanValue(); + encodeThis(); + } + /** * Create a default IssuerAlternativeNameExtension. */ diff --git a/jdk/src/share/classes/sun/security/x509/OCSPNoCheckExtension.java b/jdk/src/share/classes/sun/security/x509/OCSPNoCheckExtension.java new file mode 100644 index 00000000000..b721439d5c9 --- /dev/null +++ b/jdk/src/share/classes/sun/security/x509/OCSPNoCheckExtension.java @@ -0,0 +1,132 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.security.x509; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Enumeration; + +import sun.security.util.*; + +/** + * Represent the OCSP NoCheck Extension from RFC2560. + * <p> + * A CA may specify that an OCSP client can trust a responder for the + * lifetime of the responder's certificate. The CA does so by including + * the extension id-pkix-ocsp-nocheck. This SHOULD be a non-critical + * extension. The value of the extension should be NULL. CAs issuing + * such a certificate should realized that a compromise of the + * responder's key, is as serious as the compromise of a CA key used to + * sign CRLs, at least for the validity period of this certificate. CA's + * may choose to issue this type of certificate with a very short + * lifetime and renew it frequently. + * <pre> + * id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 } + * </pre> + * + * @author Xuelei Fan + * @see Extension + * @see CertAttrSet + */ +public class OCSPNoCheckExtension extends Extension + implements CertAttrSet<String> { + + /** + * Identifier for this attribute, to be used with the + * get, set, delete methods of Certificate, x509 type. + */ + public static final String IDENT = + "x509.info.extensions.OCSPNoCheck"; + /** + * Attribute names. + */ + public static final String NAME = "OCSPNoCheck"; + + /** + * Create a OCSPNoCheckExtension + */ + public OCSPNoCheckExtension() throws IOException { + this.extensionId = PKIXExtensions.OCSPNoCheck_Id; + this.critical = false; + this.extensionValue = new byte[0]; + } + + /** + * Create the extension from the passed DER encoded value. + * + * @param critical true if the extension is to be treated as critical. + * @param value an array of DER encoded bytes of the actual value. + * @exception IOException on error. + */ + public OCSPNoCheckExtension(Boolean critical, Object value) + throws IOException { + + this.extensionId = PKIXExtensions.OCSPNoCheck_Id; + this.critical = critical.booleanValue(); + + // the value should be null, just ignore it here. + this.extensionValue = new byte[0]; + } + + /** + * Set the attribute value. + */ + public void set(String name, Object obj) throws IOException { + throw new IOException("No attribute is allowed by " + + "CertAttrSet:OCSPNoCheckExtension."); + } + + /** + * Get the attribute value. + */ + public Object get(String name) throws IOException { + throw new IOException("No attribute is allowed by " + + "CertAttrSet:OCSPNoCheckExtension."); + } + + /** + * Delete the attribute value. + */ + public void delete(String name) throws IOException { + throw new IOException("No attribute is allowed by " + + "CertAttrSet:OCSPNoCheckExtension."); + } + + /** + * Return an enumeration of names of attributes existing within this + * attribute. + */ + public Enumeration<String> getElements() { + return (new AttributeNameEnumeration()).elements(); + } + + /** + * Return the name of this attribute. + */ + public String getName() { + return NAME; + } +} diff --git a/jdk/src/share/classes/sun/security/x509/OIDMap.java b/jdk/src/share/classes/sun/security/x509/OIDMap.java index ddbb1d6f60a..f52fab3eeef 100644 --- a/jdk/src/share/classes/sun/security/x509/OIDMap.java +++ b/jdk/src/share/classes/sun/security/x509/OIDMap.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,8 @@ public class OIDMap { private static final String CERT_ISSUER = ROOT + "." + CertificateIssuerExtension.NAME; + private static final String SUBJECT_INFO_ACCESS = ROOT + "." + + SubjectInfoAccessExtension.NAME; private static final String AUTH_INFO_ACCESS = ROOT + "." + AuthorityInfoAccessExtension.NAME; private static final String ISSUING_DIST_POINT = ROOT + "." + @@ -98,6 +100,8 @@ public class OIDMap { DeltaCRLIndicatorExtension.NAME; private static final String FRESHEST_CRL = ROOT + "." + FreshestCRLExtension.NAME; + private static final String OCSPNOCHECK = ROOT + "." + + OCSPNoCheckExtension.NAME; private static final int NetscapeCertType_data[] = { 2, 16, 840, 1, 113730, 1, 1 }; @@ -148,6 +152,8 @@ public class OIDMap { "sun.security.x509.CRLDistributionPointsExtension"); addInternal(CERT_ISSUER, PKIXExtensions.CertificateIssuer_Id, "sun.security.x509.CertificateIssuerExtension"); + addInternal(SUBJECT_INFO_ACCESS, PKIXExtensions.SubjectInfoAccess_Id, + "sun.security.x509.SubjectInfoAccessExtension"); addInternal(AUTH_INFO_ACCESS, PKIXExtensions.AuthInfoAccess_Id, "sun.security.x509.AuthorityInfoAccessExtension"); addInternal(ISSUING_DIST_POINT, @@ -157,6 +163,8 @@ public class OIDMap { "sun.security.x509.DeltaCRLIndicatorExtension"); addInternal(FRESHEST_CRL, PKIXExtensions.FreshestCRL_Id, "sun.security.x509.FreshestCRLExtension"); + addInternal(OCSPNOCHECK, PKIXExtensions.OCSPNoCheck_Id, + "sun.security.x509.OCSPNoCheckExtension"); } /** diff --git a/jdk/src/share/classes/sun/security/x509/PKIXExtensions.java b/jdk/src/share/classes/sun/security/x509/PKIXExtensions.java index 78177944c08..f140c548551 100644 --- a/jdk/src/share/classes/sun/security/x509/PKIXExtensions.java +++ b/jdk/src/share/classes/sun/security/x509/PKIXExtensions.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,6 +74,8 @@ public class PKIXExtensions { private static final int AuthInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 1}; private static final int SubjectInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 11}; private static final int FreshestCRL_data [] = { 2, 5, 29, 46 }; + private static final int OCSPNoCheck_data [] = { 1, 3, 6, 1, 5, 5, 7, + 48, 1, 5}; /** * Identifies the particular public key used to sign the certificate. @@ -216,6 +218,12 @@ public class PKIXExtensions { */ public static final ObjectIdentifier FreshestCRL_Id; + /** + * Identifies the OCSP client can trust the responder for the + * lifetime of the responder's certificate. + */ + public static final ObjectIdentifier OCSPNoCheck_Id; + static { AuthorityKey_Id = ObjectIdentifier.newInternal(AuthorityKey_data); SubjectKey_Id = ObjectIdentifier.newInternal(SubjectKey_data); @@ -257,5 +265,6 @@ public class PKIXExtensions { SubjectInfoAccess_Id = ObjectIdentifier.newInternal(SubjectInfoAccess_data); FreshestCRL_Id = ObjectIdentifier.newInternal(FreshestCRL_data); + OCSPNoCheck_Id = ObjectIdentifier.newInternal(OCSPNoCheck_data); } } diff --git a/jdk/src/share/classes/sun/security/x509/SubjectInfoAccessExtension.java b/jdk/src/share/classes/sun/security/x509/SubjectInfoAccessExtension.java new file mode 100644 index 00000000000..449f45eb595 --- /dev/null +++ b/jdk/src/share/classes/sun/security/x509/SubjectInfoAccessExtension.java @@ -0,0 +1,244 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.security.x509; + +import java.io.IOException; +import java.io.OutputStream; + +import java.util.*; + +import sun.security.util.DerOutputStream; +import sun.security.util.DerValue; + +/** + * The Subject Information Access Extension (OID = 1.3.6.1.5.5.7.1.11). + * <p> + * The subject information access extension indicates how to access + * information and services for the subject of the certificate in which + * the extension appears. When the subject is a CA, information and + * services may include certificate validation services and CA policy + * data. When the subject is an end entity, the information describes + * the type of services offered and how to access them. In this case, + * the contents of this extension are defined in the protocol + * specifications for the supported services. This extension may be + * included in end entity or CA certificates. Conforming CAs MUST mark + * this extension as non-critical. + * <p> + * This extension is defined in <a href="http://www.ietf.org/rfc/rfc3280.txt"> + * Internet X.509 PKI Certificate and Certificate Revocation List + * (CRL) Profile</a>. The profile permits + * the extension to be included in end-entity or CA certificates, + * and it must be marked as non-critical. Its ASN.1 definition is as follows: + * <pre> + * id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 } + * + * SubjectInfoAccessSyntax ::= + * SEQUENCE SIZE (1..MAX) OF AccessDescription + * + * AccessDescription ::= SEQUENCE { + * accessMethod OBJECT IDENTIFIER, + * accessLocation GeneralName } + * </pre> + * <p> + * @see Extension + * @see CertAttrSet + */ + +public class SubjectInfoAccessExtension extends Extension + implements CertAttrSet<String> { + + /** + * Identifier for this attribute, to be used with the + * get, set, delete methods of Certificate, x509 type. + */ + public static final String IDENT = + "x509.info.extensions.SubjectInfoAccess"; + + /** + * Attribute name. + */ + public static final String NAME = "SubjectInfoAccess"; + public static final String DESCRIPTIONS = "descriptions"; + + /** + * The List of AccessDescription objects. + */ + private List<AccessDescription> accessDescriptions; + + /** + * Create an SubjectInfoAccessExtension from a List of + * AccessDescription; the criticality is set to false. + * + * @param accessDescriptions the List of AccessDescription + * @throws IOException on error + */ + public SubjectInfoAccessExtension( + List<AccessDescription> accessDescriptions) throws IOException { + this.extensionId = PKIXExtensions.SubjectInfoAccess_Id; + this.critical = false; + this.accessDescriptions = accessDescriptions; + encodeThis(); + } + + /** + * Create the extension from the passed DER encoded value of the same. + * + * @param critical true if the extension is to be treated as critical. + * @param value Array of DER encoded bytes of the actual value. + * @exception IOException on error. + */ + public SubjectInfoAccessExtension(Boolean critical, Object value) + throws IOException { + this.extensionId = PKIXExtensions.SubjectInfoAccess_Id; + this.critical = critical.booleanValue(); + + if (!(value instanceof byte[])) { + throw new IOException("Illegal argument type"); + } + + extensionValue = (byte[])value; + DerValue val = new DerValue(extensionValue); + if (val.tag != DerValue.tag_Sequence) { + throw new IOException("Invalid encoding for " + + "SubjectInfoAccessExtension."); + } + accessDescriptions = new ArrayList<AccessDescription>(); + while (val.data.available() != 0) { + DerValue seq = val.data.getDerValue(); + AccessDescription accessDescription = new AccessDescription(seq); + accessDescriptions.add(accessDescription); + } + } + + /** + * Return the list of AccessDescription objects. + */ + public List<AccessDescription> getAccessDescriptions() { + return accessDescriptions; + } + + /** + * Return the name of this attribute. + */ + public String getName() { + return NAME; + } + + /** + * Write the extension to the DerOutputStream. + * + * @param out the DerOutputStream to write the extension to. + * @exception IOException on encoding errors. + */ + public void encode(OutputStream out) throws IOException { + DerOutputStream tmp = new DerOutputStream(); + if (this.extensionValue == null) { + this.extensionId = PKIXExtensions.SubjectInfoAccess_Id; + this.critical = false; + encodeThis(); + } + super.encode(tmp); + out.write(tmp.toByteArray()); + } + + /** + * Set the attribute value. + */ + public void set(String name, Object obj) throws IOException { + if (name.equalsIgnoreCase(DESCRIPTIONS)) { + if (!(obj instanceof List)) { + throw new IOException("Attribute value should be of type List."); + } + accessDescriptions = (List<AccessDescription>)obj; + } else { + throw new IOException("Attribute name [" + name + + "] not recognized by " + + "CertAttrSet:SubjectInfoAccessExtension."); + } + encodeThis(); + } + + /** + * Get the attribute value. + */ + public Object get(String name) throws IOException { + if (name.equalsIgnoreCase(DESCRIPTIONS)) { + return accessDescriptions; + } else { + throw new IOException("Attribute name [" + name + + "] not recognized by " + + "CertAttrSet:SubjectInfoAccessExtension."); + } + } + + /** + * Delete the attribute value. + */ + public void delete(String name) throws IOException { + if (name.equalsIgnoreCase(DESCRIPTIONS)) { + accessDescriptions = new ArrayList<AccessDescription>(); + } else { + throw new IOException("Attribute name [" + name + + "] not recognized by " + + "CertAttrSet:SubjectInfoAccessExtension."); + } + encodeThis(); + } + + /** + * Return an enumeration of names of attributes existing within this + * attribute. + */ + public Enumeration<String> getElements() { + AttributeNameEnumeration elements = new AttributeNameEnumeration(); + elements.addElement(DESCRIPTIONS); + return elements.elements(); + } + + // Encode this extension value + private void encodeThis() throws IOException { + if (accessDescriptions.isEmpty()) { + this.extensionValue = null; + } else { + DerOutputStream ads = new DerOutputStream(); + for (AccessDescription accessDescription : accessDescriptions) { + accessDescription.encode(ads); + } + DerOutputStream seq = new DerOutputStream(); + seq.write(DerValue.tag_Sequence, ads); + this.extensionValue = seq.toByteArray(); + } + } + + /** + * Return the extension as user readable string. + */ + public String toString() { + return super.toString() + "SubjectInfoAccess [\n " + + accessDescriptions + "\n]\n"; + } + +} diff --git a/jdk/src/share/classes/sun/swing/FilePane.java b/jdk/src/share/classes/sun/swing/FilePane.java index de5ad7c4831..71112b319d8 100644 --- a/jdk/src/share/classes/sun/swing/FilePane.java +++ b/jdk/src/share/classes/sun/swing/FilePane.java @@ -34,6 +34,7 @@ import java.text.DateFormat; import java.text.MessageFormat; import java.util.*; import java.util.List; +import java.util.concurrent.Callable; import javax.swing.*; import javax.swing.border.*; @@ -900,6 +901,16 @@ public class FilePane extends JPanel implements PropertyChangeListener { } } + @Override + public void sort() { + ShellFolder.getInvoker().invoke(new Callable<Void>() { + public Void call() throws Exception { + DetailsTableRowSorter.super.sort(); + return null; + } + }); + } + public void modelStructureChanged() { super.modelStructureChanged(); updateComparators(detailsTableModel.getColumns()); diff --git a/jdk/src/share/classes/sun/swing/plaf/synth/SynthFileChooserUIImpl.java b/jdk/src/share/classes/sun/swing/plaf/synth/SynthFileChooserUIImpl.java index 5ded9d729a4..7069c394ad6 100644 --- a/jdk/src/share/classes/sun/swing/plaf/synth/SynthFileChooserUIImpl.java +++ b/jdk/src/share/classes/sun/swing/plaf/synth/SynthFileChooserUIImpl.java @@ -29,6 +29,8 @@ import java.awt.event.*; import java.beans.*; import java.io.*; import java.util.*; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.swing.*; import javax.swing.event.*; @@ -749,7 +751,11 @@ public class SynthFileChooserUIImpl extends SynthFileChooserUI { File[] baseFolders; if (useShellFolder) { - baseFolders = (File[])ShellFolder.get("fileChooserComboBoxFolders"); + baseFolders = AccessController.doPrivileged(new PrivilegedAction<File[]>() { + public File[] run() { + return (File[]) ShellFolder.get("fileChooserComboBoxFolders"); + } + }); } else { baseFolders = fsv.getRoots(); } diff --git a/jdk/src/share/classes/sun/text/normalizer/CharTrie.java b/jdk/src/share/classes/sun/text/normalizer/CharTrie.java index 3069de8650e..eadbce37c22 100644 --- a/jdk/src/share/classes/sun/text/normalizer/CharTrie.java +++ b/jdk/src/share/classes/sun/text/normalizer/CharTrie.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -77,6 +76,66 @@ public class CharTrie extends Trie m_friendAgent_ = new FriendAgent(); } + /** + * Make a dummy CharTrie. + * A dummy trie is an empty runtime trie, used when a real data trie cannot + * be loaded. + * + * The trie always returns the initialValue, + * or the leadUnitValue for lead surrogate code points. + * The Latin-1 part is always set up to be linear. + * + * @param initialValue the initial value that is set for all code points + * @param leadUnitValue the value for lead surrogate code _units_ that do not + * have associated supplementary data + * @param dataManipulate object which provides methods to parse the char data + */ + public CharTrie(int initialValue, int leadUnitValue, DataManipulate dataManipulate) { + super(new char[BMP_INDEX_LENGTH+SURROGATE_BLOCK_COUNT], HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_, dataManipulate); + + int dataLength, latin1Length, i, limit; + char block; + + /* calculate the actual size of the dummy trie data */ + + /* max(Latin-1, block 0) */ + dataLength=latin1Length= INDEX_STAGE_1_SHIFT_<=8 ? 256 : DATA_BLOCK_LENGTH; + if(leadUnitValue!=initialValue) { + dataLength+=DATA_BLOCK_LENGTH; + } + m_data_=new char[dataLength]; + m_dataLength_=dataLength; + + m_initialValue_=(char)initialValue; + + /* fill the index and data arrays */ + + /* indexes are preset to 0 (block 0) */ + + /* Latin-1 data */ + for(i=0; i<latin1Length; ++i) { + m_data_[i]=(char)initialValue; + } + + if(leadUnitValue!=initialValue) { + /* indexes for lead surrogate code units to the block after Latin-1 */ + block=(char)(latin1Length>>INDEX_STAGE_2_SHIFT_); + i=0xd800>>INDEX_STAGE_1_SHIFT_; + limit=0xdc00>>INDEX_STAGE_1_SHIFT_; + for(; i<limit; ++i) { + m_index_[i]=block; + } + + /* data for lead surrogate code units */ + limit=latin1Length+DATA_BLOCK_LENGTH; + for(i=latin1Length; i<limit; ++i) { + m_data_[i]=(char)leadUnitValue; + } + } + + m_friendAgent_ = new FriendAgent(); + } + /** * Java friend implementation */ @@ -130,7 +189,18 @@ public class CharTrie extends Trie */ public final char getCodePointValue(int ch) { - int offset = getCodePointOffset(ch); + int offset; + + // fastpath for U+0000..U+D7FF + if(0 <= ch && ch < UTF16.LEAD_SURROGATE_MIN_VALUE) { + // copy of getRawOffset() + offset = (m_index_[ch >> INDEX_STAGE_1_SHIFT_] << INDEX_STAGE_2_SHIFT_) + + (ch & INDEX_STAGE_3_MASK_); + return m_data_[offset]; + } + + // handle U+D800..U+10FFFF + offset = getCodePointOffset(ch); // return -1 if there is an error, in this case we return the default // value: m_initialValue_ diff --git a/jdk/src/share/classes/sun/text/normalizer/NormalizerBase.java b/jdk/src/share/classes/sun/text/normalizer/NormalizerBase.java index c2fc1ab291d..a82475c6009 100644 --- a/jdk/src/share/classes/sun/text/normalizer/NormalizerBase.java +++ b/jdk/src/share/classes/sun/text/normalizer/NormalizerBase.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -127,7 +126,7 @@ import java.text.Normalizer; * normalize(FCD) may be implemented with NFD. * * For more details on FCD see the collation design document: - * http://oss.software.ibm.com/cvs/icu/~checkout~/icuhtml/design/collation/ICU_collation_design.htm + * http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm * * ICU collation performs either NFD or FCD normalization automatically if * normalization is turned on for the collator object. Beyond collation and diff --git a/jdk/src/share/classes/sun/text/normalizer/NormalizerDataReader.java b/jdk/src/share/classes/sun/text/normalizer/NormalizerDataReader.java index 0378d5b5923..69b120d36e4 100644 --- a/jdk/src/share/classes/sun/text/normalizer/NormalizerDataReader.java +++ b/jdk/src/share/classes/sun/text/normalizer/NormalizerDataReader.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -331,7 +330,7 @@ final class NormalizerDataReader implements ICUBinary.Authenticate { throws IOException{ //Read the bytes that make up the normTrie - dataInputStream.read(normBytes); + dataInputStream.readFully(normBytes); //normTrieStream= new ByteArrayInputStream(normBytes); @@ -346,11 +345,11 @@ final class NormalizerDataReader implements ICUBinary.Authenticate { } //Read the fcdTrie - dataInputStream.read(fcdBytes); + dataInputStream.readFully(fcdBytes); //Read the AuxTrie - dataInputStream.read(auxBytes); + dataInputStream.readFully(auxBytes); } public byte[] getDataFormatVersion(){ diff --git a/jdk/src/share/classes/sun/text/normalizer/NormalizerImpl.java b/jdk/src/share/classes/sun/text/normalizer/NormalizerImpl.java index cd4669063c6..112afb0dac0 100644 --- a/jdk/src/share/classes/sun/text/normalizer/NormalizerImpl.java +++ b/jdk/src/share/classes/sun/text/normalizer/NormalizerImpl.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -102,7 +101,7 @@ public final class NormalizerImpl { private static final long MIN_SPECIAL = (long)(0xfc000000 & UNSIGNED_INT_MASK); private static final long SURROGATES_TOP = (long)(0xfff00000 & UNSIGNED_INT_MASK); private static final long MIN_HANGUL = (long)(0xfff00000 & UNSIGNED_INT_MASK); - private static final long MIN_JAMO_V = (long)(0xfff20000 & UNSIGNED_INT_MASK); +// private static final long MIN_JAMO_V = (long)(0xfff20000 & UNSIGNED_INT_MASK); private static final long JAMO_V_TOP = (long)(0xfff30000 & UNSIGNED_INT_MASK); @@ -908,7 +907,7 @@ public final class NormalizerImpl { buffer = composePart(args,prevStarter,src,srcStart,srcLimit,options,nx); // compare the normalized version with the original - if(0!=strCompare(buffer,0,args.length,src,prevStarter,(srcStart-prevStarter), false)) { + if(0!=strCompare(buffer,0,args.length,src,prevStarter,srcStart, false)) { result=NormalizerBase.NO; // normalization differs break; } @@ -2291,7 +2290,7 @@ public final class NormalizerImpl { private static final int OPTIONS_NX_MASK=0x1f; private static final int OPTIONS_UNICODE_MASK=0xe0; public static final int OPTIONS_SETS_MASK=0xff; - private static final int OPTIONS_UNICODE_SHIFT=5; +// private static final int OPTIONS_UNICODE_SHIFT=5; private static final UnicodeSet[] nxCache = new UnicodeSet[OPTIONS_SETS_MASK+1]; /* Constants for options flags for normalization.*/ diff --git a/jdk/src/share/classes/sun/text/normalizer/Trie.java b/jdk/src/share/classes/sun/text/normalizer/Trie.java index 378a6005c1c..16c0f921089 100644 --- a/jdk/src/share/classes/sun/text/normalizer/Trie.java +++ b/jdk/src/share/classes/sun/text/normalizer/Trie.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -37,10 +36,9 @@ package sun.text.normalizer; -import java.io.InputStream; import java.io.DataInputStream; +import java.io.InputStream; import java.io.IOException; -import java.util.Arrays; /** * <p>A trie is a kind of compressed, serializable table of values @@ -81,7 +79,6 @@ public abstract class Trie * This interface specifies methods to be implemented in order for * com.ibm.impl.Trie, to surrogate offset information encapsulated within * the data. - * @draft 2.1 */ public static interface DataManipulate { @@ -92,11 +89,17 @@ public abstract class Trie * @param value data value for a surrogate from the trie, including the * folding offset * @return data offset or 0 if there is no data for the lead surrogate - * @draft 2.1 */ public int getFoldingOffset(int value); } + // default implementation + private static class DefaultGetFoldingOffset implements DataManipulate { + public int getFoldingOffset(int value) { + return value; + } + } + // protected constructor ------------------------------------------- /** @@ -107,7 +110,6 @@ public abstract class Trie * trie data * @throws IOException thrown when input stream does not have the * right header. - * @draft 2.1 */ protected Trie(InputStream inputStream, DataManipulate dataManipulate) throws IOException @@ -121,7 +123,11 @@ public abstract class Trie throw new IllegalArgumentException("ICU data file error: Trie header authentication failed, please check if you have the most updated ICU data file"); } - m_dataManipulate_ = dataManipulate; + if(dataManipulate != null) { + m_dataManipulate_ = dataManipulate; + } else { + m_dataManipulate_ = new DefaultGetFoldingOffset(); + } m_isLatin1Linear_ = (m_options_ & HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_) != 0; m_dataOffset_ = input.readInt(); @@ -135,19 +141,21 @@ public abstract class Trie * @param options used by the trie * @param dataManipulate object containing the information to parse the * trie data - * @draft 2.2 */ protected Trie(char index[], int options, DataManipulate dataManipulate) { m_options_ = options; - m_dataManipulate_ = dataManipulate; + if(dataManipulate != null) { + m_dataManipulate_ = dataManipulate; + } else { + m_dataManipulate_ = new DefaultGetFoldingOffset(); + } m_isLatin1Linear_ = (m_options_ & HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_) != 0; m_index_ = index; m_dataOffset_ = m_index_.length; } - // protected data members ------------------------------------------ /** @@ -158,7 +166,6 @@ public abstract class Trie protected static final int LEAD_INDEX_OFFSET_ = 0x2800 >> 5; /** * Shift size for shifting right the input index. 1..9 - * @draft 2.1 */ protected static final int INDEX_STAGE_1_SHIFT_ = 5; /** @@ -168,31 +175,39 @@ public abstract class Trie * This requires blocks of stage 2 data to be aligned by * DATA_GRANULARITY. * 0..INDEX_STAGE_1_SHIFT - * @draft 2.1 */ protected static final int INDEX_STAGE_2_SHIFT_ = 2; + /** + * Number of data values in a stage 2 (data array) block. + */ + protected static final int DATA_BLOCK_LENGTH=1<<INDEX_STAGE_1_SHIFT_; /** * Mask for getting the lower bits from the input index. - * DATA_BLOCK_LENGTH_ - 1. - * @draft 2.1 + * DATA_BLOCK_LENGTH - 1. */ - protected static final int INDEX_STAGE_3_MASK_ = - (1 << INDEX_STAGE_1_SHIFT_) - 1; + protected static final int INDEX_STAGE_3_MASK_ = DATA_BLOCK_LENGTH - 1; + /** Number of bits of a trail surrogate that are used in index table lookups. */ + protected static final int SURROGATE_BLOCK_BITS=10-INDEX_STAGE_1_SHIFT_; + /** + * Number of index (stage 1) entries per lead surrogate. + * Same as number of index entries for 1024 trail surrogates, + * ==0x400>>INDEX_STAGE_1_SHIFT_ + */ + protected static final int SURROGATE_BLOCK_COUNT=(1<<SURROGATE_BLOCK_BITS); + /** Length of the BMP portion of the index (stage 1) array. */ + protected static final int BMP_INDEX_LENGTH=0x10000>>INDEX_STAGE_1_SHIFT_; /** * Surrogate mask to use when shifting offset to retrieve supplementary * values - * @draft 2.1 */ protected static final int SURROGATE_MASK_ = 0x3FF; /** * Index or UTF16 characters - * @draft 2.1 */ protected char m_index_[]; /** * Internal TrieValue which handles the parsing of the data value. * This class is to be implemented by the user - * @draft 2.1 */ protected DataManipulate m_dataManipulate_; /** @@ -200,7 +215,6 @@ public abstract class Trie * index and data into a char array, so this is used to indicate the * initial offset to the data portion. * Note this index always points to the initial value. - * @draft 2.1 */ protected int m_dataOffset_; /** @@ -215,7 +229,6 @@ public abstract class Trie * @param lead lead surrogate * @param trail trailing surrogate * @return offset to data - * @draft 2.1 */ protected abstract int getSurrogateOffset(char lead, char trail); @@ -223,14 +236,12 @@ public abstract class Trie * Gets the value at the argument index * @param index value at index will be retrieved * @return 32 bit value - * @draft 2.1 */ protected abstract int getValue(int index); /** * Gets the default initial value * @return 32 bit value - * @draft 2.1 */ protected abstract int getInitialValue(); @@ -247,7 +258,6 @@ public abstract class Trie * @param offset index offset which ch is to start from * @param ch index to be used after offset * @return offset to the data - * @draft 2.1 */ protected final int getRawOffset(int offset, char ch) { @@ -261,7 +271,6 @@ public abstract class Trie * Treats a lead surrogate as a normal code point. * @param ch BMP character * @return offset to data - * @draft 2.1 */ protected final int getBMPOffset(char ch) { @@ -279,7 +288,6 @@ public abstract class Trie * the next trailing surrogate character. * @param ch lead surrogate character * @return offset to data - * @draft 2.1 */ protected final int getLeadOffset(char ch) { @@ -293,26 +301,27 @@ public abstract class Trie * Gets the offset to data which the codepoint points to * @param ch codepoint * @return offset to data - * @draft 2.1 */ protected final int getCodePointOffset(int ch) { // if ((ch >> 16) == 0) slower - if (ch >= UTF16.CODEPOINT_MIN_VALUE - && ch < UTF16.SUPPLEMENTARY_MIN_VALUE) { + if (ch < 0) { + return -1; + } else if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE) { + // fastpath for the part of the BMP below surrogates (D800) where getRawOffset() works + return getRawOffset(0, (char)ch); + } else if (ch < UTF16.SUPPLEMENTARY_MIN_VALUE) { // BMP codepoint return getBMPOffset((char)ch); - } - // for optimization - if (ch >= UTF16.CODEPOINT_MIN_VALUE - && ch <= UCharacter.MAX_VALUE) { + } else if (ch <= UCharacter.MAX_VALUE) { // look at the construction of supplementary characters // trail forms the ends of it. return getSurrogateOffset(UTF16.getLeadSurrogate(ch), (char)(ch & SURROGATE_MASK_)); + } else { + // return -1 // if there is an error, in this case we return + return -1; } - // return -1 if there is an error, in this case we return - return -1; } /** @@ -320,7 +329,6 @@ public abstract class Trie * <p>This is overwritten by the child classes. * @param inputStream input stream containing the trie information * @exception IOException thrown when data reading fails. - * @draft 2.1 */ protected void unserialize(InputStream inputStream) throws IOException { @@ -335,7 +343,6 @@ public abstract class Trie /** * Determines if this is a 32 bit trie * @return true if options specifies this is a 32 bit trie - * @draft 2.1 */ protected final boolean isIntTrie() { @@ -345,7 +352,6 @@ public abstract class Trie /** * Determines if this is a 16 bit trie * @return true if this is a 16 bit trie - * @draft 2.1 */ protected final boolean isCharTrie() { @@ -354,40 +360,20 @@ public abstract class Trie // private data members -------------------------------------------- - /** - * Signature index - */ - private static final int HEADER_SIGNATURE_INDEX_ = 0; - /** - * Options index - */ - private static final int HEADER_OPTIONS_INDEX_ = 1 << 1; - /** - * Index length index - */ - private static final int HEADER_INDEX_LENGTH_INDEX_ = 2 << 1; - /** - * Data length index - */ - private static final int HEADER_DATA_LENGTH_INDEX_ = 3 << 1; - /** - * Size of header - */ - private static final int HEADER_LENGTH_ = 4 << 1; /** * Latin 1 option mask */ - private static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200; + protected static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200; /** * Constant number to authenticate the byte block */ - private static final int HEADER_SIGNATURE_ = 0x54726965; + protected static final int HEADER_SIGNATURE_ = 0x54726965; /** * Header option formatting */ private static final int HEADER_OPTIONS_SHIFT_MASK_ = 0xF; - private static final int HEADER_OPTIONS_INDEX_SHIFT_ = 4; - private static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100; + protected static final int HEADER_OPTIONS_INDEX_SHIFT_ = 4; + protected static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100; /** * Flag indicator for Latin quick access data block @@ -409,9 +395,8 @@ public abstract class Trie /** * Authenticates raw data header. * Checking the header information, signature and options. - * @param rawdata array of char data to be checked + * @param signature This contains the options and type of a Trie * @return true if the header is authenticated valid - * @draft 2.1 */ private final boolean checkHeader(int signature) { diff --git a/jdk/src/share/classes/sun/text/normalizer/TrieIterator.java b/jdk/src/share/classes/sun/text/normalizer/TrieIterator.java index 9810c1002cb..b29ab1c569b 100644 --- a/jdk/src/share/classes/sun/text/normalizer/TrieIterator.java +++ b/jdk/src/share/classes/sun/text/normalizer/TrieIterator.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -108,15 +107,14 @@ package sun.text.normalizer; * @since release 2.1, Jan 17 2002 */ public class TrieIterator implements RangeValueIterator - { + // public constructor --------------------------------------------- /** * TrieEnumeration constructor * @param trie to be used * @exception IllegalArgumentException throw when argument is null. - * @draft 2.1 */ public TrieIterator(Trie trie) { @@ -141,7 +139,6 @@ public class TrieIterator implements RangeValueIterator * @return true if we are not at the end of the iteration, false otherwise. * @exception NoSuchElementException - if no more elements exist. * @see com.ibm.icu.util.RangeValueIterator.Element - * @draft 2.1 */ public final boolean next(Element element) { @@ -158,7 +155,6 @@ public class TrieIterator implements RangeValueIterator /** * Resets the iterator to the beginning of the iteration - * @draft 2.1 */ public final void reset() { @@ -186,7 +182,6 @@ public class TrieIterator implements RangeValueIterator * The default function is to return the value as it is. * @param value a value from the trie * @return extracted value - * @draft 2.1 */ protected int extract(int value) { @@ -278,7 +273,6 @@ public class TrieIterator implements RangeValueIterator * Note, if there are no more iterations, it will never get to here. * Blocked out by next(). * @param element return result object - * @draft 2.1 */ private final void calculateNextSupplementaryElement(Element element) { @@ -516,10 +510,6 @@ public class TrieIterator implements RangeValueIterator */ private static final int TRAIL_SURROGATE_MIN_VALUE_ = 0xDC00; /** - * Trail surrogate maximum value - */ - private static final int TRAIL_SURROGATE_MAX_VALUE_ = 0xDFFF; - /** * Number of trail surrogate */ private static final int TRAIL_SURROGATE_COUNT_ = 0x400; @@ -538,11 +528,6 @@ public class TrieIterator implements RangeValueIterator private static final int DATA_BLOCK_LENGTH_ = 1 << Trie.INDEX_STAGE_1_SHIFT_; /** - * Number of codepoints in a stage 2 block - */ - private static final int DATA_BLOCK_SUPPLEMENTARY_LENGTH_ = - DATA_BLOCK_LENGTH_ << 10; - /** * Trie instance */ private Trie m_trie_; @@ -560,10 +545,4 @@ public class TrieIterator implements RangeValueIterator private int m_nextBlock_; private int m_nextBlockIndex_; private int m_nextTrailIndexOffset_; - /** - * This is the return result element - */ - private int m_start_; - private int m_limit_; - private int m_value_; } diff --git a/jdk/src/share/classes/sun/text/normalizer/UBiDiProps.java b/jdk/src/share/classes/sun/text/normalizer/UBiDiProps.java new file mode 100644 index 00000000000..0f5d9600203 --- /dev/null +++ b/jdk/src/share/classes/sun/text/normalizer/UBiDiProps.java @@ -0,0 +1,179 @@ +/* + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + ******************************************************************************* + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* +* file name: UBiDiProps.java +* encoding: US-ASCII +* tab size: 8 (not used) +* indentation:4 +* +* created on: 2005jan16 +* created by: Markus W. Scherer +* +* Low-level Unicode bidi/shaping properties access. +* Java port of ubidi_props.h/.c. +*/ + +package sun.text.normalizer; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; + +public final class UBiDiProps { + // constructors etc. --------------------------------------------------- *** + + // port of ubidi_openProps() + public UBiDiProps() throws IOException{ + InputStream is=ICUData.getStream(DATA_FILE_NAME); + BufferedInputStream b=new BufferedInputStream(is, 4096 /* data buffer size */); + readData(b); + b.close(); + is.close(); + + } + + private void readData(InputStream is) throws IOException { + DataInputStream inputStream=new DataInputStream(is); + + // read the header + ICUBinary.readHeader(inputStream, FMT, new IsAcceptable()); + + // read indexes[] + int i, count; + count=inputStream.readInt(); + if(count<IX_INDEX_TOP) { + throw new IOException("indexes[0] too small in "+DATA_FILE_NAME); + } + indexes=new int[count]; + + indexes[0]=count; + for(i=1; i<count; ++i) { + indexes[i]=inputStream.readInt(); + } + + // read the trie + trie=new CharTrie(inputStream, null); + + // read mirrors[] + count=indexes[IX_MIRROR_LENGTH]; + if(count>0) { + mirrors=new int[count]; + for(i=0; i<count; ++i) { + mirrors[i]=inputStream.readInt(); + } + } + + // read jgArray[] + count=indexes[IX_JG_LIMIT]-indexes[IX_JG_START]; + jgArray=new byte[count]; + for(i=0; i<count; ++i) { + jgArray[i]=inputStream.readByte(); + } + } + + // implement ICUBinary.Authenticate + private final class IsAcceptable implements ICUBinary.Authenticate { + public boolean isDataVersionAcceptable(byte version[]) { + return version[0]==1 && + version[2]==Trie.INDEX_STAGE_1_SHIFT_ && version[3]==Trie.INDEX_STAGE_2_SHIFT_; + } + } + + // UBiDiProps singleton + private static UBiDiProps gBdp=null; + + // port of ubidi_getSingleton() + public static final synchronized UBiDiProps getSingleton() throws IOException { + if(gBdp==null) { + gBdp=new UBiDiProps(); + } + return gBdp; + } + + // UBiDiProps dummy singleton + private static UBiDiProps gBdpDummy=null; + + private UBiDiProps(boolean makeDummy) { // ignore makeDummy, only creates a unique signature + indexes=new int[IX_TOP]; + indexes[0]=IX_TOP; + trie=new CharTrie(0, 0, null); // dummy trie, always returns 0 + } + + /** + * Get a singleton dummy object, one that works with no real data. + * This can be used when the real data is not available. + * Using the dummy can reduce checks for available data after an initial failure. + * Port of ucase_getDummy(). + */ + public static final synchronized UBiDiProps getDummy() { + if(gBdpDummy==null) { + gBdpDummy=new UBiDiProps(true); + } + return gBdpDummy; + } + + public final int getClass(int c) { + return getClassFromProps(trie.getCodePointValue(c)); + } + + // data members -------------------------------------------------------- *** + private int indexes[]; + private int mirrors[]; + private byte jgArray[]; + + private CharTrie trie; + + // data format constants ----------------------------------------------- *** + private static final String DATA_FILE_NAME = "/sun/text/resources/ubidi.icu"; + + /* format "BiDi" */ + private static final byte FMT[]={ 0x42, 0x69, 0x44, 0x69 }; + + /* indexes into indexes[] */ + private static final int IX_INDEX_TOP=0; + private static final int IX_MIRROR_LENGTH=3; + + private static final int IX_JG_START=4; + private static final int IX_JG_LIMIT=5; + + private static final int IX_TOP=16; + + private static final int CLASS_MASK= 0x0000001f; + + private static final int getClassFromProps(int props) { + return props&CLASS_MASK; + } + +} diff --git a/jdk/src/share/classes/sun/text/normalizer/UCharacter.java b/jdk/src/share/classes/sun/text/normalizer/UCharacter.java index 26a5eca99fc..8225517f07c 100644 --- a/jdk/src/share/classes/sun/text/normalizer/UCharacter.java +++ b/jdk/src/share/classes/sun/text/normalizer/UCharacter.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ */ /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -36,19 +36,18 @@ package sun.text.normalizer; -import java.lang.ref.SoftReference; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; +import java.io.IOException; +import java.util.MissingResourceException; /** * <p> * The UCharacter class provides extensions to the - * <a href=http://java.sun.com/j2se/1.3/docs/api/java/lang/Character.html> + * <a href="http://java.sun.com/j2se/1.5/docs/api/java/lang/Character.html"> * java.lang.Character</a> class. These extensions provide support for - * Unicode 3.2 properties and together with the <a href=../text/UTF16.html>UTF16</a> + * more Unicode properties and together with the <a href=../text/UTF16.html>UTF16</a> * class, provide support for supplementary characters (those with code * points above U+FFFF). + * Each ICU release supports the latest version of Unicode available at that time. * </p> * <p> * Code points are represented in these API using ints. While it would be @@ -67,7 +66,7 @@ import java.util.Map; * <i>$ICU4J_CLASS/com.ibm.icu.impl.data</i>. * </p> * <p> - * Aside from the additions for UTF-16 support, and the updated Unicode 3.1 + * Aside from the additions for UTF-16 support, and the updated Unicode * properties, the main differences between UCharacter and Character are: * <ul> * <li> UCharacter is not designed to be a char wrapper and does not have @@ -77,7 +76,7 @@ import java.util.Map; * <li> char charValue(), * <li> int compareTo(java.lang.Character, java.lang.Character), etc. * </ul> - * <li> UCharacter does not include Character APIs that are deprecated, not + * <li> UCharacter does not include Character APIs that are deprecated, nor * does it include the Java-specific character information, such as * boolean isJavaIdentifierPart(char ch). * <li> Character maps characters 'A' - 'Z' and 'a' - 'z' to the numeric @@ -89,10 +88,75 @@ import java.util.Map; * </ul> * <p> * Further detail differences can be determined from the program - * <a href = http://oss.software.ibm.com/developerworks/opensource/cvs/icu4j/~checkout~/icu4j/src/com/ibm/icu/dev/test/lang/UCharacterCompare.java> + * <a href="http://source.icu-project.org/repos/icu/icu4j/trunk/src/com/ibm/icu/dev/test/lang/UCharacterCompare.java"> * com.ibm.icu.dev.test.lang.UCharacterCompare</a> * </p> * <p> + * In addition to Java compatibility functions, which calculate derived properties, + * this API provides low-level access to the Unicode Character Database. + * </p> + * <p> + * Unicode assigns each code point (not just assigned character) values for + * many properties. + * Most of them are simple boolean flags, or constants from a small enumerated list. + * For some properties, values are strings or other relatively more complex types. + * </p> + * <p> + * For more information see + * "About the Unicode Character Database" (http://www.unicode.org/ucd/) + * and the ICU User Guide chapter on Properties (http://www.icu-project.org/userguide/properties.html). + * </p> + * <p> + * There are also functions that provide easy migration from C/POSIX functions + * like isblank(). Their use is generally discouraged because the C/POSIX + * standards do not define their semantics beyond the ASCII range, which means + * that different implementations exhibit very different behavior. + * Instead, Unicode properties should be used directly. + * </p> + * <p> + * There are also only a few, broad C/POSIX character classes, and they tend + * to be used for conflicting purposes. For example, the "isalpha()" class + * is sometimes used to determine word boundaries, while a more sophisticated + * approach would at least distinguish initial letters from continuation + * characters (the latter including combining marks). + * (In ICU, BreakIterator is the most sophisticated API for word boundaries.) + * Another example: There is no "istitle()" class for titlecase characters. + * </p> + * <p> + * ICU 3.4 and later provides API access for all twelve C/POSIX character classes. + * ICU implements them according to the Standard Recommendations in + * Annex C: Compatibility Properties of UTS #18 Unicode Regular Expressions + * (http://www.unicode.org/reports/tr18/#Compatibility_Properties). + * </p> + * <p> + * API access for C/POSIX character classes is as follows: + * - alpha: isUAlphabetic(c) or hasBinaryProperty(c, UProperty.ALPHABETIC) + * - lower: isULowercase(c) or hasBinaryProperty(c, UProperty.LOWERCASE) + * - upper: isUUppercase(c) or hasBinaryProperty(c, UProperty.UPPERCASE) + * - punct: ((1<<getType(c)) & ((1<<DASH_PUNCTUATION)|(1<<START_PUNCTUATION)|(1<<END_PUNCTUATION)|(1<<CONNECTOR_PUNCTUATION)|(1<<OTHER_PUNCTUATION)|(1<<INITIAL_PUNCTUATION)|(1<<FINAL_PUNCTUATION)))!=0 + * - digit: isDigit(c) or getType(c)==DECIMAL_DIGIT_NUMBER + * - xdigit: hasBinaryProperty(c, UProperty.POSIX_XDIGIT) + * - alnum: hasBinaryProperty(c, UProperty.POSIX_ALNUM) + * - space: isUWhiteSpace(c) or hasBinaryProperty(c, UProperty.WHITE_SPACE) + * - blank: hasBinaryProperty(c, UProperty.POSIX_BLANK) + * - cntrl: getType(c)==CONTROL + * - graph: hasBinaryProperty(c, UProperty.POSIX_GRAPH) + * - print: hasBinaryProperty(c, UProperty.POSIX_PRINT) + * </p> + * <p> + * The C/POSIX character classes are also available in UnicodeSet patterns, + * using patterns like [:graph:] or \p{graph}. + * </p> + * <p> + * Note: There are several ICU (and Java) whitespace functions. + * Comparison: + * - isUWhiteSpace=UCHAR_WHITE_SPACE: Unicode White_Space property; + * most of general categories "Z" (separators) + most whitespace ISO controls + * (including no-break spaces, but excluding IS1..IS4 and ZWSP) + * - isWhitespace: Java isWhitespace; Z + whitespace ISO controls but excluding no-break spaces + * - isSpaceChar: just Z (including no-break spaces) + * </p> + * <p> * This class is not subclassable * </p> * @author Syn Wee Quek @@ -110,95 +174,10 @@ public final class UCharacter */ public static interface NumericType { - /** - * @stable ICU 2.4 - */ - public static final int NONE = 0; /** * @stable ICU 2.4 */ public static final int DECIMAL = 1; - /** - * @stable ICU 2.4 - */ - public static final int DIGIT = 2; - /** - * @stable ICU 2.4 - */ - public static final int NUMERIC = 3; - /** - * @stable ICU 2.4 - */ - public static final int COUNT = 4; - } - - /** - * Hangul Syllable Type constants. - * - * @see UProperty#HANGUL_SYLLABLE_TYPE - * @stable ICU 2.6 - */ - public static interface HangulSyllableType - { - /** - * @stable ICU 2.6 - */ - public static final int NOT_APPLICABLE = 0; /*[NA]*/ /*See note !!*/ - /** - * @stable ICU 2.6 - */ - public static final int LEADING_JAMO = 1; /*[L]*/ - /** - * @stable ICU 2.6 - */ - public static final int VOWEL_JAMO = 2; /*[V]*/ - /** - * @stable ICU 2.6 - */ - public static final int TRAILING_JAMO = 3; /*[T]*/ - /** - * @stable ICU 2.6 - */ - public static final int LV_SYLLABLE = 4; /*[LV]*/ - /** - * @stable ICU 2.6 - */ - public static final int LVT_SYLLABLE = 5; /*[LVT]*/ - /** - * @stable ICU 2.6 - */ - public static final int COUNT = 6; - } - - /** - * [Sun] This interface moved from UCharacterEnums.java. - * - * 'Enum' for the CharacterCategory constants. These constants are - * compatible in name <b>but not in value</b> with those defined in - * <code>java.lang.Character</code>. - * @see UCharacterCategory - * @draft ICU 3.0 - * @deprecated This is a draft API and might change in a future release of ICU. - */ - public static interface ECharacterCategory - { - /** - * Character type Lu - * @stable ICU 2.1 - */ - public static final int UPPERCASE_LETTER = 1; - - /** - * Character type Lt - * @stable ICU 2.1 - */ - public static final int TITLECASE_LETTER = 3; - - /** - * Character type Lo - * @stable ICU 2.1 - */ - public static final int OTHER_LETTER = 5; } // public data members ----------------------------------------------- @@ -225,14 +204,6 @@ public final class UCharacter public static final int SUPPLEMENTARY_MIN_VALUE = UTF16.SUPPLEMENTARY_MIN_VALUE; - /** - * Special value that is returned by getUnicodeNumericValue(int) when no - * numeric value is defined for a code point. - * @stable ICU 2.4 - * @see #getUnicodeNumericValue - */ - public static final double NO_NUMERIC_VALUE = -123456789; - // public methods ---------------------------------------------------- /** @@ -262,160 +233,15 @@ public final class UCharacter { // when ch is out of bounds getProperty == 0 int props = getProperty(ch); - if (getNumericType(props) != NumericType.DECIMAL) { - return (radix <= 10) ? -1 : getEuropeanDigit(ch); + int value; + if (getNumericType(props) == NumericType.DECIMAL) { + value = UCharacterProperty.getUnsignedValue(props); + } else { + value = getEuropeanDigit(ch); } - // if props == 0, it will just fall through and return -1 - if (isNotExceptionIndicator(props)) { - // not contained in exception data - // getSignedValue is just shifting so we can check for the sign - // first - // Optimization - // int result = UCharacterProperty.getSignedValue(props); - // if (result >= 0) { - // return result; - // } - if (props >= 0) { - return UCharacterProperty.getSignedValue(props); - } - } - else { - int index = UCharacterProperty.getExceptionIndex(props); - if (PROPERTY_.hasExceptionValue(index, - UCharacterProperty.EXC_NUMERIC_VALUE_)) { - int result = PROPERTY_.getException(index, - UCharacterProperty.EXC_NUMERIC_VALUE_); - if (result >= 0) { - return result; - } - } - } - - if (radix > 10) { - int result = getEuropeanDigit(ch); - if (result >= 0 && result < radix) { - return result; - } - } - return -1; + return (0 <= value && value < radix) ? value : -1; } - /** - * <p>Get the numeric value for a Unicode code point as defined in the - * Unicode Character Database.</p> - * <p>A "double" return type is necessary because some numeric values are - * fractions, negative, or too large for int.</p> - * <p>For characters without any numeric values in the Unicode Character - * Database, this function will return NO_NUMERIC_VALUE.</p> - * <p><em>API Change:</em> In release 2.2 and prior, this API has a - * return type int and returns -1 when the argument ch does not have a - * corresponding numeric value. This has been changed to synch with ICU4C - * </p> - * This corresponds to the ICU4C function u_getNumericValue. - * @param ch Code point to get the numeric value for. - * @return numeric value of ch, or NO_NUMERIC_VALUE if none is defined. - * @stable ICU 2.4 - */ - public static double getUnicodeNumericValue(int ch) - { - // equivalent to c version double u_getNumericValue(UChar32 c) - int props = PROPERTY_.getProperty(ch); - int numericType = getNumericType(props); - if (numericType > NumericType.NONE && numericType < NumericType.COUNT) { - if (isNotExceptionIndicator(props)) { - return UCharacterProperty.getSignedValue(props); - } - else { - int index = UCharacterProperty.getExceptionIndex(props); - boolean nex = false; - boolean dex = false; - double numerator = 0; - if (PROPERTY_.hasExceptionValue(index, - UCharacterProperty.EXC_NUMERIC_VALUE_)) { - int num = PROPERTY_.getException(index, - UCharacterProperty.EXC_NUMERIC_VALUE_); - // There are special values for huge numbers that are - // powers of ten. genprops/store.c documents: - // if numericValue = 0x7fffff00 + x then - // numericValue = 10 ^ x - if (num >= NUMERATOR_POWER_LIMIT_) { - num &= 0xff; - // 10^x without math.h - numerator = Math.pow(10, num); - } - else { - numerator = num; - } - nex = true; - } - double denominator = 0; - if (PROPERTY_.hasExceptionValue(index, - UCharacterProperty.EXC_DENOMINATOR_VALUE_)) { - denominator = PROPERTY_.getException(index, - UCharacterProperty.EXC_DENOMINATOR_VALUE_); - // faster path not in c - if (numerator != 0) { - return numerator / denominator; - } - dex = true; - } - - if (nex) { - if (dex) { - return numerator / denominator; - } - return numerator; - } - if (dex) { - return 1 / denominator; - } - } - } - return NO_NUMERIC_VALUE; - } - - /** - * Returns a value indicating a code point's Unicode category. - * Up-to-date Unicode implementation of java.lang.Character.getType() - * except for the above mentioned code points that had their category - * changed.<br> - * Return results are constants from the interface - * <a href=UCharacterCategory.html>UCharacterCategory</a><br> - * <em>NOTE:</em> the UCharacterCategory values are <em>not</em> compatible with - * those returned by java.lang.Character.getType. UCharacterCategory values - * match the ones used in ICU4C, while java.lang.Character type - * values, though similar, skip the value 17.</p> - * @param ch code point whose type is to be determined - * @return category which is a value of UCharacterCategory - * @stable ICU 2.1 - */ - public static int getType(int ch) - { - return getProperty(ch) & UCharacterProperty.TYPE_MASK; - } - - //// for StringPrep - /** - * Returns a code point corresponding to the two UTF16 characters. - * @param lead the lead char - * @param trail the trail char - * @return code point if surrogate characters are valid. - * @exception IllegalArgumentException thrown when argument characters do - * not form a valid codepoint - * @stable ICU 2.1 - */ - public static int getCodePoint(char lead, char trail) - { - if (lead >= UTF16.LEAD_SURROGATE_MIN_VALUE && - lead <= UTF16.LEAD_SURROGATE_MAX_VALUE && - trail >= UTF16.TRAIL_SURROGATE_MIN_VALUE && - trail <= UTF16.TRAIL_SURROGATE_MAX_VALUE) { - return UCharacterProperty.getRawSupplementary(lead, trail); - } - throw new IllegalArgumentException("Illegal surrogate characters"); - } - - //// for StringPrep /** * Returns the Bidirection property of a code point. * For example, 0x0041 (letter A) has the LEFT_TO_RIGHT directional @@ -428,111 +254,24 @@ public final class UCharacter */ public static int getDirection(int ch) { - // when ch is out of bounds getProperty == 0 - return (getProperty(ch) >> BIDI_SHIFT_) & BIDI_MASK_AFTER_SHIFT_; + return gBdp.getClass(ch); } /** - * The given string is mapped to its case folding equivalent according to - * UnicodeData.txt and CaseFolding.txt; if any character has no case - * folding equivalent, the character itself is returned. - * "Full", multiple-code point case folding mappings are returned here. - * For "simple" single-code point mappings use the API - * foldCase(int ch, boolean defaultmapping). - * @param str the String to be converted - * @param defaultmapping Indicates if all mappings defined in - * CaseFolding.txt is to be used, otherwise the - * mappings for dotted I and dotless i marked with - * 'I' in CaseFolding.txt will be skipped. - * @return the case folding equivalent of the character, if - * any; otherwise the character itself. - * @see #foldCase(int, boolean) + * Returns a code point corresponding to the two UTF16 characters. + * @param lead the lead char + * @param trail the trail char + * @return code point if surrogate characters are valid. + * @exception IllegalArgumentException thrown when argument characters do + * not form a valid codepoint * @stable ICU 2.1 */ - public static String foldCase(String str, boolean defaultmapping) + public static int getCodePoint(char lead, char trail) { - int size = str.length(); - StringBuffer result = new StringBuffer(size); - int offset = 0; - int ch; - - // case mapping loop - while (offset < size) { - ch = UTF16.charAt(str, offset); - offset += UTF16.getCharCount(ch); - int props = PROPERTY_.getProperty(ch); - if (isNotExceptionIndicator(props)) { - int type = UCharacterProperty.TYPE_MASK & props; - if (type == ECharacterCategory.UPPERCASE_LETTER || - type == ECharacterCategory.TITLECASE_LETTER) { - ch += UCharacterProperty.getSignedValue(props); - } - } - else { - int index = UCharacterProperty.getExceptionIndex(props); - if (PROPERTY_.hasExceptionValue(index, - UCharacterProperty.EXC_CASE_FOLDING_)) { - int exception = PROPERTY_.getException(index, - UCharacterProperty.EXC_CASE_FOLDING_); - if (exception != 0) { - PROPERTY_.getFoldCase(exception & LAST_CHAR_MASK_, - exception >> SHIFT_24_, result); - } - else { - // special case folding mappings, hardcoded - if (ch != 0x49 && ch != 0x130) { - // return ch itself because there is no special - // mapping for it - UTF16.append(result, ch); - continue; - } - if (defaultmapping) { - // default mappings - if (ch == 0x49) { - // 0049; C; 0069; # LATIN CAPITAL LETTER I - result.append( - UCharacterProperty.LATIN_SMALL_LETTER_I_); - } - else if (ch == 0x130) { - // 0130; F; 0069 0307; - // # LATIN CAPITAL LETTER I WITH DOT ABOVE - result.append( - UCharacterProperty.LATIN_SMALL_LETTER_I_); - result.append((char)0x307); - } - } - else { - // Turkic mappings - if (ch == 0x49) { - // 0049; T; 0131; # LATIN CAPITAL LETTER I - result.append((char)0x131); - } - else if (ch == 0x130) { - // 0130; T; 0069; - // # LATIN CAPITAL LETTER I WITH DOT ABOVE - result.append( - UCharacterProperty.LATIN_SMALL_LETTER_I_); - } - } - } - // do not fall through to the output of c - continue; - } - else { - if (PROPERTY_.hasExceptionValue(index, - UCharacterProperty.EXC_LOWERCASE_)) { - ch = PROPERTY_.getException(index, - UCharacterProperty.EXC_LOWERCASE_); - } - } - - } - - // handle 1:1 code point mappings from UnicodeData.txt - UTF16.append(result, ch); + if (UTF16.isLeadSurrogate(lead) && UTF16.isTrailSurrogate(trail)) { + return UCharacterProperty.getRawSupplementary(lead, trail); } - - return result.toString(); + throw new IllegalArgumentException("Illegal surrogate characters"); } /** @@ -555,83 +294,6 @@ public final class UCharacter return PROPERTY_.getAge(ch); } - /** - * <p>Gets the property value for an Unicode property type of a code point. - * Also returns binary and mask property values.</p> - * <p>Unicode, especially in version 3.2, defines many more properties than - * the original set in UnicodeData.txt.</p> - * <p>The properties APIs are intended to reflect Unicode properties as - * defined in the Unicode Character Database (UCD) and Unicode Technical - * Reports (UTR). For details about the properties see - * http://www.unicode.org/.</p> - * <p>For names of Unicode properties see the UCD file PropertyAliases.txt. - * </p> - * <pre> - * Sample usage: - * int ea = UCharacter.getIntPropertyValue(c, UProperty.EAST_ASIAN_WIDTH); - * int ideo = UCharacter.getIntPropertyValue(c, UProperty.IDEOGRAPHIC); - * boolean b = (ideo == 1) ? true : false; - * </pre> - * @param ch code point to test. - * @param type UProperty selector constant, identifies which binary - * property to check. Must be - * UProperty.BINARY_START <= type < UProperty.BINARY_LIMIT or - * UProperty.INT_START <= type < UProperty.INT_LIMIT or - * UProperty.MASK_START <= type < UProperty.MASK_LIMIT. - * @return numeric value that is directly the property value or, - * for enumerated properties, corresponds to the numeric value of - * the enumerated constant of the respective property value - * enumeration type (cast to enum type if necessary). - * Returns 0 or 1 (for false / true) for binary Unicode properties. - * Returns a bit-mask for mask properties. - * Returns 0 if 'type' is out of bounds or if the Unicode version - * does not have data for the property at all, or not for this code - * point. - * @see UProperty - * @see #hasBinaryProperty - * @see #getIntPropertyMinValue - * @see #getIntPropertyMaxValue - * @see #getUnicodeVersion - * @stable ICU 2.4 - */ - public static int getIntPropertyValue(int ch, int type) - { - /* - * For Normalizer with Unicode 3.2, this method is called only for - * HANGUL_SYLLABLE_TYPE in UnicodeSet.addPropertyStarts(). - */ - if (type == UProperty.HANGUL_SYLLABLE_TYPE) { - /* purely algorithmic; hardcode known characters, check for assigned new ones */ - if(ch<NormalizerImpl.JAMO_L_BASE) { - /* NA */ - } else if(ch<=0x11ff) { - /* Jamo range */ - if(ch<=0x115f) { - /* Jamo L range, HANGUL CHOSEONG ... */ - if(ch==0x115f || ch<=0x1159 || getType(ch)==ECharacterCategory.OTHER_LETTER) { - return HangulSyllableType.LEADING_JAMO; - } - } else if(ch<=0x11a7) { - /* Jamo V range, HANGUL JUNGSEONG ... */ - if(ch<=0x11a2 || getType(ch)==ECharacterCategory.OTHER_LETTER) { - return HangulSyllableType.VOWEL_JAMO; - } - } else { - /* Jamo T range */ - if(ch<=0x11f9 || getType(ch)==ECharacterCategory.OTHER_LETTER) { - return HangulSyllableType.TRAILING_JAMO; - } - } - } else if((ch-=NormalizerImpl.HANGUL_BASE)<0) { - /* NA */ - } else if(ch<NormalizerImpl.HANGUL_COUNT) { - /* Hangul syllable */ - return ch%NormalizerImpl.JAMO_T_COUNT==0 ? HangulSyllableType.LV_SYLLABLE : HangulSyllableType.LVT_SYLLABLE; - } - } - return 0; /* NA */ - } - // private variables ------------------------------------------------- /** @@ -643,143 +305,43 @@ public final class UCharacter */ private static final char[] PROPERTY_TRIE_INDEX_; private static final char[] PROPERTY_TRIE_DATA_; - private static final int[] PROPERTY_DATA_; private static final int PROPERTY_INITIAL_VALUE_; + private static final UBiDiProps gBdp; + // block to initialise character property database static { try { - PROPERTY_ = UCharacterProperty.getInstance(); - PROPERTY_TRIE_INDEX_ = PROPERTY_.m_trieIndex_; - PROPERTY_TRIE_DATA_ = PROPERTY_.m_trieData_; - PROPERTY_DATA_ = PROPERTY_.m_property_; - PROPERTY_INITIAL_VALUE_ - = PROPERTY_DATA_[PROPERTY_.m_trieInitialValue_]; + PROPERTY_ = UCharacterProperty.getInstance(); + PROPERTY_TRIE_INDEX_ = PROPERTY_.m_trieIndex_; + PROPERTY_TRIE_DATA_ = PROPERTY_.m_trieData_; + PROPERTY_INITIAL_VALUE_ = PROPERTY_.m_trieInitialValue_; } catch (Exception e) { - throw new RuntimeException(e.getMessage()); + throw new MissingResourceException(e.getMessage(),"",""); } + + UBiDiProps bdp; + try { + bdp=UBiDiProps.getSingleton(); + } catch(IOException e) { + bdp=UBiDiProps.getDummy(); + } + gBdp=bdp; } - /** - * To get the last character out from a data type - */ - private static final int LAST_CHAR_MASK_ = 0xFFFF; - - /** - * To get the last byte out from a data type - */ -// private static final int LAST_BYTE_MASK_ = 0xFF; - - /** - * Shift 16 bits - */ -// private static final int SHIFT_16_ = 16; - - /** - * Shift 24 bits - */ - private static final int SHIFT_24_ = 24; - /** * Shift to get numeric type */ - private static final int NUMERIC_TYPE_SHIFT_ = 12; + private static final int NUMERIC_TYPE_SHIFT_ = 5; /** * Mask to get numeric type */ private static final int NUMERIC_TYPE_MASK_ = 0x7 << NUMERIC_TYPE_SHIFT_; - /** - * Shift to get bidi bits - */ - private static final int BIDI_SHIFT_ = 6; - /** - * Mask to be applied after shifting to get bidi bits - */ - private static final int BIDI_MASK_AFTER_SHIFT_ = 0x1F; - - /** - * <p>Numerator power limit. - * There are special values for huge numbers that are powers of ten.</p> - * <p>c version genprops/store.c documents: - * if numericValue = 0x7fffff00 + x then numericValue = 10 ^ x</p> - */ - private static final int NUMERATOR_POWER_LIMIT_ = 0x7fffff00; - /** - * Integer properties mask and shift values for joining type. - * Equivalent to icu4c UPROPS_JT_MASK. - */ - private static final int JOINING_TYPE_MASK_ = 0x00003800; - /** - * Integer properties mask and shift values for joining type. - * Equivalent to icu4c UPROPS_JT_SHIFT. - */ - private static final int JOINING_TYPE_SHIFT_ = 11; - /** - * Integer properties mask and shift values for joining group. - * Equivalent to icu4c UPROPS_JG_MASK. - */ - private static final int JOINING_GROUP_MASK_ = 0x000007e0; - /** - * Integer properties mask and shift values for joining group. - * Equivalent to icu4c UPROPS_JG_SHIFT. - */ - private static final int JOINING_GROUP_SHIFT_ = 5; - /** - * Integer properties mask for decomposition type. - * Equivalent to icu4c UPROPS_DT_MASK. - */ - private static final int DECOMPOSITION_TYPE_MASK_ = 0x0000001f; - /** - * Integer properties mask and shift values for East Asian cell width. - * Equivalent to icu4c UPROPS_EA_MASK - */ - private static final int EAST_ASIAN_MASK_ = 0x00038000; - /** - * Integer properties mask and shift values for East Asian cell width. - * Equivalent to icu4c UPROPS_EA_SHIFT - */ - private static final int EAST_ASIAN_SHIFT_ = 15; - - /** - * Integer properties mask and shift values for line breaks. - * Equivalent to icu4c UPROPS_LB_MASK - */ - private static final int LINE_BREAK_MASK_ = 0x007C0000; - /** - * Integer properties mask and shift values for line breaks. - * Equivalent to icu4c UPROPS_LB_SHIFT - */ - private static final int LINE_BREAK_SHIFT_ = 18; - /** - * Integer properties mask and shift values for blocks. - * Equivalent to icu4c UPROPS_BLOCK_MASK - */ - private static final int BLOCK_MASK_ = 0x00007f80; - /** - * Integer properties mask and shift values for blocks. - * Equivalent to icu4c UPROPS_BLOCK_SHIFT - */ - private static final int BLOCK_SHIFT_ = 7; - /** - * Integer properties mask and shift values for scripts. - * Equivalent to icu4c UPROPS_SHIFT_MASK - */ - private static final int SCRIPT_MASK_ = 0x0000007f; - - // private constructor ----------------------------------------------- - ///CLOVER:OFF - /** - * Private constructor to prevent instantiation - */ - private UCharacter() - { - } - ///CLOVER:ON // private methods --------------------------------------------------- /** @@ -818,17 +380,6 @@ public final class UCharacter return (props & NUMERIC_TYPE_MASK_) >> NUMERIC_TYPE_SHIFT_; } - /** - * Checks if the property value has a exception indicator - * @param props 32 bit property value - * @return true if property does not have a exception indicator, false - * otherwise - */ - private static boolean isNotExceptionIndicator(int props) - { - return (props & UCharacterProperty.EXCEPTION_MASK) == 0; - } - /** * Gets the property value at the index. * This is optimized. @@ -841,35 +392,34 @@ public final class UCharacter * @return property value of code point * @stable ICU 2.6 */ - private static int getProperty(int ch) + private static final int getProperty(int ch) { if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE || (ch > UTF16.LEAD_SURROGATE_MAX_VALUE && ch < UTF16.SUPPLEMENTARY_MIN_VALUE)) { - // BMP codepoint - try { // using try for < 0 ch is faster than using an if statement - return PROPERTY_DATA_[ - PROPERTY_TRIE_DATA_[ + // BMP codepoint 0000..D7FF or DC00..FFFF + try { // using try for ch < 0 is faster than using an if statement + return PROPERTY_TRIE_DATA_[ (PROPERTY_TRIE_INDEX_[ch >> 5] << 2) - + (ch & 0x1f)]]; + + (ch & 0x1f)]; } catch (ArrayIndexOutOfBoundsException e) { return PROPERTY_INITIAL_VALUE_; } } if (ch <= UTF16.LEAD_SURROGATE_MAX_VALUE) { - // surrogate - return PROPERTY_DATA_[ - PROPERTY_TRIE_DATA_[ + // lead surrogate D800..DBFF + return PROPERTY_TRIE_DATA_[ (PROPERTY_TRIE_INDEX_[(0x2800 >> 5) + (ch >> 5)] << 2) - + (ch & 0x1f)]]; + + (ch & 0x1f)]; } // for optimization if (ch <= UTF16.CODEPOINT_MAX_VALUE) { + // supplementary code point 10000..10FFFF // look at the construction of supplementary characters // trail forms the ends of it. - return PROPERTY_DATA_[PROPERTY_.m_trie_.getSurrogateValue( + return PROPERTY_.m_trie_.getSurrogateValue( UTF16.getLeadSurrogate(ch), - (char)(ch & 0x3ff))]; + (char)(ch & 0x3ff)); } // return m_dataOffset_ if there is an error, in this case we return // the default value: m_initialValue_ @@ -877,4 +427,5 @@ public final class UCharacter // this is for optimization. return PROPERTY_INITIAL_VALUE_; } + } diff --git a/jdk/src/share/classes/sun/text/normalizer/UCharacterProperty.java b/jdk/src/share/classes/sun/text/normalizer/UCharacterProperty.java index 1a748ff1731..a7412588ec1 100644 --- a/jdk/src/share/classes/sun/text/normalizer/UCharacterProperty.java +++ b/jdk/src/share/classes/sun/text/normalizer/UCharacterProperty.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -40,8 +39,7 @@ package sun.text.normalizer; import java.io.BufferedInputStream; import java.io.InputStream; import java.io.IOException; -import java.text.BreakIterator; -import java.util.Locale; +import java.util.MissingResourceException; /** * <p>Internal class used for Unicode character property database.</p> @@ -56,10 +54,9 @@ import java.util.Locale; * <a href=UCharacter.html>UCharacter</a>.</p> * @author Syn Wee Quek * @since release 2.1, february 1st 2002 -* @draft 2.1 */ -public final class UCharacterProperty implements Trie.DataManipulate +public final class UCharacterProperty { // public data members ----------------------------------------------- @@ -83,68 +80,16 @@ public final class UCharacterProperty implements Trie.DataManipulate */ public int m_trieInitialValue_; /** - * Character property table - */ - public int m_property_[]; - /** * Unicode version */ public VersionInfo m_unicodeVersion_; - /** - * Exception indicator for uppercase type - */ - public static final int EXC_UPPERCASE_ = 0; - /** - * Exception indicator for lowercase type - */ - public static final int EXC_LOWERCASE_ = 1; - /** - * Exception indicator for titlecase type - */ - public static final int EXC_TITLECASE_ = 2; - /** - * Exception indicator for digit type - */ - public static final int EXC_UNUSED_ = 3; - /** - * Exception indicator for numeric type - */ - public static final int EXC_NUMERIC_VALUE_ = 4; - /** - * Exception indicator for denominator type - */ - public static final int EXC_DENOMINATOR_VALUE_ = 5; - /** - * Exception indicator for mirror type - */ - public static final int EXC_MIRROR_MAPPING_ = 6; - /** - * Exception indicator for special casing type - */ - public static final int EXC_SPECIAL_CASING_ = 7; - /** - * Exception indicator for case folding type - */ - public static final int EXC_CASE_FOLDING_ = 8; - /** - * EXC_COMBINING_CLASS_ is not found in ICU. - * Used to retrieve the combining class of the character in the exception - * value - */ - public static final int EXC_COMBINING_CLASS_ = 9; - /** - * Latin lowercase i - */ - public static final char LATIN_SMALL_LETTER_I_ = 0x69; - /** - * Character type mask - */ - public static final int TYPE_MASK = 0x1F; - /** - * Exception test mask - */ - public static final int EXCEPTION_MASK = 0x20; + // uprops.h enum UPropertySource --------------------------------------- *** + + /** From uchar.c/uprops.icu properties vectors trie */ + public static final int SRC_PROPSVEC=2; + /** One more than the highest UPropertySource (SRC_) constant. */ + public static final int SRC_COUNT=9; // public methods ---------------------------------------------------- @@ -158,23 +103,6 @@ public final class UCharacterProperty implements Trie.DataManipulate m_trieInitialValue_ = friendagent.getPrivateInitialValue(); } - /** - * Called by com.ibm.icu.util.Trie to extract from a lead surrogate's - * data the index array offset of the indexes for that lead surrogate. - * @param value data value for a surrogate from the trie, including the - * folding offset - * @return data offset or 0 if there is no data for the lead surrogate - */ - public int getFoldingOffset(int value) - { - if ((value & SUPPLEMENTARY_FOLD_INDICATOR_MASK_) != 0) { - return (value & SUPPLEMENTARY_FOLD_OFFSET_MASK_); - } - else { - return 0; - } - } - /** * Gets the property value at the index. * This is optimized. @@ -183,129 +111,79 @@ public final class UCharacterProperty implements Trie.DataManipulate * @param ch code point whose property value is to be retrieved * @return property value of code point */ - public int getProperty(int ch) + public final int getProperty(int ch) { if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE || (ch > UTF16.LEAD_SURROGATE_MAX_VALUE && ch < UTF16.SUPPLEMENTARY_MIN_VALUE)) { - // BMP codepoint + // BMP codepoint 0000..D7FF or DC00..FFFF // optimized - try { - return m_property_[ - m_trieData_[ + try { // using try for ch < 0 is faster than using an if statement + return m_trieData_[ (m_trieIndex_[ch >> Trie.INDEX_STAGE_1_SHIFT_] << Trie.INDEX_STAGE_2_SHIFT_) - + (ch & Trie.INDEX_STAGE_3_MASK_)]]; + + (ch & Trie.INDEX_STAGE_3_MASK_)]; } catch (ArrayIndexOutOfBoundsException e) { - return m_property_[m_trieInitialValue_]; + return m_trieInitialValue_; } } if (ch <= UTF16.LEAD_SURROGATE_MAX_VALUE) { - return m_property_[ - m_trieData_[ + // lead surrogate D800..DBFF + return m_trieData_[ (m_trieIndex_[Trie.LEAD_INDEX_OFFSET_ + (ch >> Trie.INDEX_STAGE_1_SHIFT_)] << Trie.INDEX_STAGE_2_SHIFT_) - + (ch & Trie.INDEX_STAGE_3_MASK_)]]; + + (ch & Trie.INDEX_STAGE_3_MASK_)]; } - // for optimization if (ch <= UTF16.CODEPOINT_MAX_VALUE) { + // supplementary code point 10000..10FFFF // look at the construction of supplementary characters // trail forms the ends of it. - return m_property_[m_trie_.getSurrogateValue( + return m_trie_.getSurrogateValue( UTF16.getLeadSurrogate(ch), - (char)(ch & Trie.SURROGATE_MASK_))]; + (char)(ch & Trie.SURROGATE_MASK_)); } + // ch is out of bounds // return m_dataOffset_ if there is an error, in this case we return // the default value: m_initialValue_ // we cannot assume that m_initialValue_ is at offset 0 // this is for optimization. - return m_property_[m_trieInitialValue_]; - // return m_property_[m_trie_.getCodePointValue(ch)]; + return m_trieInitialValue_; + + // this all is an inlined form of return m_trie_.getCodePointValue(ch); } /** - * Getting the signed numeric value of a character embedded in the property + * Getting the unsigned numeric value of a character embedded in the property * argument * @param prop the character - * @return signed numberic value + * @return unsigned numberic value */ - public static int getSignedValue(int prop) - { - return (prop >> VALUE_SHIFT_); - } - - /** - * Getting the exception index for argument property - * @param prop character property - * @return exception index - */ - public static int getExceptionIndex(int prop) + public static int getUnsignedValue(int prop) { return (prop >> VALUE_SHIFT_) & UNSIGNED_VALUE_MASK_AFTER_SHIFT_; } - /** - * Determines if the exception value passed in has the kind of information - * which the indicator wants, e.g if the exception value contains the digit - * value of the character - * @param index exception index - * @param indicator type indicator - * @return true if type value exist - */ - public boolean hasExceptionValue(int index, int indicator) - { - return (m_exception_[index] & (1 << indicator)) != 0; - } - - /** - * Gets the exception value at the index, assuming that data type is - * available. Result is undefined if data is not available. Use - * hasExceptionValue() to determine data's availability. - * @param index - * @param etype exception data type - * @return exception data type value at index - */ - public int getException(int index, int etype) - { - // contained in exception data - if (etype == EXC_COMBINING_CLASS_) { - return m_exception_[index]; - } - // contained in the exception digit address - index = addExceptionOffset(m_exception_[index], etype, ++ index); - return m_exception_[index]; - } - - /** - * Gets the folded case value at the index - * @param index of the case value to be retrieved - * @param count number of characters to retrieve - * @param str string buffer to which to append the result - */ - public void getFoldCase(int index, int count, StringBuffer str) - { - // first 2 chars are for the simple mappings - index += 2; - while (count > 0) { - str.append(m_case_[index]); - index ++; - count --; - } - } - /** * Gets the unicode additional properties. * C version getUnicodeProperties. * @param codepoint codepoint whose additional properties is to be * retrieved + * @param column * @return unicode properties */ - public int getAdditional(int codepoint) { - return m_additionalVectors_[m_additionalTrie_.getCodePointValue(codepoint)]; + public int getAdditional(int codepoint, int column) { + if (column == -1) { + return getProperty(codepoint); + } + if (column < 0 || column >= m_additionalColumnsCount_) { + return 0; + } + return m_additionalVectors_[ + m_additionalTrie_.getCodePointValue(codepoint) + column]; } - /** + /** * <p>Get the "age" of the code point.</p> * <p>The "age" is the Unicode version when the code point was first * designated (as a non-character or for Private Use) or assigned a @@ -316,11 +194,10 @@ public final class UCharacterProperty implements Trie.DataManipulate * <p>This API does not check the validity of the codepoint.</p> * @param codepoint The code point. * @return the Unicode version number - * @draft ICU 2.1 */ public VersionInfo getAge(int codepoint) { - int version = getAdditional(codepoint) >> AGE_SHIFT_; + int version = getAdditional(codepoint, 0) >> AGE_SHIFT_; return VersionInfo.getInstance( (version >> FIRST_NIBBLE_SHIFT_) & LAST_NIBBLE_MASK_, version & LAST_NIBBLE_MASK_, 0, 0); @@ -341,16 +218,16 @@ public final class UCharacterProperty implements Trie.DataManipulate /** * Loads the property data and initialize the UCharacterProperty instance. - * @throws RuntimeException when data is missing or data has been corrupted + * @throws MissingResourceException when data is missing or data has been corrupted */ - public static UCharacterProperty getInstance() throws RuntimeException + public static UCharacterProperty getInstance() { - if (INSTANCE_ == null) { + if(INSTANCE_ == null) { try { INSTANCE_ = new UCharacterProperty(); } catch (Exception e) { - throw new RuntimeException(e.getMessage()); + throw new MissingResourceException(e.getMessage(),"",""); } } return INSTANCE_; @@ -359,6 +236,9 @@ public final class UCharacterProperty implements Trie.DataManipulate /** * Checks if the argument c is to be treated as a white space in ICU * rules. Usually ICU rule white spaces are ignored unless quoted. + * Equivalent to test for Pattern_White_Space Unicode property. + * Stable set of characters, won't change. + * See UAX #31 Identifier and Pattern Syntax: http://www.unicode.org/reports/tr31/ * @param c codepoint to check * @return true if c is a ICU white space */ @@ -366,8 +246,9 @@ public final class UCharacterProperty implements Trie.DataManipulate { /* "white space" in the sense of ICU rule parsers This is a FIXED LIST that is NOT DEPENDENT ON UNICODE PROPERTIES. - See UTR #31: http://www.unicode.org/reports/tr31/. + See UAX #31 Identifier and Pattern Syntax: http://www.unicode.org/reports/tr31/ U+0009..U+000D, U+0020, U+0085, U+200E..U+200F, and U+2028..U+2029 + Equivalent to test for Pattern_White_Space Unicode property. */ return (c >= 0x0009 && c <= 0x2029 && (c <= 0x000D || c == 0x0020 || c == 0x0085 || @@ -376,15 +257,6 @@ public final class UCharacterProperty implements Trie.DataManipulate // protected variables ----------------------------------------------- - /** - * Case table - */ - char m_case_[]; - - /** - * Exception property table - */ - int m_exception_[]; /** * Extra property trie */ @@ -426,78 +298,20 @@ public final class UCharacterProperty implements Trie.DataManipulate */ private static final int DATA_BUFFER_SIZE_ = 25000; - /** - * This, from what i infer is the max size of the indicators used for the - * exception values. - * Number of bits in an 8-bit integer value - */ - private static final int EXC_GROUP_ = 8; - - /** - * Mask to get the group - */ - private static final int EXC_GROUP_MASK_ = 255; - - /** - * Mask to get the digit value in the exception result - */ - private static final int EXC_DIGIT_MASK_ = 0xFFFF; - - /** - * Offset table for data in exception block.<br> - * Table formed by the number of bits used for the index, e.g. 0 = 0 bits, - * 1 = 1 bits. - */ - private static final byte FLAGS_OFFSET_[] = - { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 - }; - /** * Numeric value shift */ - private static final int VALUE_SHIFT_ = 20; + private static final int VALUE_SHIFT_ = 8; /** * Mask to be applied after shifting to obtain an unsigned numeric value */ - private static final int UNSIGNED_VALUE_MASK_AFTER_SHIFT_ = 0x7FF; - - /** - * - */ - private static final int NUMERIC_TYPE_SHIFT = 12; - - /** - * Folding indicator mask - */ - private static final int SUPPLEMENTARY_FOLD_INDICATOR_MASK_ = 0x8000; - - /** - * Folding offset mask - */ - private static final int SUPPLEMENTARY_FOLD_OFFSET_MASK_ = 0x7FFF; + private static final int UNSIGNED_VALUE_MASK_AFTER_SHIFT_ = 0xFF; /** * Shift value for lead surrogate to form a supplementary character. */ private static final int LEAD_SURROGATE_SHIFT_ = 10; - /** * Offset to add to combined surrogate pair to avoid msking. */ @@ -507,16 +321,12 @@ public final class UCharacterProperty implements Trie.DataManipulate LEAD_SURROGATE_SHIFT_) - UTF16.TRAIL_SURROGATE_MIN_VALUE; - /** - * To get the last character out from a data type - */ - private static final int LAST_CHAR_MASK_ = 0xFFFF; + // additional properties ---------------------------------------------- /** * First nibble shift */ private static final int FIRST_NIBBLE_SHIFT_ = 0x4; - /** * Second nibble mask */ @@ -530,7 +340,7 @@ public final class UCharacterProperty implements Trie.DataManipulate /** * Constructor - * @exception thrown when data reading fails or data corrupted + * @exception IOException thrown when data reading fails or data corrupted */ private UCharacterProperty() throws IOException { @@ -544,275 +354,16 @@ public final class UCharacterProperty implements Trie.DataManipulate m_trie_.putIndexData(this); } - /* Is followed by {case-ignorable}* cased ? */ - /** - * Getting the correct address for data in the exception value - * @param evalue exception value - * @param indicator type of data to retrieve - * @param address current address to move from - * @return the correct address - */ - private int addExceptionOffset(int evalue, int indicator, int address) - { - int result = address; - if (indicator >= EXC_GROUP_) { - result += FLAGS_OFFSET_[evalue & EXC_GROUP_MASK_]; - evalue >>= EXC_GROUP_; - indicator -= EXC_GROUP_; - } - int mask = (1 << indicator) - 1; - result += FLAGS_OFFSET_[evalue & mask]; - return result; - } - - private static final int TAB = 0x0009; - private static final int LF = 0x000a; - private static final int FF = 0x000c; - private static final int CR = 0x000d; - private static final int U_A = 0x0041; - private static final int U_Z = 0x005a; - private static final int U_a = 0x0061; - private static final int U_z = 0x007a; - private static final int DEL = 0x007f; - private static final int NL = 0x0085; - private static final int NBSP = 0x00a0; - private static final int CGJ = 0x034f; - private static final int FIGURESP= 0x2007; - private static final int HAIRSP = 0x200a; - private static final int ZWNJ = 0x200c; - private static final int ZWJ = 0x200d; - private static final int RLM = 0x200f; - private static final int NNBSP = 0x202f; - private static final int WJ = 0x2060; - private static final int INHSWAP = 0x206a; - private static final int NOMDIG = 0x206f; - private static final int ZWNBSP = 0xfeff; - - public UnicodeSet addPropertyStarts(UnicodeSet set) { - int c; - - /* add the start code point of each same-value range of each trie */ - //utrie_enum(&normTrie, NULL, _enumPropertyStartsRange, set); - TrieIterator propsIter = new TrieIterator(m_trie_); - RangeValueIterator.Element propsResult = new RangeValueIterator.Element(); - while(propsIter.next(propsResult)){ - set.add(propsResult.start); - } - //utrie_enum(&propsVectorsTrie, NULL, _enumPropertyStartsRange, set); - TrieIterator propsVectorsIter = new TrieIterator(m_additionalTrie_); - RangeValueIterator.Element propsVectorsResult = new RangeValueIterator.Element(); - while(propsVectorsIter.next(propsVectorsResult)){ - set.add(propsVectorsResult.start); - } - - - /* add code points with hardcoded properties, plus the ones following them */ - - /* add for IS_THAT_CONTROL_SPACE() */ - set.add(TAB); /* range TAB..CR */ - set.add(CR+1); - set.add(0x1c); - set.add(0x1f+1); - set.add(NL); - set.add(NL+1); - - /* add for u_isIDIgnorable() what was not added above */ - set.add(DEL); /* range DEL..NBSP-1, NBSP added below */ - set.add(HAIRSP); - set.add(RLM+1); - set.add(INHSWAP); - set.add(NOMDIG+1); - set.add(ZWNBSP); - set.add(ZWNBSP+1); - - /* add no-break spaces for u_isWhitespace() what was not added above */ - set.add(NBSP); - set.add(NBSP+1); - set.add(FIGURESP); - set.add(FIGURESP+1); - set.add(NNBSP); - set.add(NNBSP+1); - - /* add for u_charDigitValue() */ - set.add(0x3007); - set.add(0x3008); - set.add(0x4e00); - set.add(0x4e01); - set.add(0x4e8c); - set.add(0x4e8d); - set.add(0x4e09); - set.add(0x4e0a); - set.add(0x56db); - set.add(0x56dc); - set.add(0x4e94); - set.add(0x4e95); - set.add(0x516d); - set.add(0x516e); - set.add(0x4e03); - set.add(0x4e04); - set.add(0x516b); - set.add(0x516c); - set.add(0x4e5d); - set.add(0x4e5e); - - /* add for u_digit() */ - set.add(U_a); - set.add(U_z+1); - set.add(U_A); - set.add(U_Z+1); - - /* add for UCHAR_DEFAULT_IGNORABLE_CODE_POINT what was not added above */ - set.add(WJ); /* range WJ..NOMDIG */ - set.add(0xfff0); - set.add(0xfffb+1); - set.add(0xe0000); - set.add(0xe0fff+1); - - /* add for UCHAR_GRAPHEME_BASE and others */ - set.add(CGJ); - set.add(CGJ+1); - - /* add for UCHAR_JOINING_TYPE */ - set.add(ZWNJ); /* range ZWNJ..ZWJ */ - set.add(ZWJ+1); - - /* add Jamo type boundaries for UCHAR_HANGUL_SYLLABLE_TYPE */ - set.add(0x1100); - int value= UCharacter.HangulSyllableType.LEADING_JAMO; - int value2; - for(c=0x115a; c<=0x115f; ++c) { - value2= UCharacter.getIntPropertyValue(c, UProperty.HANGUL_SYLLABLE_TYPE); - if(value!=value2) { - value=value2; - set.add(c); + public void upropsvec_addPropertyStarts(UnicodeSet set) { + /* add the start code point of each same-value range of the properties vectors trie */ + if(m_additionalColumnsCount_>0) { + /* if m_additionalColumnsCount_==0 then the properties vectors trie may not be there at all */ + TrieIterator propsVectorsIter = new TrieIterator(m_additionalTrie_); + RangeValueIterator.Element propsVectorsResult = new RangeValueIterator.Element(); + while(propsVectorsIter.next(propsVectorsResult)){ + set.add(propsVectorsResult.start); } } - - set.add(0x1160); - value=UCharacter.HangulSyllableType.VOWEL_JAMO; - for(c=0x11a3; c<=0x11a7; ++c) { - value2=UCharacter.getIntPropertyValue(c, UProperty.HANGUL_SYLLABLE_TYPE); - if(value!=value2) { - value=value2; - set.add(c); - } - } - - set.add(0x11a8); - value=UCharacter.HangulSyllableType.TRAILING_JAMO; - for(c=0x11fa; c<=0x11ff; ++c) { - value2=UCharacter.getIntPropertyValue(c, UProperty.HANGUL_SYLLABLE_TYPE); - if(value!=value2) { - value=value2; - set.add(c); - } - } - - - /* - * Omit code points for u_charCellWidth() because - * - it is deprecated and not a real Unicode property - * - they are probably already set from the trie enumeration - */ - - /* - * Omit code points with hardcoded specialcasing properties - * because we do not build property UnicodeSets for them right now. - */ - return set; // for chaining - } -/*---------------------------------------------------------------- - * Inclusions list - *----------------------------------------------------------------*/ - - /* - * Return a set of characters for property enumeration. - * The set implicitly contains 0x110000 as well, which is one more than the highest - * Unicode code point. - * - * This set is used as an ordered list - its code points are ordered, and - * consecutive code points (in Unicode code point order) in the set define a range. - * For each two consecutive characters (start, limit) in the set, - * all of the UCD/normalization and related properties for - * all code points start..limit-1 are all the same, - * except for character names and ISO comments. - * - * All Unicode code points U+0000..U+10ffff are covered by these ranges. - * The ranges define a partition of the Unicode code space. - * ICU uses the inclusions set to enumerate properties for generating - * UnicodeSets containing all code points that have a certain property value. - * - * The Inclusion List is generated from the UCD. It is generated - * by enumerating the data tries, and code points for hardcoded properties - * are added as well. - * - * -------------------------------------------------------------------------- - * - * The following are ideas for getting properties-unique code point ranges, - * with possible optimizations beyond the current implementation. - * These optimizations would require more code and be more fragile. - * The current implementation generates one single list (set) for all properties. - * - * To enumerate properties efficiently, one needs to know ranges of - * repetitive values, so that the value of only each start code point - * can be applied to the whole range. - * This information is in principle available in the uprops.icu/unorm.icu data. - * - * There are two obstacles: - * - * 1. Some properties are computed from multiple data structures, - * making it necessary to get repetitive ranges by intersecting - * ranges from multiple tries. - * - * 2. It is not economical to write code for getting repetitive ranges - * that are precise for each of some 50 properties. - * - * Compromise ideas: - * - * - Get ranges per trie, not per individual property. - * Each range contains the same values for a whole group of properties. - * This would generate currently five range sets, two for uprops.icu tries - * and three for unorm.icu tries. - * - * - Combine sets of ranges for multiple tries to get sufficient sets - * for properties, e.g., the uprops.icu main and auxiliary tries - * for all non-normalization properties. - * - * Ideas for representing ranges and combining them: - * - * - A UnicodeSet could hold just the start code points of ranges. - * Multiple sets are easily combined by or-ing them together. - * - * - Alternatively, a UnicodeSet could hold each even-numbered range. - * All ranges could be enumerated by using each start code point - * (for the even-numbered ranges) as well as each limit (end+1) code point - * (for the odd-numbered ranges). - * It should be possible to combine two such sets by xor-ing them, - * but no more than two. - * - * The second way to represent ranges may(?!) yield smaller UnicodeSet arrays, - * but the first one is certainly simpler and applicable for combining more than - * two range sets. - * - * It is possible to combine all range sets for all uprops/unorm tries into one - * set that can be used for all properties. - * As an optimization, there could be less-combined range sets for certain - * groups of properties. - * The relationship of which less-combined range set to use for which property - * depends on the implementation of the properties and must be hardcoded - * - somewhat error-prone and higher maintenance but can be tested easily - * by building property sets "the simple way" in test code. - * - * --- - * - * Do not use a UnicodeSet pattern because that causes infinite recursion; - * UnicodeSet depends on the inclusions set. - */ - public UnicodeSet getInclusions() { - UnicodeSet set = new UnicodeSet(); - NormalizerImpl.addPropertyStarts(set); - addPropertyStarts(set); - return set; } } diff --git a/jdk/src/share/classes/sun/text/normalizer/UCharacterPropertyReader.java b/jdk/src/share/classes/sun/text/normalizer/UCharacterPropertyReader.java index bb44a8f9b4c..60cb327c4d8 100644 --- a/jdk/src/share/classes/sun/text/normalizer/UCharacterPropertyReader.java +++ b/jdk/src/share/classes/sun/text/normalizer/UCharacterPropertyReader.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -37,8 +36,8 @@ package sun.text.normalizer; -import java.io.InputStream; import java.io.DataInputStream; +import java.io.InputStream; import java.io.IOException; /** @@ -50,254 +49,13 @@ import java.io.IOException; * </p> * <p>uprops.icu which is in big-endian format is jared together with this * package.</p> +* +* Unicode character properties file format see +* (ICU4C)/source/tools/genprops/store.c +* * @author Syn Wee Quek * @since release 2.1, February 1st 2002 -* @draft 2.1 */ -/* Unicode character properties file format ------------------------------------ - -The file format prepared and written here contains several data -structures that store indexes or data. - - - -The following is a description of format version 3 . - -Data contents: - -The contents is a parsed, binary form of several Unicode character -database files, most prominently UnicodeData.txt. - -Any Unicode code point from 0 to 0x10ffff can be looked up to get -the properties, if any, for that code point. This means that the input -to the lookup are 21-bit unsigned integers, with not all of the -21-bit range used. - -It is assumed that client code keeps a uint32_t pointer -to the beginning of the data: - - const uint32_t *p32; - -Formally, the file contains the following structures: - - const int32_t indexes[16] with values i0..i15: - - i0 propsIndex; -- 32-bit unit index to the table of 32-bit properties words - i1 exceptionsIndex; -- 32-bit unit index to the table of 32-bit exception words - i2 exceptionsTopIndex; -- 32-bit unit index to the array of UChars for special mappings - - i3 additionalTrieIndex; -- 32-bit unit index to the additional trie for more properties - i4 additionalVectorsIndex; -- 32-bit unit index to the table of properties vectors - i5 additionalVectorsColumns; -- number of 32-bit words per properties vector - - i6 reservedItemIndex; -- 32-bit unit index to the top of the properties vectors table - i7..i9 reservedIndexes; -- reserved values; 0 for now - - i10 maxValues; -- maximum code values for vector word 0, see uprops.h (format version 3.1+) - i11 maxValues2; -- maximum code values for vector word 2, see uprops.h (format version 3.2) - i12..i15 reservedIndexes; -- reserved values; 0 for now - - PT serialized properties trie, see utrie.h (byte size: 4*(i0-16)) - - P const uint32_t props32[i1-i0]; - E const uint32_t exceptions[i2-i1]; - U const UChar uchars[2*(i3-i2)]; - - AT serialized trie for additional properties (byte size: 4*(i4-i3)) - PV const uint32_t propsVectors[(i6-i4)/i5][i5]==uint32_t propsVectors[i6-i4]; - -Trie lookup and properties: - -In order to condense the data for the 21-bit code space, several properties of -the Unicode code assignment are exploited: -- The code space is sparse. -- There are several 10k of consecutive codes with the same properties. -- Characters and scripts are allocated in groups of 16 code points. -- Inside blocks for scripts the properties are often repetitive. -- The 21-bit space is not fully used for Unicode. - -The lookup of properties for a given code point is done with a trie lookup, -using the UTrie implementation. -The trie lookup result is a 16-bit index in the props32[] table where the -actual 32-bit properties word is stored. This is done to save space. - -(There are thousands of 16-bit entries in the trie data table, but -only a few hundred unique 32-bit properties words. -If the trie data table contained 32-bit words directly, then that would be -larger because the length of the table would be the same as now but the -width would be 32 bits instead of 16. This saves more than 10kB.) - -With a given Unicode code point - - UChar32 c; - -and 0<=c<0x110000, the lookup is done like this: - - uint16_t i; - UTRIE_GET16(c, i); - uint32_t props=p32[i]; - -For some characters, not all of the properties can be efficiently encoded -using 32 bits. For them, the 32-bit word contains an index into the exceptions[] -array: - - if(props&EXCEPTION_BIT)) { - uint16_t e=(uint16_t)(props>>VALUE_SHIFT); - ... - } - -The exception values are a variable number of uint32_t starting at - - const uint32_t *pe=p32+exceptionsIndex+e; - -The first uint32_t there contains flags about what values actually follow it. -Some of the exception values are UChar32 code points for the case mappings, -others are numeric values etc. - -32-bit properties sets: - -Each 32-bit properties word contains: - - 0.. 4 general category - 5 has exception values - 6..10 BiDi category -11 is mirrored -12..14 numericType: - 0 no numeric value - 1 decimal digit value - 2 digit value - 3 numeric value - ### TODO: type 4 for Han digits & numbers?! -15..19 reserved -20..31 value according to bits 0..5: - if(has exception) { - exception index; - } else switch(general category) { - case Ll: delta to uppercase; -- same as titlecase - case Lu: -delta to lowercase; -- titlecase is same as c - case Lt: -delta to lowercase; -- uppercase is same as c - default: - if(is mirrored) { - delta to mirror; - } else if(numericType!=0) { - numericValue; - } else { - 0; - }; - } - -Exception values: - -In the first uint32_t exception word for a code point, -bits -31..16 reserved -15..0 flags that indicate which values follow: - -bit - 0 has uppercase mapping - 1 has lowercase mapping - 2 has titlecase mapping - 3 unused - 4 has numeric value (numerator) - if numericValue=0x7fffff00+x then numericValue=10^x - 5 has denominator value - 6 has a mirror-image Unicode code point - 7 has SpecialCasing.txt entries - 8 has CaseFolding.txt entries - -According to the flags in this word, one or more uint32_t words follow it -in the sequence of the bit flags in the flags word; if a flag is not set, -then the value is missing or 0: - -For the case mappings and the mirror-image Unicode code point, -one uint32_t or UChar32 each is the code point. -If the titlecase mapping is missing, then it is the same as the uppercase mapping. - -For the digit values, bits 31..16 contain the decimal digit value, and -bits 15..0 contain the digit value. A value of -1 indicates that -this value is missing. - -For the numeric/numerator value, an int32_t word contains the value directly, -except for when there is no numerator but a denominator, then the numerator -is implicitly 1. This means: - numerator denominator result - none none none - x none x - none y 1/y - x y x/y - -If the numerator value is 0x7fffff00+x then it is replaced with 10^x. - -For the denominator value, a uint32_t word contains the value directly. - -For special casing mappings, the 32-bit exception word contains: -31 if set, this character has complex, conditional mappings - that are not stored; - otherwise, the mappings are stored according to the following bits -30..24 number of UChars used for mappings -23..16 reserved -15.. 0 UChar offset from the beginning of the UChars array where the - UChars for the special case mappings are stored in the following format: - -Format of special casing UChars: -One UChar value with lengths as follows: -14..10 number of UChars for titlecase mapping - 9.. 5 number of UChars for uppercase mapping - 4.. 0 number of UChars for lowercase mapping - -Followed by the UChars for lowercase, uppercase, titlecase mappings in this order. - -For case folding mappings, the 32-bit exception word contains: -31..24 number of UChars used for the full mapping -23..16 reserved -15.. 0 UChar offset from the beginning of the UChars array where the - UChars for the special case mappings are stored in the following format: - -Format of case folding UChars: -Two UChars contain the simple mapping as follows: - 0, 0 no simple mapping - BMP,0 a simple mapping to a BMP code point - s1, s2 a simple mapping to a supplementary code point stored as two surrogates -This is followed by the UChars for the full case folding mappings. - -Example: -U+2160, ROMAN NUMERAL ONE, needs an exception because it has a lowercase -mapping and a numeric value. -Its exception values would be stored as 3 uint32_t words: - -- flags=0x0a (see above) with combining class 0 -- lowercase mapping 0x2170 -- numeric value=1 - ---- Additional properties (new in format version 2.1) --- - -The second trie for additional properties (AT) is also a UTrie with 16-bit data. -The data words consist of 32-bit unit indexes (not row indexes!) into the -table of unique properties vectors (PV). -Each vector contains a set of properties. -The width of a vector (number of uint32_t per row) may change -with the formatVersion, it is stored in i5. - -Current properties: see icu/source/common/uprops.h - ---- Changes in format version 3.1 --- - -See i10 maxValues above, contains only UBLOCK_COUNT and USCRIPT_CODE_LIMIT. - ---- Changes in format version 3.2 --- - -- The tries use linear Latin-1 ranges. -- The additional properties bits store full properties XYZ instead - of partial Other_XYZ, so that changes in the derivation formulas - need not be tracked in runtime library code. -- Joining Type and Line Break are also stored completely, so that uprops.c - needs no runtime formulas for enumerated properties either. -- Store the case-sensitive flag in the main properties word. -- i10 also contains U_LB_COUNT and U_EA_COUNT. -- i11 contains maxValues2 for vector word 2. - ------------------------------------------------------------------------------ */ - final class UCharacterPropertyReader implements ICUBinary.Authenticate { // public methods ---------------------------------------------------- @@ -315,7 +73,6 @@ final class UCharacterPropertyReader implements ICUBinary.Authenticate * <p>Protected constructor.</p> * @param inputStream ICU uprop.dat file input stream * @exception IOException throw if data file fails authentication - * @draft 2.1 */ protected UCharacterPropertyReader(InputStream inputStream) throws IOException @@ -331,8 +88,7 @@ final class UCharacterPropertyReader implements ICUBinary.Authenticate * <p>Reads uprops.icu, parse it into blocks of data to be stored in * UCharacterProperty.</P * @param ucharppty UCharacterProperty instance - * @exception thrown when data reading fails - * @draft 2.1 + * @exception IOException thrown when data reading fails */ protected void read(UCharacterProperty ucharppty) throws IOException { @@ -362,38 +118,30 @@ final class UCharacterPropertyReader implements ICUBinary.Authenticate // read the trie index block // m_props_index_ in terms of ints - ucharppty.m_trie_ = new CharTrie(m_dataInputStream_, ucharppty); + ucharppty.m_trie_ = new CharTrie(m_dataInputStream_, null); - // reads the 32 bit properties block + // skip the 32 bit properties block int size = m_exceptionOffset_ - m_propertyOffset_; - ucharppty.m_property_ = new int[size]; - for (int i = 0; i < size; i ++) { - ucharppty.m_property_[i] = m_dataInputStream_.readInt(); - } + m_dataInputStream_.skipBytes(size * 4); // reads the 32 bit exceptions block size = m_caseOffset_ - m_exceptionOffset_; - ucharppty.m_exception_ = new int[size]; - for (int i = 0; i < size; i ++) { - ucharppty.m_exception_[i] = m_dataInputStream_.readInt(); - } + m_dataInputStream_.skipBytes(size * 4); // reads the 32 bit case block size = (m_additionalOffset_ - m_caseOffset_) << 1; - ucharppty.m_case_ = new char[size]; - for (int i = 0; i < size; i ++) { - ucharppty.m_case_[i] = m_dataInputStream_.readChar(); - } + m_dataInputStream_.skipBytes(size * 2); - // reads the additional property block - ucharppty.m_additionalTrie_ = new CharTrie(m_dataInputStream_, - ucharppty); + if(m_additionalColumnsCount_ > 0) { + // reads the additional property block + ucharppty.m_additionalTrie_ = new CharTrie(m_dataInputStream_, null); - // additional properties - size = m_reservedOffset_ - m_additionalVectorsOffset_; - ucharppty.m_additionalVectors_ = new int[size]; - for (int i = 0; i < size; i ++) { - ucharppty.m_additionalVectors_[i] = m_dataInputStream_.readInt(); + // additional properties + size = m_reservedOffset_ - m_additionalVectorsOffset_; + ucharppty.m_additionalVectors_ = new int[size]; + for (int i = 0; i < size; i ++) { + ucharppty.m_additionalVectors_[i] = m_dataInputStream_.readInt(); + } } m_dataInputStream_.close(); @@ -428,12 +176,15 @@ final class UCharacterPropertyReader implements ICUBinary.Authenticate private byte m_unicodeVersion_[]; /** - * File format version that this class understands. - * No guarantees are made if a older version is used + * Data format "UPro". */ private static final byte DATA_FORMAT_ID_[] = {(byte)0x55, (byte)0x50, (byte)0x72, (byte)0x6F}; - private static final byte DATA_FORMAT_VERSION_[] = {(byte)0x3, (byte)0x1, + /** + * Format version; this code works with all versions with the same major + * version number and the same Trie bit distribution. + */ + private static final byte DATA_FORMAT_VERSION_[] = {(byte)0x5, (byte)0, (byte)Trie.INDEX_STAGE_1_SHIFT_, (byte)Trie.INDEX_STAGE_2_SHIFT_}; } diff --git a/jdk/src/share/classes/sun/text/normalizer/UProperty.java b/jdk/src/share/classes/sun/text/normalizer/UProperty.java deleted file mode 100644 index 3b8c097f43a..00000000000 --- a/jdk/src/share/classes/sun/text/normalizer/UProperty.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* - ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -package sun.text.normalizer; - -/** - * <p>Selection constants for Unicode properties. </p> - * <p>These constants are used in functions like - * UCharacter.hasBinaryProperty(int) to select one of the Unicode properties. - * </p> - * <p>The properties APIs are intended to reflect Unicode properties as - * defined in the Unicode Character Database (UCD) and Unicode Technical - * Reports (UTR).</p> - * <p>For details about the properties see <a href=http://www.unicode.org> - * http://www.unicode.org</a>.</p> - * <p>For names of Unicode properties see the UCD file PropertyAliases.txt. - * </p> - * <p>Important: If ICU is built with UCD files from Unicode versions below - * 3.2, then properties marked with "new" are not or not fully - * available. Check UCharacter.getUnicodeVersion() to be sure.</p> - * @author Syn Wee Quek - * @stable ICU 2.6 - * @see com.ibm.icu.lang.UCharacter - */ -public interface UProperty -{ - // public data member -------------------------------------------------- - - /** - * Enumerated property Hangul_Syllable_Type, new in Unicode 4. - * Returns HangulSyllableType values. - * @stable ICU 2.6 - */ - public static final int HANGUL_SYLLABLE_TYPE = 0x100B; - - /** - * Bitmask property General_Category_Mask. - * This is the General_Category property returned as a bit mask. - * When used in UCharacter.getIntPropertyValue(c), - * returns bit masks for UCharacterCategory values where exactly one bit is set. - * When used with UCharacter.getPropertyValueName() and UCharacter.getPropertyValueEnum(), - * a multi-bit mask is used for sets of categories like "Letters". - * @stable ICU 2.4 - */ - public static final int GENERAL_CATEGORY_MASK = 0x2000; -} diff --git a/jdk/src/share/classes/sun/text/normalizer/UTF16.java b/jdk/src/share/classes/sun/text/normalizer/UTF16.java index 3b872a6063f..2aa7c6d3571 100644 --- a/jdk/src/share/classes/sun/text/normalizer/UTF16.java +++ b/jdk/src/share/classes/sun/text/normalizer/UTF16.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -184,15 +183,16 @@ public final class UTF16 * bounds. * @stable ICU 2.1 */ - public static int charAt(String source, int offset16) - { - if (offset16 < 0 || offset16 >= source.length()) { - throw new StringIndexOutOfBoundsException(offset16); - } - + public static int charAt(String source, int offset16) { char single = source.charAt(offset16); - if (single < LEAD_SURROGATE_MIN_VALUE || - single > TRAIL_SURROGATE_MAX_VALUE) { + if (single < LEAD_SURROGATE_MIN_VALUE) { + return single; + } + return _charAt(source, offset16, single); + } + + private static int _charAt(String source, int offset16, char single) { + if (single > TRAIL_SURROGATE_MAX_VALUE) { return single; } @@ -201,29 +201,23 @@ public final class UTF16 // low, look both directions. if (single <= LEAD_SURROGATE_MAX_VALUE) { - ++ offset16; + ++offset16; if (source.length() != offset16) { char trail = source.charAt(offset16); - if (trail >= TRAIL_SURROGATE_MIN_VALUE && - trail <= TRAIL_SURROGATE_MAX_VALUE) { - return UCharacterProperty.getRawSupplementary(single, - trail); + if (trail >= TRAIL_SURROGATE_MIN_VALUE && trail <= TRAIL_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } + } else { + --offset16; + if (offset16 >= 0) { + // single is a trail surrogate so + char lead = source.charAt(offset16); + if (lead >= LEAD_SURROGATE_MIN_VALUE && lead <= LEAD_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(lead, single); } } } - else - { - -- offset16; - if (offset16 >= 0) { - // single is a trail surrogate so - char lead = source.charAt(offset16); - if (lead >= LEAD_SURROGATE_MIN_VALUE && - lead <= LEAD_SURROGATE_MAX_VALUE) { - return UCharacterProperty.getRawSupplementary(lead, - single); - } - } - } return single; // return unmatched surrogate } diff --git a/jdk/src/share/classes/sun/text/normalizer/UnicodeSet.java b/jdk/src/share/classes/sun/text/normalizer/UnicodeSet.java index eaffb7c8b44..21ab0c883de 100644 --- a/jdk/src/share/classes/sun/text/normalizer/UnicodeSet.java +++ b/jdk/src/share/classes/sun/text/normalizer/UnicodeSet.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -38,11 +37,8 @@ package sun.text.normalizer; import java.text.ParsePosition; -import java.util.Map; -import java.util.HashMap; -import java.util.TreeSet; import java.util.Iterator; -import java.util.Collection; +import java.util.TreeSet; /** * A mutable set of Unicode characters and multicharacter strings. Objects of this class @@ -130,8 +126,8 @@ import java.util.Collection; * "[:Lu:]" and the Perl-like syntax "\p{Lu}" are recognized. For a * complete list of supported property patterns, see the User's Guide * for UnicodeSet at - * <a href="http://oss.software.ibm.com/icu/userguide/unicodeSet.html"> - * http://oss.software.ibm.com/icu/userguide/unicodeSet.html</a>. + * <a href="http://www.icu-project.org/userguide/unicodeSet.html"> + * http://www.icu-project.org/userguide/unicodeSet.html</a>. * Actual determination of property data is defined by the underlying * Unicode database as implemented by UCharacter. * @@ -271,9 +267,11 @@ import java.util.Collection; * </tr> * </table> * </blockquote> + * <p>To iterate over contents of UnicodeSet, use UnicodeSetIterator class. * * @author Alan Liu * @stable ICU 2.0 + * @see UnicodeSetIterator */ public class UnicodeSet implements UnicodeMatcher { @@ -322,7 +320,7 @@ public class UnicodeSet implements UnicodeMatcher { * properties are all exactly alike, e.g. CJK Ideographs from * U+4E00 to U+9FA5. */ - private static UnicodeSet INCLUSIONS = null; + private static UnicodeSet INCLUSIONS[] = null; //---------------------------------------------------------------- // Public API @@ -471,17 +469,18 @@ public class UnicodeSet implements UnicodeMatcher { return result; } - return _generatePattern(result, escapeUnprintable); + return _generatePattern(result, escapeUnprintable, true); } /** * Generate and append a string representation of this set to result. * This does not use this.pat, the cleaned up copy of the string * passed to applyPattern(). - * @stable ICU 2.0 + * @param includeStrings if false, doesn't include the strings. + * @stable ICU 3.8 */ public StringBuffer _generatePattern(StringBuffer result, - boolean escapeUnprintable) { + boolean escapeUnprintable, boolean includeStrings) { result.append('['); int count = getRangeCount(); @@ -524,7 +523,7 @@ public class UnicodeSet implements UnicodeMatcher { } } - if (strings.size() > 0) { + if (includeStrings && strings.size() > 0) { Iterator it = strings.iterator(); while (it.hasNext()) { result.append('{'); @@ -535,19 +534,8 @@ public class UnicodeSet implements UnicodeMatcher { return result.append(']'); } - /** - * Adds the specified range to this set if it is not already - * present. If this set already contains the specified range, - * the call leaves this set unchanged. If <code>end > start</code> - * then an empty range is added, leaving the set unchanged. - * - * @param start first character, inclusive, of range to be added - * to this set. - * @param end last character, inclusive, of range to be added - * to this set. - * @stable ICU 2.0 - */ - public UnicodeSet add(int start, int end) { + // for internal use, after checkFrozen has been called + private UnicodeSet add_unchecked(int start, int end) { if (start < MIN_VALUE || start > MAX_VALUE) { throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(start, 6)); } @@ -569,6 +557,11 @@ public class UnicodeSet implements UnicodeMatcher { * @stable ICU 2.0 */ public final UnicodeSet add(int c) { + return add_unchecked(c); + } + + // for internal use only, after checkFrozen has been called + private final UnicodeSet add_unchecked(int c) { if (c < MIN_VALUE || c > MAX_VALUE) { throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(c, 6)); } @@ -663,13 +656,12 @@ public class UnicodeSet implements UnicodeMatcher { * @stable ICU 2.0 */ public final UnicodeSet add(String s) { - int cp = getSingleCP(s); if (cp < 0) { strings.add(s); pat = null; } else { - add(cp, cp); + add_unchecked(cp, cp); } return this; } @@ -981,7 +973,6 @@ public class UnicodeSet implements UnicodeMatcher { */ void applyPattern(RuleCharacterIterator chars, SymbolTable symbols, StringBuffer rebuiltPat, int options) { - // Syntax characters: [ ] ^ - & { } // Recognized special forms for chars, sets: c-c s-s s&s @@ -992,7 +983,7 @@ public class UnicodeSet implements UnicodeMatcher { opts |= RuleCharacterIterator.SKIP_WHITESPACE; } - StringBuffer pat = new StringBuffer(), buf = null; + StringBuffer patBuf = new StringBuffer(), buf = null; boolean usePat = false; UnicodeSet scratch = null; Object backup = null; @@ -1049,13 +1040,13 @@ public class UnicodeSet implements UnicodeMatcher { } else { // Handle opening '[' delimiter mode = 1; - pat.append('['); + patBuf.append('['); backup = chars.getPos(backup); // prepare to backup c = chars.next(opts); literal = chars.isEscaped(); if (c == '^' && !literal) { invert = true; - pat.append('^'); + patBuf.append('^'); backup = chars.getPos(backup); // prepare to backup c = chars.next(opts); literal = chars.isEscaped(); @@ -1093,13 +1084,13 @@ public class UnicodeSet implements UnicodeMatcher { if (op != 0) { syntaxError(chars, "Char expected after operator"); } - add(lastChar, lastChar); - _appendToPat(pat, lastChar, false); + add_unchecked(lastChar, lastChar); + _appendToPat(patBuf, lastChar, false); lastItem = op = 0; } if (op == '-' || op == '&') { - pat.append(op); + patBuf.append(op); } if (nested == null) { @@ -1108,14 +1099,14 @@ public class UnicodeSet implements UnicodeMatcher { } switch (setMode) { case 1: - nested.applyPattern(chars, symbols, pat, options); + nested.applyPattern(chars, symbols, patBuf, options); break; case 2: chars.skipIgnored(opts); - nested.applyPropertyPattern(chars, pat, symbols); + nested.applyPropertyPattern(chars, patBuf, symbols); break; case 3: // `nested' already parsed - nested._toPattern(pat, false); + nested._toPattern(patBuf, false); break; } @@ -1158,17 +1149,17 @@ public class UnicodeSet implements UnicodeMatcher { switch (c) { case ']': if (lastItem == 1) { - add(lastChar, lastChar); - _appendToPat(pat, lastChar, false); + add_unchecked(lastChar, lastChar); + _appendToPat(patBuf, lastChar, false); } // Treat final trailing '-' as a literal if (op == '-') { - add(op, op); - pat.append(op); + add_unchecked(op, op); + patBuf.append(op); } else if (op == '&') { syntaxError(chars, "Trailing '&'"); } - pat.append(']'); + patBuf.append(']'); mode = 2; continue; case '-': @@ -1178,11 +1169,11 @@ public class UnicodeSet implements UnicodeMatcher { continue; } else { // Treat final trailing '-' as a literal - add(c, c); + add_unchecked(c, c); c = chars.next(opts); literal = chars.isEscaped(); if (c == ']' && !literal) { - pat.append("-]"); + patBuf.append("-]"); mode = 2; continue; } @@ -1202,8 +1193,8 @@ public class UnicodeSet implements UnicodeMatcher { syntaxError(chars, "Missing operand after operator"); } if (lastItem == 1) { - add(lastChar, lastChar); - _appendToPat(pat, lastChar, false); + add_unchecked(lastChar, lastChar); + _appendToPat(patBuf, lastChar, false); } lastItem = 0; if (buf == null) { @@ -1228,9 +1219,9 @@ public class UnicodeSet implements UnicodeMatcher { // we don't need to drop through to the further // processing add(buf.toString()); - pat.append('{'); - _appendToPat(pat, buf.toString(), false); - pat.append('}'); + patBuf.append('{'); + _appendToPat(patBuf, buf.toString(), false); + patBuf.append('}'); continue; case SymbolTable.SYMBOL_REF: // symbols nosymbols @@ -1250,12 +1241,12 @@ public class UnicodeSet implements UnicodeMatcher { } if (anchor && op == 0) { if (lastItem == 1) { - add(lastChar, lastChar); - _appendToPat(pat, lastChar, false); + add_unchecked(lastChar, lastChar); + _appendToPat(patBuf, lastChar, false); } - add(UnicodeMatcher.ETHER); + add_unchecked(UnicodeMatcher.ETHER); usePat = true; - pat.append(SymbolTable.SYMBOL_REF).append(']'); + patBuf.append(SymbolTable.SYMBOL_REF).append(']'); mode = 2; continue; } @@ -1281,14 +1272,14 @@ public class UnicodeSet implements UnicodeMatcher { // these are most likely typos. syntaxError(chars, "Invalid range"); } - add(lastChar, c); - _appendToPat(pat, lastChar, false); - pat.append(op); - _appendToPat(pat, c, false); + add_unchecked(lastChar, c); + _appendToPat(patBuf, lastChar, false); + patBuf.append(op); + _appendToPat(patBuf, c, false); lastItem = op = 0; } else { - add(lastChar, lastChar); - _appendToPat(pat, lastChar, false); + add_unchecked(lastChar, lastChar); + _appendToPat(patBuf, lastChar, false); lastChar = c; } break; @@ -1315,9 +1306,9 @@ public class UnicodeSet implements UnicodeMatcher { // Use the rebuilt pattern (pat) only if necessary. Prefer the // generated pattern. if (usePat) { - rebuiltPat.append(pat.toString()); + rebuiltPat.append(patBuf.toString()); } else { - _generatePattern(rebuiltPat, false); + _generatePattern(rebuiltPat, false, true); } } @@ -1590,7 +1581,9 @@ public class UnicodeSet implements UnicodeMatcher { private static class VersionFilter implements Filter { VersionInfo version; + VersionFilter(VersionInfo version) { this.version = version; } + public boolean contains(int ch) { VersionInfo v = UCharacter.getAge(ch); // Reference comparison ok; VersionInfo caches and reuses @@ -1600,18 +1593,28 @@ public class UnicodeSet implements UnicodeMatcher { } } - private static synchronized UnicodeSet getInclusions() { + private static synchronized UnicodeSet getInclusions(int src) { if (INCLUSIONS == null) { - UCharacterProperty property = UCharacterProperty.getInstance(); - INCLUSIONS = property.getInclusions(); + INCLUSIONS = new UnicodeSet[UCharacterProperty.SRC_COUNT]; } - return INCLUSIONS; + if(INCLUSIONS[src] == null) { + UnicodeSet incl = new UnicodeSet(); + switch(src) { + case UCharacterProperty.SRC_PROPSVEC: + UCharacterProperty.getInstance().upropsvec_addPropertyStarts(incl); + break; + default: + throw new IllegalStateException("UnicodeSet.getInclusions(unknown src "+src+")"); + } + INCLUSIONS[src] = incl; + } + return INCLUSIONS[src]; } /** * Generic filter-based scanning code for UCD property UnicodeSets. */ - private UnicodeSet applyFilter(Filter filter) { + private UnicodeSet applyFilter(Filter filter, int src) { // Walk through all Unicode characters, noting the start // and end of each range for which filter.contain(c) is // true. Add each range to a set. @@ -1629,7 +1632,7 @@ public class UnicodeSet implements UnicodeMatcher { clear(); int startHasProperty = -1; - UnicodeSet inclusions = getInclusions(); + UnicodeSet inclusions = getInclusions(src); int limitRange = inclusions.getRangeCount(); for (int j=0; j<limitRange; ++j) { @@ -1646,19 +1649,18 @@ public class UnicodeSet implements UnicodeMatcher { startHasProperty = ch; } } else if (startHasProperty >= 0) { - add(startHasProperty, ch-1); + add_unchecked(startHasProperty, ch-1); startHasProperty = -1; } } } if (startHasProperty >= 0) { - add(startHasProperty, 0x10FFFF); + add_unchecked(startHasProperty, 0x10FFFF); } return this; } - /** * Remove leading and trailing rule white space and compress * internal rule white space to a single space character. @@ -1686,10 +1688,6 @@ public class UnicodeSet implements UnicodeMatcher { return buf.toString(); } - //---------------------------------------------------------------- - // Property set API - //---------------------------------------------------------------- - /** * Modifies this set to contain those code points which have the * given value for the given property. Prior contents of this @@ -1699,22 +1697,21 @@ public class UnicodeSet implements UnicodeMatcher { * @param symbols if not null, then symbols are first called to see if a property * is available. If true, then everything else is skipped. * @return this set - * @draft ICU 3.2 - * @deprecated This is a draft API and might change in a future release of ICU. + * @stable ICU 3.2 */ public UnicodeSet applyPropertyAlias(String propertyAlias, String valueAlias, SymbolTable symbols) { - if (propertyAlias.equals("Age")) - { - // Must munge name, since - // VersionInfo.getInstance() does not do - // 'loose' matching. - VersionInfo version = VersionInfo.getInstance(mungeCharName(valueAlias)); - applyFilter(new VersionFilter(version)); - return this; - } - else - throw new IllegalArgumentException("Unsupported property"); + if (valueAlias.length() > 0) { + if (propertyAlias.equals("Age")) { + // Must munge name, since + // VersionInfo.getInstance() does not do + // 'loose' matching. + VersionInfo version = VersionInfo.getInstance(mungeCharName(valueAlias)); + applyFilter(new VersionFilter(version), UCharacterProperty.SRC_PROPSVEC); + return this; + } + } + throw new IllegalArgumentException("Unsupported property: " + propertyAlias); } /** @@ -1840,14 +1837,14 @@ public class UnicodeSet implements UnicodeMatcher { */ private void applyPropertyPattern(RuleCharacterIterator chars, StringBuffer rebuiltPat, SymbolTable symbols) { - String pat = chars.lookahead(); + String patStr = chars.lookahead(); ParsePosition pos = new ParsePosition(0); - applyPropertyPattern(pat, pos, symbols); + applyPropertyPattern(patStr, pos, symbols); if (pos.getIndex() == 0) { syntaxError(chars, "Invalid property pattern"); } chars.jumpahead(pos.getIndex()); - rebuiltPat.append(pat.substring(0, pos.getIndex())); + rebuiltPat.append(patStr.substring(0, pos.getIndex())); } //---------------------------------------------------------------- @@ -1860,8 +1857,9 @@ public class UnicodeSet implements UnicodeMatcher { * which UCharacterProperty.isRuleWhiteSpace() returns true, * unless they are quoted or escaped. This may be ORed together * with other selectors. - * @internal + * @stable ICU 3.8 */ public static final int IGNORE_SPACE = 1; } + diff --git a/jdk/src/share/classes/sun/text/normalizer/UnicodeSetIterator.java b/jdk/src/share/classes/sun/text/normalizer/UnicodeSetIterator.java index 4d558da18dd..0d8ffe84f2d 100644 --- a/jdk/src/share/classes/sun/text/normalizer/UnicodeSetIterator.java +++ b/jdk/src/share/classes/sun/text/normalizer/UnicodeSetIterator.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ - /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -167,8 +166,8 @@ public class UnicodeSetIterator { * @param set the set to iterate over. * @stable ICU 2.0 */ - public void reset(UnicodeSet set) { - this.set = set; + public void reset(UnicodeSet uset) { + set = uset; reset(); } @@ -213,8 +212,8 @@ public class UnicodeSetIterator { /** * @internal */ - protected void loadRange(int range) { - nextElement = set.getRangeStart(range); - endElement = set.getRangeEnd(range); + protected void loadRange(int aRange) { + nextElement = set.getRangeStart(aRange); + endElement = set.getRangeEnd(aRange); } } diff --git a/jdk/src/share/classes/sun/text/normalizer/Utility.java b/jdk/src/share/classes/sun/text/normalizer/Utility.java index 895097f13d2..7d8b33b9d59 100644 --- a/jdk/src/share/classes/sun/text/normalizer/Utility.java +++ b/jdk/src/share/classes/sun/text/normalizer/Utility.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ */ /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * @@ -36,10 +36,27 @@ package sun.text.normalizer; -// This class contains utility functions so testing not needed -///CLOVER:OFF public final class Utility { + /** + * Convenience utility to compare two Object[]s + * Ought to be in System. + * @param len the length to compare. + * The start indices and start+len must be valid. + */ + public final static boolean arrayRegionMatches(char[] source, int sourceStart, + char[] target, int targetStart, + int len) + { + int sourceEnd = sourceStart + len; + int delta = targetStart - sourceStart; + for (int i = sourceStart; i < sourceEnd; i++) { + if (source[i]!=target[i + delta]) + return false; + } + return true; + } + /** * Convert characters outside the range U+0020 to U+007F to * Unicode escapes, and convert backslash to a double backslash. @@ -344,7 +361,6 @@ public final class Utility { return false; } - //// for StringPrep /** * Similar to StringBuffer.getChars, version 1.3. * Since JDK 1.2 implements StringBuffer.getChars differently, this method @@ -356,7 +372,6 @@ public final class Utility { * @param dst char array to store the retrieved chars * @param dstBegin offset to the start of the destination char array to * store the retrieved chars - * @draft since ICU4J 2.0 */ public static void getChars(StringBuffer src, int srcBegin, int srcEnd, char dst[], int dstBegin) @@ -367,23 +382,4 @@ public final class Utility { src.getChars(srcBegin, srcEnd, dst, dstBegin); } - /** - * Convenience utility to compare two char[]s. - * @param len the length to compare. - * The start indices and start+len must be valid. - */ - public final static boolean arrayRegionMatches(char[] source, int sourceStart, - char[] target, int targetStart, - int len) - { - int sourceEnd = sourceStart + len; - int delta = targetStart - sourceStart; - for (int i = sourceStart; i < sourceEnd; i++) { - if (source[i] != target[i + delta]) - return false; - } - return true; - } - } -///CLOVER:ON diff --git a/jdk/src/share/classes/sun/text/normalizer/VersionInfo.java b/jdk/src/share/classes/sun/text/normalizer/VersionInfo.java index e1a0d92ddb5..2b0f7c7918b 100644 --- a/jdk/src/share/classes/sun/text/normalizer/VersionInfo.java +++ b/jdk/src/share/classes/sun/text/normalizer/VersionInfo.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ */ /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * * * * The original version of this source code and documentation is copyrighted * * and owned by IBM, These materials are provided under terms of a License * diff --git a/jdk/src/share/classes/sun/text/resources/ubidi.icu b/jdk/src/share/classes/sun/text/resources/ubidi.icu new file mode 100644 index 00000000000..e4a2d819407 Binary files /dev/null and b/jdk/src/share/classes/sun/text/resources/ubidi.icu differ diff --git a/jdk/src/share/classes/sun/text/resources/unorm.icu b/jdk/src/share/classes/sun/text/resources/unorm.icu index 5d56aa22fc2..96560e6dcfb 100644 Binary files a/jdk/src/share/classes/sun/text/resources/unorm.icu and b/jdk/src/share/classes/sun/text/resources/unorm.icu differ diff --git a/jdk/src/share/classes/sun/text/resources/uprops.icu b/jdk/src/share/classes/sun/text/resources/uprops.icu index 610ad5abee0..0140aa29928 100644 Binary files a/jdk/src/share/classes/sun/text/resources/uprops.icu and b/jdk/src/share/classes/sun/text/resources/uprops.icu differ diff --git a/jdk/src/share/lib/security/java.policy b/jdk/src/share/lib/security/java.policy index bcb5a6c4d86..3312bdf92f2 100644 --- a/jdk/src/share/lib/security/java.policy +++ b/jdk/src/share/lib/security/java.policy @@ -15,7 +15,8 @@ grant { // It is strongly recommended that you either remove this permission // from this policy file or further restrict it to code sources // that you specify, because Thread.stop() is potentially unsafe. - // See "http://java.sun.com/notes" for more information. + // See the API specification of java.lang.Thread.stop() for more + // information. permission java.lang.RuntimePermission "stopThread"; // allows anyone to listen on un-privileged ports diff --git a/jdk/src/share/native/java/lang/ClassLoader.c b/jdk/src/share/native/java/lang/ClassLoader.c index 6f5960af5bf..bedf87ce7e6 100644 --- a/jdk/src/share/native/java/lang/ClassLoader.c +++ b/jdk/src/share/native/java/lang/ClassLoader.c @@ -1,5 +1,5 @@ /* - * Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -437,3 +437,21 @@ Java_java_lang_ClassLoader_00024NativeLibrary_find (*env)->ReleaseStringUTFChars(env, name, cname); return res; } + +JNIEXPORT jobject JNICALL +Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index) +{ + jobjectArray jcallerStack; + int len; + + jcallerStack = JVM_GetClassContext(env); + if ((*env)->ExceptionCheck(env)) { + return NULL; + } + len = (*env)->GetArrayLength(env, jcallerStack); + if (index < len) { + return (*env)->GetObjectArrayElement(env, jcallerStack, index); + } + return NULL; +} + diff --git a/jdk/src/share/native/java/util/zip/zip_util.c b/jdk/src/share/native/java/util/zip/zip_util.c index 3b00b9500ac..89f52ae3bcc 100644 --- a/jdk/src/share/native/java/util/zip/zip_util.c +++ b/jdk/src/share/native/java/util/zip/zip_util.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -135,11 +135,6 @@ ZFILE_Close(ZFILE zfd) { #endif } -static jlong -ZFILE_Lseek(ZFILE zfd, off_t offset, int whence) { - return IO_Lseek(zfd, offset, whence); -} - static int ZFILE_read(ZFILE zfd, char *buf, jint nbytes) { #ifdef WIN32 @@ -216,7 +211,7 @@ readFully(ZFILE zfd, void *buf, jlong len) { static int readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset) { - if (ZFILE_Lseek(zfd, (off_t) offset, SEEK_SET) == -1) { + if (IO_Lseek(zfd, offset, SEEK_SET) == -1) { return -1; /* lseek failure. */ } @@ -317,6 +312,38 @@ findEND(jzfile *zip, void *endbuf) return -1; /* END header not found */ } +/* + * Searches for the ZIP64 end of central directory (END) header. The + * contents of the ZIP64 END header will be read and placed in end64buf. + * Returns the file position of the ZIP64 END header, otherwise returns + * -1 if the END header was not found or an error occurred. + * + * The ZIP format specifies the "position" of each related record as + * ... + * [central directory] + * [zip64 end of central directory record] + * [zip64 end of central directory locator] + * [end of central directory record] + * + * The offset of zip64 end locator can be calculated from endpos as + * "endpos - ZIP64_LOCHDR". + * The "offset" of zip64 end record is stored in zip64 end locator. + */ +static jlong +findEND64(jzfile *zip, void *end64buf, jlong endpos) +{ + char loc64[ZIP64_LOCHDR]; + jlong end64pos; + if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) { + return -1; // end64 locator not found + } + end64pos = ZIP64_LOCOFF(loc64); + if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) { + return -1; // end64 record not found + } + return end64pos; +} + /* * Returns a hash code value for a C-style NUL-terminated string. */ @@ -468,7 +495,7 @@ static jlong readCEN(jzfile *zip, jint knownTotal) { /* Following are unsigned 32-bit */ - jlong endpos, cenpos, cenlen; + jlong endpos, end64pos, cenpos, cenlen, cenoff; /* Following are unsigned 16-bit */ jint total, tablelen, i, j; unsigned char *cenbuf = NULL; @@ -476,9 +503,10 @@ readCEN(jzfile *zip, jint knownTotal) unsigned char *cp; #ifdef USE_MMAP static jlong pagesize; - off_t offset; + jlong offset; #endif unsigned char endbuf[ENDHDR]; + jint endhdrlen = ENDHDR; jzcell *entries; jint *table; @@ -495,13 +523,27 @@ readCEN(jzfile *zip, jint knownTotal) /* Get position and length of central directory */ cenlen = ENDSIZ(endbuf); + cenoff = ENDOFF(endbuf); + total = ENDTOT(endbuf); + if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL || + total == ZIP64_MAGICCOUNT) { + unsigned char end64buf[ZIP64_ENDHDR]; + if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { + cenlen = ZIP64_ENDSIZ(end64buf); + cenoff = ZIP64_ENDOFF(end64buf); + total = (jint)ZIP64_ENDTOT(end64buf); + endpos = end64pos; + endhdrlen = ZIP64_ENDHDR; + } + } + if (cenlen > endpos) ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); cenpos = endpos - cenlen; /* Get position of first local file (LOC) header, taking into * account that there may be a stub prefixed to the zip file. */ - zip->locpos = cenpos - ENDOFF(endbuf); + zip->locpos = cenpos - cenoff; if (zip->locpos < 0) ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); @@ -532,9 +574,9 @@ readCEN(jzfile *zip, jint knownTotal) out the page size in order to make offset to be multiples of page size. */ - zip->mlen = cenpos - offset + cenlen + ENDHDR; + zip->mlen = cenpos - offset + cenlen + endhdrlen; zip->offset = offset; - mappedAddr = mmap(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, offset); + mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : (unsigned char*)mappedAddr; @@ -556,8 +598,13 @@ readCEN(jzfile *zip, jint knownTotal) * is a 2-byte field, but we (and other zip implementations) * support approx. 2**31 entries, we do not trust ENDTOT, but * treat it only as a strong hint. When we call ourselves - * recursively, knownTotal will have the "true" value. */ - total = (knownTotal != -1) ? knownTotal : ENDTOT(endbuf); + * recursively, knownTotal will have the "true" value. + * + * Keep this path alive even with the Zip64 END support added, just + * for zip files that have more than 0xffff entries but don't have + * the Zip64 enabled. + */ + total = (knownTotal != -1) ? knownTotal : total; entries = zip->entries = calloc(total, sizeof(entries[0])); tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions table = zip->table = malloc(tablelen * sizeof(table[0])); @@ -720,7 +767,7 @@ ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) return NULL; } - len = zip->len = ZFILE_Lseek(zfd, 0, SEEK_END); + len = zip->len = IO_Lseek(zfd, 0, SEEK_END); if (len <= 0) { if (len == 0) { /* zip file is empty */ if (pmsg) { @@ -859,6 +906,7 @@ typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint; static jzentry * newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) { + jlong locoff; jint nlen, elen, clen; jzentry *ze; char *cen; @@ -885,18 +933,55 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) ze->size = CENLEN(cen); ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); ze->crc = CENCRC(cen); - ze->pos = -(zip->locpos + CENOFF(cen)); + locoff = CENOFF(cen); + ze->pos = -(zip->locpos + locoff); if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; memcpy(ze->name, cen + CENHDR, nlen); ze->name[nlen] = '\0'; if (elen > 0) { + char *extra = cen + CENHDR + nlen; + /* This entry has "extra" data */ if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; ze->extra[0] = (unsigned char) elen; ze->extra[1] = (unsigned char) (elen >> 8); - memcpy(ze->extra+2, cen + CENHDR + nlen, elen); + memcpy(ze->extra+2, extra, elen); + if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL || + locoff == ZIP64_MAGICVAL) { + jint off = 0; + while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data + jint sz = SH(extra, off + 2); + if (SH(extra, off) == ZIP64_EXTID) { + off += 4; + if (ze->size == ZIP64_MAGICVAL) { + // if invalid zip64 extra fields, just skip + if (sz < 8 || (off + 8) > elen) + break; + ze->size = LL(extra, off); + sz -= 8; + off += 8; + } + if (ze->csize == ZIP64_MAGICVAL) { + if (sz < 8 || (off + 8) > elen) + break; + ze->csize = LL(extra, off); + sz -= 8; + off += 8; + } + if (locoff == ZIP64_MAGICVAL) { + if (sz < 8 || (off + 8) > elen) + break; + ze->pos = -(zip->locpos + LL(extra, off)); + sz -= 8; + off += 8; + } + break; + } + off += (sz + 4); + } + } } if (clen > 0) { diff --git a/jdk/src/share/native/java/util/zip/zip_util.h b/jdk/src/share/native/java/util/zip/zip_util.h index 5fdebaf1347..7ad11715e5a 100644 --- a/jdk/src/share/native/java/util/zip/zip_util.h +++ b/jdk/src/share/native/java/util/zip/zip_util.h @@ -1,5 +1,5 @@ /* - * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,9 +38,13 @@ #define CENSIG 0x02014b50L /* "PK\001\002" */ #define ENDSIG 0x06054b50L /* "PK\005\006" */ +#define ZIP64_ENDSIG 0x06064b50L /* "PK\006\006" */ +#define ZIP64_LOCSIG 0x07064b50L /* "PK\006\007" */ + /* * Header sizes including signatures */ + #ifdef USE_MMAP #define SIGSIZ 4 #endif @@ -49,12 +53,22 @@ #define CENHDR 46 #define ENDHDR 22 +#define ZIP64_ENDHDR 56 // ZIP64 end header size +#define ZIP64_LOCHDR 20 // ZIP64 end loc header size +#define ZIP64_EXTHDR 24 // EXT header size +#define ZIP64_EXTID 1 // Extra field Zip64 header ID + +#define ZIP64_MAGICVAL 0xffffffffLL +#define ZIP64_MAGICCOUNT 0xffff + + /* * Header field access macros */ #define CH(b, n) (((unsigned char *)(b))[n]) #define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) -#define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) +#define LG(b, n) ((SH(b, n) | (SH(b, n+2) << 16)) &0xffffffffUL) +#define LL(b, n) (((jlong)LG(b, n)) | (((jlong)LG(b, n+4)) << 32)) #define GETSIG(b) LG(b, 0) /* @@ -105,6 +119,26 @@ #define ENDOFF(b) LG(b, 16) /* central directory offset */ #define ENDCOM(b) SH(b, 20) /* size of zip file comment */ +/* + * Macros for getting Zip64 end of central directory header fields + */ +#define ZIP64_ENDLEN(b) LL(b, 4) /* size of zip64 end of central dir */ +#define ZIP64_ENDVEM(b) SH(b, 12) /* version made by */ +#define ZIP64_ENDVER(b) SH(b, 14) /* version needed to extract */ +#define ZIP64_ENDNMD(b) LG(b, 16) /* number of this disk */ +#define ZIP64_ENDDSK(b) LG(b, 20) /* disk number of start */ +#define ZIP64_ENDTOD(b) LL(b, 24) /* total number of entries on this disk */ +#define ZIP64_ENDTOT(b) LL(b, 32) /* total number of entries */ +#define ZIP64_ENDSIZ(b) LL(b, 40) /* central directory size in bytes */ +#define ZIP64_ENDOFF(b) LL(b, 48) /* offset of first CEN header */ + +/* + * Macros for getting Zip64 end of central directory locator fields + */ +#define ZIP64_LOCDSK(b) LG(b, 4) /* disk number start */ +#define ZIP64_LOCOFF(b) LL(b, 8) /* offset of zip64 end */ +#define ZIP64_LOCTOT(b) LG(b, 16) /* total number of disks */ + /* * Supported compression methods */ @@ -145,7 +179,7 @@ typedef struct jzentry { /* Zip file entry */ */ typedef struct jzcell { unsigned int hash; /* 32 bit hashcode on name */ - unsigned int cenpos; /* Offset of central directory file header */ + jlong cenpos; /* Offset of central directory file header */ unsigned int next; /* hash chain: index into jzfile->entries */ } jzcell; @@ -174,7 +208,7 @@ typedef struct jzfile { /* Zip file */ #ifdef USE_MMAP unsigned char *maddr; /* beginning address of the CEN & ENDHDR */ jlong mlen; /* length (in bytes) mmaped */ - off_t offset; /* offset of the mmapped region from the + jlong offset; /* offset of the mmapped region from the start of the file. */ #else cencache cencache; /* CEN header cache */ diff --git a/jdk/src/share/native/java/util/zip/zlib-1.1.3/zlib.h b/jdk/src/share/native/java/util/zip/zlib-1.1.3/zlib.h index 9576715b2fa..00fdf06007d 100644 --- a/jdk/src/share/native/java/util/zip/zlib-1.1.3/zlib.h +++ b/jdk/src/share/native/java/util/zip/zlib-1.1.3/zlib.h @@ -106,11 +106,11 @@ struct internal_state; typedef struct z_stream_s { Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ + long long total_in; /* total nb of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ + long long total_out; /* total nb of bytes output so far */ char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ diff --git a/jdk/src/share/native/sun/awt/image/dither.c b/jdk/src/share/native/sun/awt/image/dither.c index a935d6766f6..cb2303e76d7 100644 --- a/jdk/src/share/native/sun/awt/image/dither.c +++ b/jdk/src/share/native/sun/awt/image/dither.c @@ -169,6 +169,7 @@ initCubemap(int* cmap, int cubesize = cube_dim * cube_dim * cube_dim; unsigned char *useFlags; unsigned char *newILut = (unsigned char*)malloc(cubesize); + int cmap_mid = (cmap_len >> 1) + (cmap_len & 0x1); if (newILut) { useFlags = (unsigned char *)calloc(cubesize, 1); @@ -188,7 +189,7 @@ initCubemap(int* cmap, currentState.iLUT = newILut; currentState.rgb = (unsigned short *) - malloc(256 * sizeof(unsigned short)); + malloc(cmap_len * sizeof(unsigned short)); if (currentState.rgb == NULL) { free(newILut); free(useFlags); @@ -199,7 +200,7 @@ initCubemap(int* cmap, } currentState.indices = (unsigned char *) - malloc(256 * sizeof(unsigned char)); + malloc(cmap_len * sizeof(unsigned char)); if (currentState.indices == NULL) { free(currentState.rgb); free(newILut); @@ -210,18 +211,18 @@ initCubemap(int* cmap, return NULL; } - for (i = 0; i < 128; i++) { + for (i = 0; i < cmap_mid; i++) { unsigned short rgb; int pixel = cmap[i]; rgb = (pixel & 0x00f80000) >> 9; rgb |= (pixel & 0x0000f800) >> 6; rgb |= (pixel & 0xf8) >> 3; INSERTNEW(currentState, rgb, i); - pixel = cmap[255-i]; + pixel = cmap[cmap_len - i - 1]; rgb = (pixel & 0x00f80000) >> 9; rgb |= (pixel & 0x0000f800) >> 6; rgb |= (pixel & 0xf8) >> 3; - INSERTNEW(currentState, rgb, 255-i); + INSERTNEW(currentState, rgb, cmap_len - i - 1); } if (!recurseLevel(¤tState)) { diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index 8c30b5ce69e..0a99c3fdb93 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -396,7 +396,7 @@ static imageIODataPtr initImageioData (JNIEnv *env, data->jpegObj = cinfo; cinfo->client_data = data; -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("new structures: data is %p, cinfo is %p\n", data, cinfo); #endif @@ -673,7 +673,7 @@ static int setQTables(JNIEnv *env, j_decompress_ptr decomp; qlen = (*env)->GetArrayLength(env, qtables); -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("in setQTables, qlen = %d, write is %d\n", qlen, write); #endif for (i = 0; i < qlen; i++) { @@ -876,7 +876,7 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo) return FALSE; } -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("Filling input buffer, remaining skip is %ld, ", sb->remaining_skip); printf("Buffer length is %d\n", sb->bufferLength); @@ -906,7 +906,7 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo) cinfo->err->error_exit((j_common_ptr) cinfo); } -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("Buffer filled. ret = %d\n", ret); #endif /* @@ -917,7 +917,7 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo) */ if (ret <= 0) { jobject reader = data->imageIOobj; -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("YO! Early EOI! ret = %d\n", ret); #endif RELEASE_ARRAYS(env, data, src->next_input_byte); @@ -1216,21 +1216,24 @@ read_icc_profile (JNIEnv *env, j_decompress_ptr cinfo) { jpeg_saved_marker_ptr marker; int num_markers = 0; + int num_found_markers = 0; int seq_no; JOCTET *icc_data; + JOCTET *dst_ptr; unsigned int total_length; #define MAX_SEQ_NO 255 // sufficient since marker numbers are bytes - char marker_present[MAX_SEQ_NO+1]; // 1 if marker found - unsigned int data_length[MAX_SEQ_NO+1]; // size of profile data in marker - unsigned int data_offset[MAX_SEQ_NO+1]; // offset for data in marker + jpeg_saved_marker_ptr icc_markers[MAX_SEQ_NO + 1]; + int first; // index of the first marker in the icc_markers array + int last; // index of the last marker in the icc_markers array jbyteArray data = NULL; /* This first pass over the saved markers discovers whether there are * any ICC markers and verifies the consistency of the marker numbering. */ - for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++) - marker_present[seq_no] = 0; + for (seq_no = 0; seq_no <= MAX_SEQ_NO; seq_no++) + icc_markers[seq_no] = NULL; + for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { if (marker_is_icc(marker)) { @@ -1242,37 +1245,58 @@ read_icc_profile (JNIEnv *env, j_decompress_ptr cinfo) return NULL; } seq_no = GETJOCTET(marker->data[12]); - if (seq_no <= 0 || seq_no > num_markers) { + + /* Some third-party tools produce images with profile chunk + * numeration started from zero. It is inconsistent with ICC + * spec, but seems to be recognized by majority of image + * processing tools, so we should be more tolerant to this + * departure from the spec. + */ + if (seq_no < 0 || seq_no > num_markers) { JNU_ThrowByName(env, "javax/imageio/IIOException", "Invalid icc profile: bad sequence number"); return NULL; } - if (marker_present[seq_no]) { + if (icc_markers[seq_no] != NULL) { JNU_ThrowByName(env, "javax/imageio/IIOException", "Invalid icc profile: duplicate sequence numbers"); return NULL; } - marker_present[seq_no] = 1; - data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN; + icc_markers[seq_no] = marker; + num_found_markers ++; } } if (num_markers == 0) return NULL; // There is no profile - /* Check for missing markers, count total space needed, - * compute offset of each marker's part of the data. - */ + if (num_markers != num_found_markers) { + JNU_ThrowByName(env, "javax/imageio/IIOException", + "Invalid icc profile: invalid number of icc markers"); + return NULL; + } + first = icc_markers[0] ? 0 : 1; + last = num_found_markers + first; + + /* Check for missing markers, count total space needed. + */ total_length = 0; - for (seq_no = 1; seq_no <= num_markers; seq_no++) { - if (marker_present[seq_no] == 0) { + for (seq_no = first; seq_no < last; seq_no++) { + unsigned int length; + if (icc_markers[seq_no] == NULL) { JNU_ThrowByName(env, "javax/imageio/IIOException", "Invalid icc profile: missing sequence number"); return NULL; } - data_offset[seq_no] = total_length; - total_length += data_length[seq_no]; + /* check the data length correctness */ + length = icc_markers[seq_no]->data_length; + if (ICC_OVERHEAD_LEN > length || length > MAX_BYTES_IN_MARKER) { + JNU_ThrowByName(env, "javax/imageio/IIOException", + "Invalid icc profile: invalid data length"); + return NULL; + } + total_length += (length - ICC_OVERHEAD_LEN); } if (total_length <= 0) { @@ -1301,19 +1325,14 @@ read_icc_profile (JNIEnv *env, j_decompress_ptr cinfo) } /* and fill it in */ - for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { - if (marker_is_icc(marker)) { - JOCTET FAR *src_ptr; - JOCTET *dst_ptr; - unsigned int length; - seq_no = GETJOCTET(marker->data[12]); - dst_ptr = icc_data + data_offset[seq_no]; - src_ptr = marker->data + ICC_OVERHEAD_LEN; - length = data_length[seq_no]; - while (length--) { - *dst_ptr++ = *src_ptr++; - } - } + dst_ptr = icc_data; + for (seq_no = first; seq_no < last; seq_no++) { + JOCTET FAR *src_ptr = icc_markers[seq_no]->data + ICC_OVERHEAD_LEN; + unsigned int length = + icc_markers[seq_no]->data_length - ICC_OVERHEAD_LEN; + + memcpy(dst_ptr, src_ptr, length); + dst_ptr += length; } /* finally, unpin the array */ @@ -1530,6 +1549,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader j_decompress_ptr cinfo; struct jpeg_source_mgr *src; sun_jpeg_error_ptr jerr; + jbyteArray profileData = NULL; if (data == NULL) { JNU_ThrowByName(env, @@ -1557,7 +1577,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader return retval; } -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("In readImageHeader, data is %p cinfo is %p\n", data, cinfo); printf("clearFirst is %d\n", clearFirst); #endif @@ -1584,7 +1604,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader if (ret == JPEG_HEADER_TABLES_ONLY) { retval = JNI_TRUE; imageio_term_source(cinfo); // Pushback remaining buffer contents -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("just read tables-only image; q table 0 at %p\n", cinfo->quant_tbl_ptrs[0]); #endif @@ -1691,6 +1711,14 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader } } RELEASE_ARRAYS(env, data, src->next_input_byte); + + /* read icc profile data */ + profileData = read_icc_profile(env, cinfo); + + if ((*env)->ExceptionCheck(env)) { + return retval; + } + (*env)->CallVoidMethod(env, this, JPEGImageReader_setImageDataID, cinfo->image_width, @@ -1698,7 +1726,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader cinfo->jpeg_color_space, cinfo->out_color_space, cinfo->num_components, - read_icc_profile(env, cinfo)); + profileData); if (reset) { jpeg_abort_decompress(cinfo); } @@ -1827,7 +1855,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage (*env)->ReleaseIntArrayElements(env, srcBands, body, JNI_ABORT); -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("---- in reader.read ----\n"); printf("numBands is %d\n", numBands); printf("bands array: "); @@ -2487,7 +2515,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeTables data->streamBuf.suspendable = FALSE; if (qtables != NULL) { -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("in writeTables: qtables not NULL\n"); #endif setQTables(env, (j_common_ptr) cinfo, qtables, TRUE); @@ -2763,7 +2791,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage cinfo->restart_interval = restartInterval; -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("writer setup complete, starting compressor\n"); #endif @@ -2812,13 +2840,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage for (i = 0; i < numBands; i++) { if (scale !=NULL && scale[i] != NULL) { *out++ = scale[i][*(in+i)]; -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG if (in == data->pixelBuf.buf.bp){ // Just the first pixel printf("in %d -> out %d, ", *(in+i), *(out-i-1)); } #endif -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG if (in == data->pixelBuf.buf.bp){ // Just the first pixel printf("\n"); } diff --git a/jdk/src/share/native/sun/font/freetypeScaler.c b/jdk/src/share/native/sun/font/freetypeScaler.c index 59c1a180c29..4028d4d97c4 100644 --- a/jdk/src/share/native/sun/font/freetypeScaler.c +++ b/jdk/src/share/native/sun/font/freetypeScaler.c @@ -394,12 +394,14 @@ static int setupFTContext(JNIEnv *env, scalerInfo->env = env; scalerInfo->font2D = font2D; - FT_Set_Transform(scalerInfo->face, &context->transform, NULL); + if (context != NULL) { + FT_Set_Transform(scalerInfo->face, &context->transform, NULL); - errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72); + errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72); - if (errCode == 0) { - errCode = FT_Activate_Size(scalerInfo->face->size); + if (errCode == 0) { + errCode = FT_Activate_Size(scalerInfo->face->size); + } } return errCode; @@ -885,6 +887,14 @@ Java_sun_font_FreetypeFontScaler_disposeNativeScaler( JNIEnv *env, jobject scaler, jlong pScaler) { FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); + /* Freetype functions *may* cause callback to java + that can use cached values. Make sure our cache is up to date. + NB: scaler context is not important at this point, can use NULL. */ + int errCode = setupFTContext(env, scaler, scalerInfo, NULL); + if (errCode) { + return; + } + freeNativeResources(env, scalerInfo); } @@ -932,12 +942,21 @@ Java_sun_font_FreetypeFontScaler_getGlyphCodeNative( JNIEnv *env, jobject scaler, jlong pScaler, jchar charCode) { FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); + int errCode; if (scaler == NULL || scalerInfo->face == NULL) { /* bad/null scaler */ invalidateJavaScaler(env, scaler, scalerInfo); return 0; } + /* Freetype functions *may* cause callback to java + that can use cached values. Make sure our cache is up to date. + Scaler context is not important here, can use NULL. */ + errCode = setupFTContext(env, scaler, scalerInfo, NULL); + if (errCode) { + return 0; + } + return FT_Get_Char_Index(scalerInfo->face, charCode); } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c index 0573a021876..42a5cc23f30 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c @@ -30,6 +30,41 @@ #include "Disposer.h" #include "lcms.h" + +#define ALIGNLONG(x) (((x)+3) & ~(3)) // Aligns to DWORD boundary + +#ifdef USE_BIG_ENDIAN +#define AdjustEndianess32(a) +#else + +static +void AdjustEndianess32(LPBYTE pByte) +{ + BYTE temp1; + BYTE temp2; + + temp1 = *pByte++; + temp2 = *pByte++; + *(pByte-1) = *pByte; + *pByte++ = temp2; + *(pByte-3) = *pByte; + *pByte = temp1; +} + +#endif + +// Transports to properly encoded values - note that icc profiles does use +// big endian notation. + +static +icInt32Number TransportValue32(icInt32Number Value) +{ + icInt32Number Temp = Value; + + AdjustEndianess32((LPBYTE) &Temp); + return Temp; +} + #define SigMake(a,b,c,d) \ ( ( ((int) ((unsigned char) (a))) << 24) | \ ( ((int) ((unsigned char) (b))) << 16) | \ @@ -182,6 +217,8 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfile sProf.pf = cmsOpenProfileFromMem((LPVOID)dataArray, (DWORD) dataSize); + (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); + if (sProf.pf == NULL) { JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); } @@ -337,6 +374,10 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData return; } +// Modify data for a tag in a profile +LCMSBOOL LCMSEXPORT _cmsModifyTagData(cmsHPROFILE hProfile, + icTagSignature sig, void *data, size_t size); + /* * Class: sun_java2d_cmm_lcms_LCMS * Method: setTagData @@ -345,7 +386,23 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) { - fprintf(stderr, "setTagData operation is not implemented"); + cmsHPROFILE profile; + storeID_t sProf; + jbyte* dataArray; + int tagSize; + + if (tagSig == SigHead) { + J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_setTagData on icSigHead not " + "permitted"); + return; + } + + sProf.j = id; + profile = (cmsHPROFILE) sProf.pf; + dataArray = (*env)->GetByteArrayElements(env, data, 0); + tagSize =(*env)->GetArrayLength(env, data); + _cmsModifyTagData(profile, (icTagSignature) tagSig, dataArray, tagSize); + (*env)->ReleaseByteArrayElements(env, data, dataArray, 0); } void* getILData (JNIEnv *env, jobject img, jint* pDataType, @@ -507,3 +564,174 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J"); } + +LCMSBOOL _cmsModifyTagData(cmsHPROFILE hProfile, icTagSignature sig, + void *data, size_t size) +{ + LCMSBOOL isNew; + int i, idx, delta, count; + LPBYTE padChars[3] = {0, 0, 0}; + LPBYTE beforeBuf, afterBuf, ptr; + size_t beforeSize, afterSize; + icUInt32Number profileSize, temp; + LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; + + isNew = FALSE; + idx = _cmsSearchTag(Icc, sig, FALSE); + if (idx < 0) { + isNew = TRUE; + idx = Icc->TagCount++; + if (Icc->TagCount >= MAX_TABLE_TAG) { + J2dRlsTraceLn1(J2D_TRACE_ERROR, "_cmsModifyTagData: Too many tags " + "(%d)\n", Icc->TagCount); + Icc->TagCount = MAX_TABLE_TAG-1; + return FALSE; + } + } + + /* Read in size from header */ + Icc->Seek(Icc, 0); + Icc->Read(&profileSize, sizeof(icUInt32Number), 1, Icc); + AdjustEndianess32((LPBYTE) &profileSize); + + /* Compute the change in profile size */ + if (isNew) { + delta = sizeof(icTag) + ALIGNLONG(size); + } else { + delta = ALIGNLONG(size) - ALIGNLONG(Icc->TagSizes[idx]); + } + /* Add tag to internal structures */ + ptr = malloc(size); + if (ptr == NULL) { + if(isNew) { + Icc->TagCount--; + } + J2dRlsTraceLn(J2D_TRACE_ERROR, "_cmsModifyTagData: ptr == NULL"); + return FALSE; + } + + if (!Icc->Grow(Icc, delta)) { + free(ptr); + if(isNew) { + Icc->TagCount--; + } + J2dRlsTraceLn(J2D_TRACE_ERROR, + "_cmsModifyTagData: Icc->Grow() == FALSE"); + return FALSE; + } + + /* Compute size of tag data before/after the modified tag */ + beforeSize = ((isNew)?profileSize:Icc->TagOffsets[idx]) - + Icc->TagOffsets[0]; + if (Icc->TagCount == (idx + 1)) { + afterSize = 0; + } else { + afterSize = profileSize - Icc->TagOffsets[idx+1]; + } + /* Make copies of the data before/after the modified tag */ + if (beforeSize > 0) { + beforeBuf = malloc(beforeSize); + if (!beforeBuf) { + if(isNew) { + Icc->TagCount--; + } + free(ptr); + J2dRlsTraceLn(J2D_TRACE_ERROR, + "_cmsModifyTagData: beforeBuf == NULL"); + return FALSE; + } + Icc->Seek(Icc, Icc->TagOffsets[0]); + Icc->Read(beforeBuf, beforeSize, 1, Icc); + } + + if (afterSize > 0) { + afterBuf = malloc(afterSize); + if (!afterBuf) { + free(ptr); + if(isNew) { + Icc->TagCount--; + } + if (beforeSize > 0) { + free(beforeBuf); + } + J2dRlsTraceLn(J2D_TRACE_ERROR, + "_cmsModifyTagData: afterBuf == NULL"); + return FALSE; + } + Icc->Seek(Icc, Icc->TagOffsets[idx+1]); + Icc->Read(afterBuf, afterSize, 1, Icc); + } + + CopyMemory(ptr, data, size); + Icc->TagSizes[idx] = size; + Icc->TagNames[idx] = sig; + if (Icc->TagPtrs[idx]) { + free(Icc->TagPtrs[idx]); + } + Icc->TagPtrs[idx] = ptr; + if (isNew) { + Icc->TagOffsets[idx] = profileSize; + } + + + /* Update the profile size in the header */ + profileSize += delta; + Icc->Seek(Icc, 0); + temp = TransportValue32(profileSize); + Icc->Write(Icc, sizeof(icUInt32Number), &temp); + + + /* Adjust tag offsets: if the tag is new, we must account + for the new tag table entry; otherwise, only those tags after + the modified tag are changed (by delta) */ + if (isNew) { + for (i = 0; i < Icc->TagCount; ++i) { + Icc->TagOffsets[i] += sizeof(icTag); + } + } else { + for (i = idx+1; i < Icc->TagCount; ++i) { + Icc->TagOffsets[i] += delta; + } + } + + /* Write out a new tag table */ + count = 0; + for (i = 0; i < Icc->TagCount; ++i) { + if (Icc->TagNames[i] != 0) { + ++count; + } + } + Icc->Seek(Icc, sizeof(icHeader)); + temp = TransportValue32(count); + Icc->Write(Icc, sizeof(icUInt32Number), &temp); + + for (i = 0; i < Icc->TagCount; ++i) { + if (Icc->TagNames[i] != 0) { + icTag tag; + tag.sig = TransportValue32(Icc->TagNames[i]); + tag.offset = TransportValue32((icInt32Number) Icc->TagOffsets[i]); + tag.size = TransportValue32((icInt32Number) Icc->TagSizes[i]); + Icc->Write(Icc, sizeof(icTag), &tag); + } + } + + /* Write unchanged data before the modified tag */ + if (beforeSize > 0) { + Icc->Write(Icc, beforeSize, beforeBuf); + free(beforeBuf); + } + + /* Write modified tag data */ + Icc->Write(Icc, size, data); + if (size % 4) { + Icc->Write(Icc, 4 - (size % 4), padChars); + } + + /* Write unchanged data after the modified tag */ + if (afterSize > 0) { + Icc->Write(Icc, afterSize, afterBuf); + free(afterBuf); + } + + return TRUE; +} diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c index 9aa971cb878..c560470c499 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -51,7 +51,7 @@ -// CIECAM 02 appearance model +// CIECAM 02 appearance model. Many thanks to Jordi Vilar for the debugging. #include "lcms.h" @@ -196,6 +196,10 @@ CAM02COLOR NonlinearCompression(CAM02COLOR clr, LPcmsCIECAM02 pMod) clr.RGBpa[i] = (400.0 * temp) / (temp + 27.13) + 0.1; } } + + clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] + + (clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb; + return clr; } @@ -249,9 +253,6 @@ CAM02COLOR ComputeCorrelates(CAM02COLOR clr, LPcmsCIECAM02 pMod) clr.H = 300 + ((100*((clr.h - 237.53)/1.2)) / temp); } - clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] + - (clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb; - clr.J = 100.0 * pow((clr.A / pMod->adoptedWhite.A), (pMod->c * pMod->z)); @@ -395,7 +396,7 @@ LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC) LPcmsCIECAM02 lpMod; - if((lpMod = (LPcmsCIECAM02) malloc(sizeof(cmsCIECAM02))) == NULL) { + if((lpMod = (LPcmsCIECAM02) _cmsMalloc(sizeof(cmsCIECAM02))) == NULL) { return (LCMSHANDLE) NULL; } @@ -449,14 +450,19 @@ LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC) lpMod -> z = compute_z(lpMod); lpMod -> Nbb = computeNbb(lpMod); lpMod -> FL = computeFL(lpMod); + + if (lpMod -> D == D_CALCULATE || + lpMod -> D == D_CALCULATE_DISCOUNT) { + lpMod -> D = computeD(lpMod); + } + lpMod -> Ncb = lpMod -> Nbb; lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite); lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod); lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite); lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod); - lpMod -> adoptedWhite = ComputeCorrelates(lpMod -> adoptedWhite, lpMod); return (LCMSHANDLE) lpMod; @@ -465,7 +471,7 @@ LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC) void LCMSEXPORT cmsCIECAM02Done(LCMSHANDLE hModel) { LPcmsCIECAM02 lpMod = (LPcmsCIECAM02) (LPSTR) hModel; - if (lpMod) free(lpMod); + if (lpMod) _cmsFree(lpMod); } @@ -510,3 +516,4 @@ void LCMSEXPORT cmsCIECAM02Reverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut ->Z = clr.XYZ[2]; } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c index a49a3e6dc0e..5c70ff458b7 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -174,7 +174,7 @@ typedef struct { LCMSAPI void LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel) { LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel; - if (lpMod) free(lpMod); + if (lpMod) _cmsFree(lpMod); } // Partial discounting for adaptation degree computation @@ -331,7 +331,7 @@ LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC) LPcmsCIECAM97s lpMod; VEC3 tmp; - if((lpMod = (LPcmsCIECAM97s) malloc(sizeof(cmsCIECAM97s))) == NULL) { + if((lpMod = (LPcmsCIECAM97s) _cmsMalloc(sizeof(cmsCIECAM97s))) == NULL) { return (LCMSHANDLE) NULL; } @@ -449,7 +449,7 @@ LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC) // RGB_subw = [MlamRigg][WP/YWp] #ifdef USE_CIECAM97s2 - MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, (LPVEC3) &lpMod -> WP); + MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &lpMod -> WP); #else VEC3divK(&tmp, (LPVEC3) &lpMod -> WP, lpMod->WP.Y); MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &tmp); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c index 2b486437a77..9f26b854476 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -65,22 +65,25 @@ LCMSAPI int LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable); // Persistence LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName); LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len); -LCMSAPI BOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName); // Properties LCMSAPI const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char* cSubProp, const char *Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer); LCMSAPI const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* cProp); LCMSAPI double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp); -LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE IT8, char ***PropertyNames); +LCMSAPI const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char *cSubProp); +LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE IT8, const char ***PropertyNames); +LCMSAPI int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char*** SubpropertyNames); // Datasets @@ -89,10 +92,10 @@ LCMSAPI const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatc LCMSAPI const char* LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE IT8, int row, int col); LCMSAPI double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE IT8, int col, int row); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val); LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample); @@ -100,15 +103,15 @@ LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPa LCMSAPI double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample, const char *Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, const char* cSample, double Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample); LCMSAPI int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames); LCMSAPI void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE IT8, const char* Formatter); @@ -126,7 +129,7 @@ LCMSAPI int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const // #define STRICT_CGATS 1 #define MAXID 128 // Max lenght of identifier -#define MAXSTR 255 // Max lenght of string +#define MAXSTR 1024 // Max lenght of string #define MAXTABLES 255 // Max Number of tables in a single stream #define MAXINCLUDE 20 // Max number of nested includes @@ -137,6 +140,9 @@ LCMSAPI int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const #ifndef NON_WINDOWS #include <io.h> +#define DIR_CHAR '\\' +#else +#define DIR_CHAR '/' #endif // Symbols @@ -160,6 +166,7 @@ typedef enum { SEND_DATA, SEND_DATA_FORMAT, SKEYWORD, + SDATA_FORMAT_ID, SINCLUDE } SYMBOL; @@ -171,7 +178,8 @@ typedef enum { WRITE_UNCOOKED, WRITE_STRINGIFY, WRITE_HEXADECIMAL, - WRITE_BINARY + WRITE_BINARY, + WRITE_PAIR } WRITEMODE; @@ -181,6 +189,8 @@ typedef struct _KeyVal { struct _KeyVal* Next; char* Keyword; // Name of variable + struct _KeyVal* NextSubkey; // If key is a dictionary, points to the next item + char* Subkey; // If key is a dictionary, points to the subkey name char* Value; // Points to value WRITEMODE WriteAs; // How to write the value @@ -220,7 +230,12 @@ typedef struct _Table { } TABLE, *LPTABLE; +// File stream being parsed +typedef struct _FileContext { + char FileName[MAX_PATH]; // File name if being readed from file + FILE* Stream; // File stream or NULL if holded in memory + } FILECTX, *LPFILECTX; // This struct hold all information about an openened // IT8 handler. Only one dataset is allowed. @@ -257,9 +272,9 @@ typedef struct { char* Source; // Points to loc. being parsed int lineno; // line counter for error reporting - char FileName[MAX_PATH]; // File name if being readed from file - FILE* Stream[MAXINCLUDE]; // File stream or NULL if holded in memory + LPFILECTX FileStack[MAXINCLUDE]; // Stack of files being parsed int IncludeSP; // Include Stack Pointer + char* MemoryBlock; // The stream if holded in memory char DoubleFormatter[MAXID]; // Printf-like 'double' formatter @@ -270,14 +285,14 @@ typedef struct { typedef struct { - FILE* stream; // For save-to-file behaviour + FILE* stream; // For save-to-file behaviour - LPBYTE Base; - LPBYTE Ptr; // For save-to-mem behaviour - size_t Used; - size_t Max; + LPBYTE Base; + LPBYTE Ptr; // For save-to-mem behaviour + size_t Used; + size_t Max; - } SAVESTREAM, FAR* LPSAVESTREAM; + } SAVESTREAM, FAR* LPSAVESTREAM; // ------------------------------------------------------ IT8 parsing routines @@ -298,59 +313,104 @@ static const KEYWORD TabKeys[] = { {".INCLUDE", SINCLUDE}, {"BEGIN_DATA", SBEGIN_DATA }, {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT }, + {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID}, {"END_DATA", SEND_DATA}, {"END_DATA_FORMAT", SEND_DATA_FORMAT}, {"KEYWORD", SKEYWORD} - }; #define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD)) // Predefined properties -static const char* PredefinedProperties[] = { +// A property +typedef struct { + const char *id; + WRITEMODE as; + } PROPERTY; - "NUMBER_OF_FIELDS", // Required - NUMBER OF FIELDS - "NUMBER_OF_SETS", // Required - NUMBER OF SETS - "ORIGINATOR", // Required - Identifies the specific system, organization or individual that created the data file. - "FILE_DESCRIPTOR", // Required - Describes the purpose or contents of the data file. - "CREATED", // Required - Indicates date of creation of the data file. - "DESCRIPTOR", // Required - Describes the purpose or contents of the data file. - "DIFFUSE_GEOMETRY", // The diffuse geometry used. Allowed values are "sphere" or "opal". - "MANUFACTURER", - "MANUFACTURE", // Some broken Fuji targets does store this value - "PROD_DATE", // Identifies year and month of production of the target in the form yyyy:mm. - "SERIAL", // Uniquely identifies individual physical target. +static PROPERTY PredefinedProperties[] = { - "MATERIAL", // Identifies the material on which the target was produced using a code + {"NUMBER_OF_FIELDS", WRITE_UNCOOKED}, // Required - NUMBER OF FIELDS + {"NUMBER_OF_SETS", WRITE_UNCOOKED}, // Required - NUMBER OF SETS + {"ORIGINATOR", WRITE_STRINGIFY}, // Required - Identifies the specific system, organization or individual that created the data file. + {"FILE_DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. + {"CREATED", WRITE_STRINGIFY}, // Required - Indicates date of creation of the data file. + {"DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. + {"DIFFUSE_GEOMETRY", WRITE_STRINGIFY}, // The diffuse geometry used. Allowed values are "sphere" or "opal". + {"MANUFACTURER", WRITE_STRINGIFY}, + {"MANUFACTURE", WRITE_STRINGIFY}, // Some broken Fuji targets does store this value + {"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm. + {"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target. + + {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code // uniquely identifying th e material. This is intend ed to be used for IT8.7 // physical targets only (i.e . IT8.7/1 a nd IT8.7/2). - "INSTRUMENTATION", // Used to report the specific instrumentation used (manufacturer and + {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and // model number) to generate the data reported. This data will often // provide more information about the particular data collected than an // extensive list of specific details. This is particularly important for // spectral data or data derived from spectrophotometry. - "MEASUREMENT_SOURCE", // Illumination used for spectral measurements. This data helps provide + {"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide // a guide to the potential for issues of paper fluorescence, etc. - "PRINT_CONDITIONS", // Used to define the characteristics of the printed sheet being reported. + {"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported. // Where standard conditions have been defined (e.g., SWOP at nominal) // named conditions may suffice. Otherwise, detailed information is // needed. - "SAMPLE_BACKING", // Identifies the backing material used behind the sample during - // measurement. Allowed values are “black”, “white”, or "na". + {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during + // measurement. Allowed values are “black”, “white”, or {"na". - "CHISQ_DOF" // Degrees of freedom associated with the Chi squared statistic + {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic + +// new in recent specs: + {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated + // along with details of the geometry and the aperture size and shape. For example, + // for transmission measurements it is important to identify 0/diffuse, diffuse/0, + // opal or integrating sphere, etc. For reflection it is important to identify 0/45, + // 45/0, sphere (specular included or excluded), etc. + + {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to + // denote the use of filters such as none, D65, Red, Green or Blue. + + {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed + // values are {"yes”, “white”, “none” or “na”. + + {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the + // calculation of various data parameters (2 degree and 10 degree), CIE standard + // illuminant functions used in the calculation of various data parameters (e.g., D50, + // D65, etc.), density status response, etc. If used there shall be at least one + // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute + // in the set shall be {"name" and shall identify the particular parameter used. + // The second shall be {"value" and shall provide the value associated with that name. + // For ASCII data, a string containing the Name and Value attribute pairs shall follow + // the weighting function keyword. A semi-colon separates attribute pairs from each + // other and within the attribute the name and value are separated by a comma. + + {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name + // of the calculation, parameter is the name of the parameter used in the calculation + // and value is the value of the parameter. + + {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc. + + {"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target. + + {"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table. + + {"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table. }; -#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(char *)) +#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(PROPERTY)) // Predefined sample types on dataset static const char* PredefinedSampleID[] = { + "SAMPLE_ID", // Identifies sample that data represents + "STRING", // Identifies label, or other non-machine readable value. + // Value must begin and end with a " symbol "CMYK_C", // Cyan component of CMYK data expressed as a percentage "CMYK_M", // Magenta component of CMYK data expressed as a percentage @@ -378,7 +438,7 @@ static const char* PredefinedSampleID[] = { "LAB_B", // b* component of Lab data "LAB_C", // C*ab component of Lab data "LAB_H", // hab component of Lab data - "LAB_DE" // CIE dE + "LAB_DE", // CIE dE "LAB_DE_94", // CIE dE using CIE 94 "LAB_DE_CMC", // dE using CMC "LAB_DE_2000", // CIE dE using CIE DE 2000 @@ -388,7 +448,7 @@ static const char* PredefinedSampleID[] = { "STDEV_Y", // Standard deviation of Y (tristimulus data) "STDEV_Z", // Standard deviation of Z (tristimulus data) "STDEV_L", // Standard deviation of L* - "STDEV_A" // Standard deviation of a* + "STDEV_A", // Standard deviation of a* "STDEV_B", // Standard deviation of b* "STDEV_DE", // Standard deviation of CIE dE "CHI_SQD_PAR"}; // The average of the standard deviations of L*, a* and b*. It is @@ -397,57 +457,120 @@ static const char* PredefinedSampleID[] = { #define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *)) +//Forward declaration of some internal functions +static +void* AllocChunk(LPIT8 it8, size_t size); + // Checks if c is a separator static -BOOL isseparator(int c) +LCMSBOOL isseparator(int c) { return (c == ' ') || (c == '\t') || (c == '\r'); } // Checks whatever if c is a valid identifier char - static -BOOL ismiddle(int c) +LCMSBOOL ismiddle(int c) { return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127)); } // Checks whatsever if c is a valid identifier middle char. static -BOOL isidchar(int c) +LCMSBOOL isidchar(int c) { return isalnum(c) || ismiddle(c); } // Checks whatsever if c is a valid identifier first char. static -BOOL isfirstidchar(int c) +LCMSBOOL isfirstidchar(int c) { return !isdigit(c) && ismiddle(c); } +// checks whether the supplied path looks like an absolute path +// NOTE: this function doesn't checks if the path exists or even if it's legal +static +LCMSBOOL isabsolutepath(const char *path) +{ + if(path == NULL) + return FALSE; + + if(path[0] == DIR_CHAR) + return TRUE; + +#ifndef NON_WINDOWS + if(isalpha(path[0]) && path[1] == ':') + return TRUE; +#endif + return FALSE; +} + +// Makes a file path based on a given reference path +// NOTE: buffer is assumed to point to at least MAX_PATH bytes +// NOTE: both relPath and basePath are assumed to be no more than MAX_PATH characters long (including the null terminator!) +// NOTE: this function doesn't check if the path exists or even if it's legal +static +LCMSBOOL _cmsMakePath(const char *relPath, const char *basePath, char *buffer) +{ + if (!isabsolutepath(relPath)) { + + char *tail; + + strncpy(buffer, basePath, MAX_PATH-1); + tail = strrchr(buffer, DIR_CHAR); + if (tail != NULL) { + + size_t len = tail - buffer; + strncpy(tail + 1, relPath, MAX_PATH - len -1); + // TODO: if combined path is longer than MAX_PATH, this should return FALSE! + return TRUE; + } + } + strncpy(buffer, relPath, MAX_PATH - 1); + buffer[MAX_PATH-1] = 0; + return TRUE; +} + + +// Make sure no exploit is being even tried static -BOOL SynError(LPIT8 it8, const char *Txt, ...) +const char* NoMeta(const char* str) +{ + if (strchr(str, '%') != NULL) + return "**** CORRUPTED FORMAT STRING ***"; + + return str; +} + + +// Syntax error +static +LCMSBOOL SynError(LPIT8 it8, const char *Txt, ...) { char Buffer[256], ErrMsg[1024]; va_list args; va_start(args, Txt); - vsprintf(Buffer, Txt, args); + vsnprintf(Buffer, 255, Txt, args); + Buffer[255] = 0; va_end(args); - sprintf(ErrMsg, "%s: Line %d, %s", it8->FileName, it8->lineno, Buffer); + snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer); + ErrMsg[1023] = 0; it8->sy = SSYNERROR; - cmsSignalError(LCMS_ERRC_ABORTED, ErrMsg); + cmsSignalError(LCMS_ERRC_ABORTED, "%s", ErrMsg); return FALSE; } +// Check if current symbol is same as specified. issue an error else. static -BOOL Check(LPIT8 it8, SYMBOL sy, const char* Err) +LCMSBOOL Check(LPIT8 it8, SYMBOL sy, const char* Err) { if (it8 -> sy != sy) - return SynError(it8, Err); + return SynError(it8, NoMeta(Err)); return TRUE; } @@ -457,15 +580,15 @@ BOOL Check(LPIT8 it8, SYMBOL sy, const char* Err) static void NextCh(LPIT8 it8) { - if (it8 -> Stream[it8 ->IncludeSP]) { + if (it8 -> FileStack[it8 ->IncludeSP]->Stream) { - it8 ->ch = fgetc(it8 ->Stream[it8 ->IncludeSP]); + it8 ->ch = fgetc(it8 ->FileStack[it8 ->IncludeSP]->Stream); - if (feof(it8 -> Stream[it8 ->IncludeSP])) { + if (feof(it8 -> FileStack[it8 ->IncludeSP]->Stream)) { if (it8 ->IncludeSP > 0) { - fclose(it8 ->Stream[it8->IncludeSP--]); + fclose(it8 ->FileStack[it8->IncludeSP--]->Stream); it8 -> ch = ' '; // Whitespace to be ignored } else @@ -476,7 +599,6 @@ void NextCh(LPIT8 it8) } else { - it8->ch = *it8->Source; if (it8->ch) it8->Source++; } @@ -799,18 +921,39 @@ void InSymbol(LPIT8 it8) if (it8 -> sy == SINCLUDE) { - FILE* IncludeFile; + LPFILECTX FileNest; + + if(it8 -> IncludeSP >= (MAXINCLUDE-1)) + { + SynError(it8, "Too many recursion levels"); + return; + } InSymbol(it8); if (!Check(it8, SSTRING, "Filename expected")) return; - IncludeFile = fopen(it8 -> str, "rt"); - if (IncludeFile == NULL) { - SynError(it8, "File %s not found", it8 ->str); - return; + FileNest = it8 -> FileStack[it8 -> IncludeSP + 1]; + if(FileNest == NULL) + { + FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (LPFILECTX)AllocChunk(it8, sizeof(FILECTX)); + //if(FileNest == NULL) + // TODO: how to manage out-of-memory conditions? } - it8 -> Stream[++it8 -> IncludeSP] = IncludeFile; + if(_cmsMakePath(it8->str, it8->FileStack[it8->IncludeSP]->FileName, FileNest->FileName) == FALSE) + { + SynError(it8, "File path too long"); + return; + } + + FileNest->Stream = fopen(FileNest->FileName, "rt"); + if (FileNest->Stream == NULL) { + + SynError(it8, "File %s not found", FileNest->FileName); + return; + } + it8->IncludeSP++; + it8 ->ch = ' '; InSymbol(it8); } @@ -819,7 +962,7 @@ void InSymbol(LPIT8 it8) // Checks end of line separator static -BOOL CheckEOLN(LPIT8 it8) +LCMSBOOL CheckEOLN(LPIT8 it8) { if (!Check(it8, SEOLN, "Expected separator")) return FALSE; while (it8 -> sy == SEOLN) @@ -850,21 +993,26 @@ void SkipEOLN(LPIT8 it8) // Returns a string holding current value static -BOOL GetVal(LPIT8 it8, char* Buffer, const char* ErrorTitle) +LCMSBOOL GetVal(LPIT8 it8, char* Buffer, size_t max, const char* ErrorTitle) { switch (it8->sy) { - case SIDENT: strncpy(Buffer, it8->id, MAXID-1); break; - case SINUM: sprintf(Buffer, "%d", it8 -> inum); break; - case SDNUM: sprintf(Buffer, it8->DoubleFormatter, it8 -> dnum); break; - case SSTRING: strncpy(Buffer, it8->str, MAXSTR-1); break; + case SIDENT: strncpy(Buffer, it8->id, max); + Buffer[max-1]=0; + break; + case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break; + case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break; + case SSTRING: strncpy(Buffer, it8->str, max); + Buffer[max-1] = 0; + break; default: - return SynError(it8, ErrorTitle); + return SynError(it8, "%s", ErrorTitle); } - return TRUE; + Buffer[max] = 0; + return TRUE; } // ---------------------------------------------------------- Table @@ -872,7 +1020,13 @@ BOOL GetVal(LPIT8 it8, char* Buffer, const char* ErrorTitle) static LPTABLE GetTable(LPIT8 it8) { - return it8 ->Tab + it8 ->nTable; + if ((it8 -> nTable >= it8 ->TablesCount) || (it8 -> nTable < 0)) { + + SynError(it8, "Table %d out of sequence", it8 -> nTable); + return it8 -> Tab; + } + + return it8 ->Tab + it8 ->nTable; } // ---------------------------------------------------------- Memory management @@ -896,15 +1050,15 @@ void LCMSEXPORT cmsIT8Free(LCMSHANDLE hIT8) for (p = it8->MemorySink; p != NULL; p = n) { n = p->Next; - if (p->Ptr) free(p->Ptr); - free(p); + if (p->Ptr) _cmsFree(p->Ptr); + _cmsFree(p); } } if (it8->MemoryBlock) - free(it8->MemoryBlock); + _cmsFree(it8->MemoryBlock); - free(it8); + _cmsFree(it8); } @@ -913,16 +1067,16 @@ static void* AllocBigBlock(LPIT8 it8, size_t size) { LPOWNEDMEM ptr1; - void* ptr = malloc(size); + void* ptr = _cmsMalloc(size); if (ptr) { ZeroMemory(ptr, size); - ptr1 = (LPOWNEDMEM) malloc(sizeof(OWNEDMEM)); + ptr1 = (LPOWNEDMEM) _cmsMalloc(sizeof(OWNEDMEM)); if (ptr1 == NULL) { - free(ptr); + _cmsFree(ptr); return NULL; } @@ -986,8 +1140,9 @@ char *AllocString(LPIT8 it8, const char* str) // Searches through linked list static -BOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, LPKEYVALUE* LastPtr) +LCMSBOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, const char* Subkey, LPKEYVALUE* LastPtr) { + if (LastPtr) *LastPtr = p; for (; p != NULL; p = p->Next) { @@ -996,8 +1151,22 @@ BOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, LPKEYVALUE* LastPtr) if (*Key != '#') { // Comments are ignored if (stricmp(Key, p->Keyword) == 0) - return TRUE; + break; } + } + + if (p == NULL) + return FALSE; + + if (Subkey == 0) + return TRUE; + + for (; p != NULL; p = p->NextSubkey) { + + if (LastPtr) *LastPtr = p; + + if (stricmp(Subkey, p->Subkey) == 0) + return TRUE; } return FALSE; @@ -1007,35 +1176,55 @@ BOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, LPKEYVALUE* LastPtr) // Add a property into a linked list static -BOOL AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char* xValue, WRITEMODE WriteAs) +LPKEYVALUE AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs) { LPKEYVALUE p; - LPKEYVALUE last; - // Check if property is already in list (this is an error) - if (IsAvailableOnList(*Head, Key, &last)) { + if (IsAvailableOnList(*Head, Key, Subkey, &p)) { - // This may work for editing properties + // This may work for editing properties - last->Value = AllocString(it8, xValue); - last->WriteAs = WriteAs; - return TRUE; - - // return SynError(it8, "duplicate key <%s>", Key); + // return SynError(it8, "duplicate key <%s>", Key); } + else { + LPKEYVALUE last = p; - // Allocate the container + // Allocate the container p = (LPKEYVALUE) AllocChunk(it8, sizeof(KEYVALUE)); if (p == NULL) { - return SynError(it8, "AddToList: out of memory"); + SynError(it8, "AddToList: out of memory"); + return NULL; } // Store name and value p->Keyword = AllocString(it8, Key); + p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey); + // Keep the container in our list + if (*Head == NULL) + *Head = p; + else + { + if(Subkey != 0 && last != 0) { + last->NextSubkey = p; + + // If Subkey is not null, then last is the last property with the same key, + // but not necessarily is the last property in the list, so we need to move + // to the actual list end + while(last->Next != 0) + last = last->Next; + } + last->Next = p; + } + + p->Next = NULL; + p->NextSubkey = NULL; + } + + p->WriteAs = WriteAs; if (xValue != NULL) { p->Value = AllocString(it8, xValue); @@ -1044,29 +1233,20 @@ BOOL AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char* xValue, p->Value = NULL; } - p->Next = NULL; - p->WriteAs = WriteAs; - - // Keep the container in our list - if (*Head == NULL) - *Head = p; - else - last->Next = p; - - return TRUE; + return p; } static -BOOL AddAvailableProperty(LPIT8 it8, const char* Key) +LPKEYVALUE AddAvailableProperty(LPIT8 it8, const char* Key, WRITEMODE as) { - return AddToList(it8, &it8->ValidKeywords, Key, NULL, WRITE_UNCOOKED); + return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as); } static -BOOL AddAvailableSampleID(LPIT8 it8, const char* Key) +LPKEYVALUE AddAvailableSampleID(LPIT8 it8, const char* Key) { - return AddToList(it8, &it8->ValidSampleID, Key, NULL, WRITE_UNCOOKED); + return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED); } @@ -1122,8 +1302,6 @@ LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void) AllocTable(it8); it8->MemoryBlock = NULL; - it8->Stream[0] = NULL; - it8->IncludeSP = 0; it8->MemorySink = NULL; it8 ->nTable = 0; @@ -1141,6 +1319,8 @@ LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void) it8 -> inum = 0; it8 -> dnum = 0.0; + it8->FileStack[0] = (LPFILECTX)AllocChunk(it8, sizeof(FILECTX)); + it8->IncludeSP = 0; it8 -> lineno = 1; strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); @@ -1149,7 +1329,7 @@ LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void) // Initialize predefined properties & data for (i=0; i < NUMPREDEFINEDPROPS; i++) - AddAvailableProperty(it8, PredefinedProperties[i]); + AddAvailableProperty(it8, PredefinedProperties[i].id, PredefinedProperties[i].as); for (i=0; i < NUMPREDEFINEDSAMPLEID; i++) AddAvailableSampleID(it8, PredefinedSampleID[i]); @@ -1167,65 +1347,72 @@ const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8) } -BOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type) +LCMSBOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type) { LPIT8 it8 = (LPIT8) hIT8; strncpy(it8 ->SheetType, Type, MAXSTR-1); + it8 ->SheetType[MAXSTR-1] = 0; return TRUE; } -BOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* Val) +LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* Val) { LPIT8 it8 = (LPIT8) hIT8; if (!Val) return FALSE; if (!*Val) return FALSE; - return AddToList(it8, &GetTable(it8)->HeaderList, "# ", Val, WRITE_UNCOOKED); + return AddToList(it8, &GetTable(it8)->HeaderList, "# ", NULL, Val, WRITE_UNCOOKED) != NULL; } // Sets a property -BOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* Key, const char *Val) +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* Key, const char *Val) { LPIT8 it8 = (LPIT8) hIT8; if (!Val) return FALSE; if (!*Val) return FALSE; - return AddToList(it8, &GetTable(it8)->HeaderList, Key, Val, WRITE_STRINGIFY); + return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Val, WRITE_STRINGIFY) != NULL; } -BOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val) +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val) { LPIT8 it8 = (LPIT8) hIT8; char Buffer[1024]; sprintf(Buffer, it8->DoubleFormatter, Val); - return AddToList(it8, &GetTable(it8)->HeaderList, cProp, Buffer, WRITE_UNCOOKED); + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL; } -BOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val) +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val) { LPIT8 it8 = (LPIT8) hIT8; char Buffer[1024]; sprintf(Buffer, "%d", Val); - return AddToList(it8, &GetTable(it8)->HeaderList, cProp, Buffer, WRITE_HEXADECIMAL); + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; } -BOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer) +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer) { LPIT8 it8 = (LPIT8) hIT8; - return AddToList(it8, &GetTable(it8)->HeaderList, Key, Buffer, WRITE_UNCOOKED); + return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL; } +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer) +{ + LPIT8 it8 = (LPIT8) hIT8; + + return AddToList(it8, &GetTable(it8)->HeaderList, Key, SubKey, Buffer, WRITE_PAIR) != NULL; +} // Gets a property const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* Key) @@ -1233,7 +1420,7 @@ const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* Key) LPIT8 it8 = (LPIT8) hIT8; LPKEYVALUE p; - if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, &p)) + if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, NULL, &p)) { return p -> Value; } @@ -1249,6 +1436,18 @@ double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp) else return 0.0; } +const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* Key, const char *SubKey) +{ + LPIT8 it8 = (LPIT8) hIT8; + LPKEYVALUE p; + + if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p)) + { + return p -> Value; + } + return NULL; +} + // ----------------------------------------------------------------- Datasets @@ -1287,10 +1486,17 @@ const char *GetDataFormat(LPIT8 it8, int n) } static -BOOL SetDataFormat(LPIT8 it8, int n, const char *label) +LCMSBOOL SetDataFormat(LPIT8 it8, int n, const char *label) { LPTABLE t = GetTable(it8); +#ifdef STRICT_CGATS + if (!IsAvailableOnList(it8-> ValidSampleID, label, NULL, NULL)) { + SynError(it8, "Invalid data format '%s'.", label); + return FALSE; + } +#endif + if (!t->DataFormat) AllocateDataFormat(it8); @@ -1308,7 +1514,7 @@ BOOL SetDataFormat(LPIT8 it8, int n, const char *label) } -BOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE h, int n, const char *Sample) +LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE h, int n, const char *Sample) { LPIT8 it8 = (LPIT8) h; return SetDataFormat(it8, n, Sample); @@ -1348,7 +1554,7 @@ char* GetData(LPIT8 it8, int nSet, int nField) } static -BOOL SetData(LPIT8 it8, int nSet, int nField, const char *Val) +LCMSBOOL SetData(LPIT8 it8, int nSet, int nField, const char *Val) { LPTABLE t = GetTable(it8); @@ -1383,42 +1589,43 @@ static void WriteStr(LPSAVESTREAM f, const char *str) { - size_t len; + size_t len; - if (str == NULL) - str = " "; + if (str == NULL) + str = " "; - // Lenghth to write - len = strlen(str); + // Lenghth to write + len = strlen(str); f ->Used += len; - if (f ->stream) { // Should I write it to a file? + if (f ->stream) { // Should I write it to a file? - fwrite(str, 1, len, f->stream); + fwrite(str, 1, len, f->stream); + + } + else { // Or to a memory block? + + + if (f ->Base) { // Am I just counting the bytes? + + if (f ->Used > f ->Max) { + + cmsSignalError(LCMS_ERRC_ABORTED, "Write to memory overflows in CGATS parser"); + return; + } + + CopyMemory(f ->Ptr, str, len); + f->Ptr += len; } - else { // Or to a memory block? - - if (f ->Base) { // Am I just counting the bytes? - - if (f ->Used > f ->Max) { - - cmsSignalError(LCMS_ERRC_ABORTED, "Write to memory overflows in CGATS parser"); - return; - } - - CopyMemory(f ->Ptr, str, len); - f->Ptr += len; - - } - - } + } } -// +// Write formatted + static void Writef(LPSAVESTREAM f, const char* frm, ...) { @@ -1426,7 +1633,8 @@ void Writef(LPSAVESTREAM f, const char* frm, ...) va_list args; va_start(args, frm); - vsprintf(Buffer, frm, args); + vsnprintf(Buffer, 4095, frm, args); + Buffer[4095] = 0; WriteStr(f, Buffer); va_end(args); @@ -1450,7 +1658,7 @@ void WriteHeader(LPIT8 it8, LPSAVESTREAM fp) for (Pt = p ->Value; *Pt; Pt++) { - Writef(fp, "%c", *Pt); + Writef(fp, "%c", *Pt); if (*Pt == '\n') { WriteStr(fp, "# "); @@ -1462,7 +1670,7 @@ void WriteHeader(LPIT8 it8, LPSAVESTREAM fp) } - if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL)) { + if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL, NULL)) { #ifdef STRICT_CGATS WriteStr(fp, "KEYWORD\t\""); @@ -1470,7 +1678,7 @@ void WriteHeader(LPIT8 it8, LPSAVESTREAM fp) WriteStr(fp, "\"\n"); #endif - AddAvailableProperty(it8, p->Keyword); + AddAvailableProperty(it8, p->Keyword, WRITE_UNCOOKED); } @@ -1495,6 +1703,10 @@ void WriteHeader(LPIT8 it8, LPSAVESTREAM fp) Writef(fp, "\t0x%B", atoi(p ->Value)); break; + case WRITE_PAIR: + Writef(fp, "\t\"%s,%s\"", p->Subkey, p->Value); + break; + default: SynError(it8, "Unknown write mode %d", p ->WriteAs); return; } @@ -1573,13 +1785,13 @@ void WriteData(LPSAVESTREAM fp, LPIT8 it8) // Saves whole file -BOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName) +LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName) { SAVESTREAM sd; int i; LPIT8 it8 = (LPIT8) hIT8; - ZeroMemory(&sd, sizeof(SAVESTREAM)); + ZeroMemory(&sd, sizeof(SAVESTREAM)); sd.stream = fopen(cFileName, "wt"); if (!sd.stream) return FALSE; @@ -1594,31 +1806,31 @@ BOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName) WriteData(&sd, it8); } - fclose(sd.stream); + fclose(sd.stream); return TRUE; } // Saves to memory -BOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded) +LCMSBOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded) { SAVESTREAM sd; int i; LPIT8 it8 = (LPIT8) hIT8; - ZeroMemory(&sd, sizeof(SAVESTREAM)); + ZeroMemory(&sd, sizeof(SAVESTREAM)); sd.stream = NULL; - sd.Base = (LPBYTE) MemPtr; - sd.Ptr = sd.Base; + sd.Base = (LPBYTE) MemPtr; + sd.Ptr = sd.Base; - sd.Used = 0; + sd.Used = 0; - if (sd.Base) - sd.Max = *BytesNeeded; // Write to memory? - else - sd.Max = 0; // Just counting the needed bytes + if (sd.Base) + sd.Max = *BytesNeeded; // Write to memory? + else + sd.Max = 0; // Just counting the needed bytes WriteStr(&sd, it8->SheetType); WriteStr(&sd, "\n"); @@ -1630,12 +1842,12 @@ BOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeed WriteData(&sd, it8); } - sd.Used++; // The \0 at the very end + sd.Used++; // The \0 at the very end - if (sd.Base) - sd.Ptr = 0; + if (sd.Base) + sd.Ptr = 0; - *BytesNeeded = sd.Used; + *BytesNeeded = sd.Used; return TRUE; } @@ -1644,7 +1856,7 @@ BOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeed // -------------------------------------------------------------- Higer level parsing static -BOOL DataFormatSection(LPIT8 it8) +LCMSBOOL DataFormatSection(LPIT8 it8) { int iField = 0; LPTABLE t = GetTable(it8); @@ -1685,16 +1897,19 @@ BOOL DataFormatSection(LPIT8 it8) static -BOOL DataSection (LPIT8 it8) +LCMSBOOL DataSection (LPIT8 it8) { int iField = 0; int iSet = 0; - char Buffer[256]; + char Buffer[MAXSTR]; LPTABLE t = GetTable(it8); InSymbol(it8); // Eats "BEGIN_DATA" CheckEOLN(it8); + if (!t->Data) + AllocateDataSet(it8); + while (it8->sy != SEND_DATA && it8->sy != SEOF) { if (iField >= t -> nSamples) { @@ -1705,7 +1920,7 @@ BOOL DataSection (LPIT8 it8) if (it8->sy != SEND_DATA && it8->sy != SEOF) { - if (!GetVal(it8, Buffer, "Sample data expected")) + if (!GetVal(it8, Buffer, 255, "Sample data expected")) return FALSE; if (!SetData(it8, iSet, iField, Buffer)) @@ -1734,10 +1949,11 @@ BOOL DataSection (LPIT8 it8) static -BOOL HeaderSection(LPIT8 it8) +LCMSBOOL HeaderSection(LPIT8 it8) { char VarName[MAXID]; char Buffer[MAXSTR]; + LPKEYVALUE Key; while (it8->sy != SEOF && it8->sy != SSYNERROR && @@ -1749,30 +1965,79 @@ BOOL HeaderSection(LPIT8 it8) case SKEYWORD: InSymbol(it8); - if (!GetVal(it8, Buffer, "Keyword expected")) return FALSE; - if (!AddAvailableProperty(it8, Buffer)) return FALSE; + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!AddAvailableProperty(it8, Buffer, WRITE_UNCOOKED)) return FALSE; + InSymbol(it8); + break; + + + case SDATA_FORMAT_ID: + InSymbol(it8); + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!AddAvailableSampleID(it8, Buffer)) return FALSE; InSymbol(it8); break; case SIDENT: strncpy(VarName, it8->id, MAXID-1); + VarName[MAXID-1] = 0; - if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL)) { + if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) { #ifdef STRICT_CGATS return SynError(it8, "Undefined keyword '%s'", VarName); #else - if (!AddAvailableProperty(it8, VarName)) return FALSE; + Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED); + if (Key == NULL) return FALSE; #endif } InSymbol(it8); - if (!GetVal(it8, Buffer, "Property data expected")) return FALSE; + if (!GetVal(it8, Buffer, MAXSTR-1, "Property data expected")) return FALSE; + if(Key->WriteAs != WRITE_PAIR) { + AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer, + (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED); + } + else { + const char *Subkey; + char *Nextkey; + if (it8->sy != SSTRING) + return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName); - AddToList(it8, &GetTable(it8)->HeaderList, VarName, Buffer, - (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED); + // chop the string as a list of "subkey, value" pairs, using ';' as a separator + for(Subkey = Buffer; Subkey != NULL; Subkey = Nextkey) + { + char *Value, *temp; + + // identify token pair boundary + Nextkey = (char*) strchr(Subkey, ';'); + if(Nextkey) + *Nextkey++ = '\0'; + + // for each pair, split the subkey and the value + Value = (char*) strrchr(Subkey, ','); + if(Value == NULL) + return SynError(it8, "Invalid value for property '%s'.", VarName); + + // gobble the spaces before the coma, and the coma itself + temp = Value++; + do *temp-- = '\0'; while(temp >= Subkey && *temp == ' '); + + // gobble any space at the right + temp = Value + strlen(Value) - 1; + while(*temp == ' ') *temp-- = '\0'; + + // trim the strings from the left + Subkey += strspn(Subkey, " "); + Value += strspn(Value, " "); + + if(Subkey[0] == 0 || Value[0] == 0) + return SynError(it8, "Invalid value for property '%s'.", VarName); + AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR); + } + } InSymbol(it8); break; @@ -1793,22 +2058,23 @@ BOOL HeaderSection(LPIT8 it8) static -BOOL ParseIT8(LPIT8 it8) +LCMSBOOL ParseIT8(LPIT8 it8, LCMSBOOL nosheet) { - char* SheetTypePtr; + char* SheetTypePtr = it8 ->SheetType; + + if (nosheet == 0) { // First line is a very special case. while (isseparator(it8->ch)) NextCh(it8); - SheetTypePtr = it8 ->SheetType; - while (it8->ch != '\r' && it8 ->ch != '\n' && it8->ch != '\t' && it8 -> ch != -1) { *SheetTypePtr++= (char) it8 ->ch; NextCh(it8); } + } *SheetTypePtr = 0; InSymbol(it8); @@ -1869,6 +2135,12 @@ void CookPointers(LPIT8 it8) for (idField = 0; idField < t -> nSamples; idField++) { + if (t ->DataFormat == NULL) { + SynError(it8, "Undefined DATA_FORMAT"); + return; + + } + Fld = t->DataFormat[idField]; if (!Fld) continue; @@ -1884,6 +2156,7 @@ void CookPointers(LPIT8 it8) char Buffer[256]; strncpy(Buffer, Data, 255); + Buffer[255] = 0; if (strlen(Buffer) <= strlen(Data)) strcpy(Data, Buffer); @@ -1916,7 +2189,7 @@ void CookPointers(LPIT8 it8) LPTABLE Table = it8 ->Tab + k; LPKEYVALUE p; - if (IsAvailableOnList(Table->HeaderList, Label, &p)) { + if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { // Available, keep type and table char Buffer[256]; @@ -1924,7 +2197,7 @@ void CookPointers(LPIT8 it8) char *Type = p ->Value; int nTable = k; - sprintf(Buffer, "%s %d %s", Label, nTable, Type ); + snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type ); SetData(it8, i, idField, Buffer); } @@ -1948,8 +2221,9 @@ void CookPointers(LPIT8 it8) // that should be something like some printable characters plus a \n static -BOOL IsMyBlock(LPBYTE Buffer, size_t n) +int IsMyBlock(LPBYTE Buffer, size_t n) { + int cols = 1, space = 0, quot = 0; size_t i; if (n < 10) return FALSE; // Too small @@ -1959,9 +2233,26 @@ BOOL IsMyBlock(LPBYTE Buffer, size_t n) for (i = 1; i < n; i++) { - if (Buffer[i] == '\n' || Buffer[i] == '\r' || Buffer[i] == '\t') return TRUE; - if (Buffer[i] < 32) return FALSE; - + switch(Buffer[i]) + { + case '\n': + case '\r': + return quot == 1 || cols > 2 ? 0 : cols; + case '\t': + case ' ': + if(!quot && !space) + space = 1; + break; + case '\"': + quot = !quot; + break; + default: + if (Buffer[i] < 32) return 0; + if (Buffer[i] > 127) return 0; + cols += space; + space = 0; + break; + } } return FALSE; @@ -1970,7 +2261,7 @@ BOOL IsMyBlock(LPBYTE Buffer, size_t n) static -BOOL IsMyFile(const char* FileName) +int IsMyFile(const char* FileName) { FILE *fp; size_t Size; @@ -1998,21 +2289,22 @@ LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len) LCMSHANDLE hIT8; LPIT8 it8; - if (!IsMyBlock((LPBYTE) Ptr, len)) return NULL; + int type = IsMyBlock((LPBYTE) Ptr, len); + if (type == 0) return NULL; hIT8 = cmsIT8Alloc(); if (!hIT8) return NULL; it8 = (LPIT8) hIT8; - it8 ->MemoryBlock = (char*) malloc(len + 1); + it8 ->MemoryBlock = (char*) _cmsMalloc(len + 1); strncpy(it8 ->MemoryBlock, (const char*) Ptr, len); it8 ->MemoryBlock[len] = 0; - strncpy(it8->FileName, "", MAX_PATH-1); + strncpy(it8->FileStack[0]->FileName, "", MAX_PATH-1); it8-> Source = it8 -> MemoryBlock; - if (!ParseIT8(it8)) { + if (!ParseIT8(it8, type-1)) { cmsIT8Free(hIT8); return FALSE; @@ -2021,7 +2313,7 @@ LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len) CookPointers(it8); it8 ->nTable = 0; - free(it8->MemoryBlock); + _cmsFree(it8->MemoryBlock); it8 -> MemoryBlock = NULL; return hIT8; @@ -2036,26 +2328,28 @@ LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName) LCMSHANDLE hIT8; LPIT8 it8; - if (!IsMyFile(cFileName)) return NULL; + int type = IsMyFile(cFileName); + if (type == 0) return NULL; hIT8 = cmsIT8Alloc(); it8 = (LPIT8) hIT8; if (!hIT8) return NULL; - it8 ->Stream[0] = fopen(cFileName, "rt"); + it8 ->FileStack[0]->Stream = fopen(cFileName, "rt"); - if (!it8 ->Stream[0]) { + if (!it8 ->FileStack[0]->Stream) { cmsIT8Free(hIT8); return NULL; } - strncpy(it8->FileName, cFileName, MAX_PATH-1); + strncpy(it8->FileStack[0]->FileName, cFileName, MAX_PATH-1); + it8->FileStack[0]->FileName[MAX_PATH-1] = 0; - if (!ParseIT8(it8)) { + if (!ParseIT8(it8, type-1)) { - fclose(it8 ->Stream[0]); + fclose(it8 ->FileStack[0]->Stream); cmsIT8Free(hIT8); return NULL; } @@ -2063,7 +2357,7 @@ LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName) CookPointers(it8); it8 ->nTable = 0; - fclose(it8 ->Stream[0]); + fclose(it8 ->FileStack[0]->Stream); return hIT8; } @@ -2078,12 +2372,12 @@ int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE hIT8, char ***SampleNames) } -int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, char ***PropertyNames) +int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, const char ***PropertyNames) { LPIT8 it8 = (LPIT8) hIT8; LPKEYVALUE p; int n; - char **Props; + const char **Props; LPTABLE t = GetTable(it8); // Pass#1 - count properties @@ -2094,7 +2388,7 @@ int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, char ***PropertyNames) } - Props = (char **) AllocChunk(it8, sizeof(char *) * n); + Props = (const char **) AllocChunk(it8, sizeof(char *) * n); // Pass#2 - Fill pointers n = 0; @@ -2106,6 +2400,41 @@ int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, char ***PropertyNames) return n; } +int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char ***SubpropertyNames) +{ + LPIT8 it8 = (LPIT8) hIT8; + LPKEYVALUE p, tmp; + int n; + const char **Props; + LPTABLE t = GetTable(it8); + + if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) { + *SubpropertyNames = 0; + return 0; + } + + // Pass#1 - count properties + + n = 0; + for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { + if(tmp->Subkey != NULL) + n++; + } + + + Props = (const char **) AllocChunk(it8, sizeof(char *) * n); + + // Pass#2 - Fill pointers + n = 0; + for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { + if(tmp->Subkey != NULL) + Props[n++] = p ->Subkey; + } + + *SubpropertyNames = Props; + return n; +} + static int LocatePatch(LPIT8 it8, const char* cPatch) { @@ -2201,7 +2530,7 @@ double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE hIT8, int row, int col) } -BOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val) +LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val) { LPIT8 it8 = (LPIT8) hIT8; @@ -2209,7 +2538,7 @@ BOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const cha } -BOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val) +LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val) { LPIT8 it8 = (LPIT8) hIT8; char Buff[256]; @@ -2260,7 +2589,7 @@ double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE it8, const char* cPatch, const cha -BOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE hIT8, const char* cPatch, +LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE hIT8, const char* cPatch, const char* cSample, const char *Val) { @@ -2305,18 +2634,19 @@ BOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE hIT8, const char* cPatch, } -BOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, +LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, const char* cSample, double Val) { LPIT8 it8 = (LPIT8) hIT8; char Buff[256]; - sprintf(Buff, it8->DoubleFormatter, Val); + snprintf(Buff, 255, it8->DoubleFormatter, Val); return cmsIT8SetData(hIT8, cPatch, cSample, Buff); } +// Buffer should get MAXSTR at least const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer) { @@ -2327,10 +2657,16 @@ const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buf if (!Data) return NULL; if (!buffer) return Data; - strcpy(buffer, Data); + strncpy(buffer, Data, MAXSTR-1); + buffer[MAXSTR-1] = 0; return buffer; } +int LCMSEXPORT cmsIT8GetPatchByName(LCMSHANDLE hIT8, const char *cPatch) +{ + return LocatePatch((LPIT8)hIT8, cPatch); +} + int LCMSEXPORT cmsIT8TableCount(LCMSHANDLE hIT8) { LPIT8 it8 = (LPIT8) hIT8; @@ -2356,7 +2692,7 @@ int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const ch cLabelFld = cmsIT8GetData(hIT8, cSet, cField); if (!cLabelFld) return -1; - if (sscanf(cLabelFld, "%s %d %s", Label, &nTable, Type) != 3) + if (sscanf(cLabelFld, "%255s %d %255s", Label, &nTable, Type) != 3) return -1; if (ExpectedType != NULL && *ExpectedType == 0) @@ -2371,6 +2707,19 @@ int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const ch } +LCMSBOOL LCMSEXPORT cmsIT8SetIndexColumn(LCMSHANDLE hIT8, const char* cSample) +{ + LPIT8 it8 = (LPIT8) hIT8; + + int pos = LocateSample(it8, cSample); + if(pos == -1) + return FALSE; + + it8->Tab[it8->nTable].SampleID = pos; + return TRUE; +} + + void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE hIT8, const char* Formatter) { LPIT8 it8 = (LPIT8) hIT8; @@ -2380,3 +2729,4 @@ void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE hIT8, const char* Formatter) else strcpy(it8->DoubleFormatter, Formatter); } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c index 81579bc4f11..4d56b3ef465 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -256,7 +256,7 @@ void ComputeBlackPointCompensationFactors(LPcmsCIEXYZ BlackPointIn, // Return TRUE if both m and of are empy -- "m" being identity and "of" being 0 static -BOOL IdentityParameters(LPWMAT3 m, LPWVEC3 of) +LCMSBOOL IdentityParameters(LPWMAT3 m, LPWVEC3 of) { WVEC3 wv0; @@ -661,3 +661,6 @@ int cmsChooseCnvrt(int Absolute, return rc; } + + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c index 016d0c4c669..a8947d4aee9 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -57,6 +57,7 @@ // errors. void cdecl cmsSignalError(int ErrorCode, const char *ErrorText, ...); + int LCMSEXPORT cmsErrorAction(int lAbort); void LCMSEXPORT cmsSetErrorHandler(cmsErrorHandlerFunction Fn); @@ -96,7 +97,7 @@ void cmsSignalError(int ErrorCode, const char *ErrorText, ...) char Buffer[1024]; - vsprintf(Buffer, ErrorText, args); + vsnprintf(Buffer, 1023, ErrorText, args); va_end(args); if (UserErrorHandler(ErrorCode, Buffer)) { @@ -118,8 +119,8 @@ void cmsSignalError(int ErrorCode, const char *ErrorText, ...) char Buffer1[1024]; char Buffer2[256]; - sprintf(Buffer1, "Error #%x; ", ErrorCode); - vsprintf(Buffer2, ErrorText, args); + snprintf(Buffer1, 767, "Error #%x; ", ErrorCode); + vsnprintf(Buffer2, 255, ErrorText, args); strcat(Buffer1, Buffer2); MessageBox(NULL, Buffer1, "Little cms", MB_OK|MB_ICONSTOP|MB_TASKMODAL); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c index 1b223c61342..7d134389dff 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -63,9 +63,9 @@ LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[]); LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma); LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma, int nPoints); -BOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); +LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); -BOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nPoints); +LCMSBOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nPoints); // Sampled curves @@ -74,7 +74,7 @@ LPSAMPLEDCURVE cdecl cmsAllocSampledCurve(int nItems); void cdecl cmsFreeSampledCurve(LPSAMPLEDCURVE p); void cdecl cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max); void cdecl cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max); -BOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); +LCMSBOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); void cdecl cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints); LPSAMPLEDCURVE cdecl cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints); @@ -84,7 +84,6 @@ double LCMSEXPORT cmsEstimateGammaEx(LPWORD GammaTable, int nEntries, double The // ---------------------------------------------------------------------------------------- -// #define DEBUG 1 #define MAX_KNOTS 4096 typedef float vec[MAX_KNOTS+1]; @@ -144,14 +143,14 @@ LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries) LPGAMMATABLE p; size_t size; - if (nEntries > 65530) { - cmsSignalError(LCMS_ERRC_WARNING, "Couldn't create gammatable of more than 65530 entries; 65530 assumed"); - nEntries = 65530; + if (nEntries > 65530 || nEntries <= 0) { + cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't create gammatable of more than 65530 entries"); + return NULL; } size = sizeof(GAMMATABLE) + (sizeof(WORD) * (nEntries-1)); - p = (LPGAMMATABLE) malloc(size); + p = (LPGAMMATABLE) _cmsMalloc(size); if (!p) return NULL; ZeroMemory(p, size); @@ -164,7 +163,7 @@ LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries) void LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma) { - if (Gamma) free(Gamma); + if (Gamma) _cmsFree(Gamma); } @@ -278,6 +277,15 @@ LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma LPWORD InPtr; LPGAMMATABLE p; + // Try to reverse it analytically whatever possible + if (InGamma -> Seed.Type > 0 && InGamma -> Seed.Type <= 5 && + _cmsCrc32OfGammaTable(InGamma) == InGamma -> Seed.Crc32) { + + return cmsBuildParametricGamma(nResultSamples, -(InGamma -> Seed.Type), InGamma ->Seed.Params); + } + + + // Nope, reverse the table p = cmsAllocGamma(nResultSamples); if (!p) return NULL; @@ -528,7 +536,7 @@ void smooth2(vec w, vec y, vec z, float lambda, int m) // Smooths a curve sampled at regular intervals -BOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda) +LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda) { vec w, y, z; @@ -640,13 +648,13 @@ LPSAMPLEDCURVE cmsAllocSampledCurve(int nItems) { LPSAMPLEDCURVE pOut; - pOut = (LPSAMPLEDCURVE) malloc(sizeof(SAMPLEDCURVE)); + pOut = (LPSAMPLEDCURVE) _cmsMalloc(sizeof(SAMPLEDCURVE)); if (pOut == NULL) return NULL; - if((pOut->Values = (double *) malloc(nItems * sizeof(double))) == NULL) + if((pOut->Values = (double *) _cmsMalloc(nItems * sizeof(double))) == NULL) { - free(pOut); + _cmsFree(pOut); return NULL; } @@ -659,8 +667,8 @@ LPSAMPLEDCURVE cmsAllocSampledCurve(int nItems) void cmsFreeSampledCurve(LPSAMPLEDCURVE p) { - free((LPVOID) p -> Values); - free((LPVOID) p); + _cmsFree((LPVOID) p -> Values); + _cmsFree((LPVOID) p); } @@ -731,7 +739,7 @@ void cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max) // Smooths a curve sampled at regular intervals -BOOL cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double lambda) +LCMSBOOL cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double lambda) { vec w, y, z; int i, nItems; @@ -915,14 +923,11 @@ LPSAMPLEDCURVE cmsConvertGammaToSampledCurve(LPGAMMATABLE Gamma, int nPoints) // Smooth endpoints (used in Black/White compensation) -BOOL _cmsSmoothEndpoints(LPWORD Table, int nEntries) +LCMSBOOL _cmsSmoothEndpoints(LPWORD Table, int nEntries) { vec w, y, z; int i, Zeros, Poles; -#ifdef DEBUG - ASAVE(Table, nEntries, "nonsmt.txt"); -#endif if (cmsIsLinear(Table, nEntries)) return FALSE; // Nothing to do diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c index 071cb4e4774..90e9181dcdb 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -66,7 +66,7 @@ to use highlights, then it will be lost. */ -BOOL _cmsEndPointsBySpace(icColorSpaceSignature Space, WORD **White, WORD **Black, +LCMSBOOL _cmsEndPointsBySpace(icColorSpaceSignature Space, WORD **White, WORD **Black, int *nOutputs) { // Only most common spaces @@ -376,7 +376,6 @@ double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2, double bs = Lab2 ->b; double Cs = sqrt( Sqr(as) + Sqr(bs) ); - double G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) )); double a_p = (1 + G ) * a1; @@ -390,15 +389,21 @@ double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2, double C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps)); double h_ps = atan2deg(a_ps, b_ps); - - double meanC_p =(C_p + C_ps) / 2; - double meanh_p = fabs(h_ps-h_p) <= 180 ? (h_ps + h_p)/2 : (h_ps+h_p-360)/2; + double hps_plus_hp = h_ps + h_p; + double hps_minus_hp = h_ps - h_p; + + double meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 : + (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 : + (hps_plus_hp - 360)/2; + + double delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) : + (hps_minus_hp) > 180 ? (hps_minus_hp - 360) : + (hps_minus_hp); + double delta_L = (Ls - L1); + double delta_C = (C_ps - C_p ); - double delta_h = fabs(h_p - h_ps) <= 180 ? fabs(h_p - h_ps) : 360 - fabs(h_p - h_ps); - double delta_L = fabs(L1 - Ls); - double delta_C = fabs(C_p - C_ps); double delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANES(delta_h) / 2); @@ -1065,7 +1070,7 @@ void SlopeLimiting(WORD Table[], int nEntries) // Check for monotonicity. static -BOOL IsMonotonic(LPGAMMATABLE t) +LCMSBOOL IsMonotonic(LPGAMMATABLE t) { int n = t -> nEntries; int i, last; @@ -1088,7 +1093,7 @@ BOOL IsMonotonic(LPGAMMATABLE t) // Check for endpoints static -BOOL HasProperEndpoints(LPGAMMATABLE t) +LCMSBOOL HasProperEndpoints(LPGAMMATABLE t) { if (t ->GammaTable[0] != 0) return FALSE; if (t ->GammaTable[t ->nEntries-1] != 0xFFFF) return FALSE; @@ -1109,7 +1114,7 @@ void _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransfor unsigned int t, i, v; int j; WORD In[MAXCHANNELS], Out[MAXCHANNELS]; - BOOL lIsSuitable; + LCMSBOOL lIsSuitable; _LPcmsTRANSFORM InputXForm = (_LPcmsTRANSFORM) h[0]; _LPcmsTRANSFORM OutputXForm = (_LPcmsTRANSFORM) h[nTransforms-1]; @@ -1126,10 +1131,10 @@ void _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransfor } - // Do nothing on all but RGB to RGB transforms + // Do nothing on all but Gray/RGB to Gray/RGB transforms - if ((InputXForm ->EntryColorSpace != icSigRgbData) || - (OutputXForm->ExitColorSpace != icSigRgbData)) return; + if (((InputXForm ->EntryColorSpace != icSigRgbData) && (InputXForm ->EntryColorSpace != icSigGrayData)) || + ((OutputXForm->ExitColorSpace != icSigRgbData) && (OutputXForm->ExitColorSpace != icSigGrayData))) return; for (t = 0; t < Grid -> InputChan; t++) @@ -1169,10 +1174,13 @@ void _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransfor if (!HasProperEndpoints(Trans[t])) lIsSuitable = FALSE; + /* // Exclude if transfer function is not smooth enough // to be modelled as a gamma function, or the gamma is reversed + if (cmsEstimateGamma(Trans[t]) < 1.0) lIsSuitable = FALSE; + */ } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c index 059f23d0104..43432f37e9b 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -282,7 +282,7 @@ void Eval8Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS // Fills optimization parameters void cmsCalcCLUT16ParamsEx(int nSamples, int InputChan, int OutputChan, - BOOL lUseTetrahedral, LPL16PARAMS p) + LCMSBOOL lUseTetrahedral, LPL16PARAMS p) { int clutPoints; @@ -579,7 +579,7 @@ WORD cmsReverseLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p) // Identify if value fall downto 0 or FFFF zone if (Value == 0) return 0; - if (Value == 0xFFFF) return 0xFFFF; + // if (Value == 0xFFFF) return 0xFFFF; // else restrict to valid zone @@ -631,7 +631,7 @@ WORD cmsReverseLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p) a = (y1 - y0) / (x1 - x0); b = y0 - a * x0; - if (a == 0) return (WORD) x; + if (fabs(a) < 0.01) return (WORD) x; f = ((Value - b) / a); @@ -763,7 +763,7 @@ void cmsTrilinearInterp16(WORD Input[], WORD Output[], X0 = p -> opta3 * x0; X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta3); - Y0 = p -> opta2 * y0; + Y0 = p -> opta2 * y0; Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta2); Z0 = p -> opta1 * z0; @@ -942,7 +942,7 @@ void cmsTetrahedralInterp16(WORD Input[], X0 = p -> opta3 * x0; X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta3); - Y0 = p -> opta2 * y0; + Y0 = p -> opta2 * y0; Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta2); Z0 = p -> opta1 * z0; @@ -1009,11 +1009,11 @@ void cmsTetrahedralInterp16(WORD Input[], Rest = c1 * rx + c2 * ry + c3 * rz; - // There is a lot of math hidden in this expression. The rest is in fixed domain - // and the result in 0..ffff domain. So the complete expression should be - // ROUND_FIXED_TO_INT(ToFixedDomain(Rest)) But that can be optimized as (Rest + 0x7FFF) / 0xFFFF + // There is a lot of math hidden in this expression. The rest is in fixed domain + // and the result in 0..ffff domain. So the complete expression should be + // ROUND_FIXED_TO_INT(ToFixedDomain(Rest)) But that can be optimized as (Rest + 0x7FFF) / 0xFFFF - Output[OutChan] = (WORD) (c0 + ((Rest + 0x7FFF) / 0xFFFF)); + Output[OutChan] = (WORD) (c0 + ((Rest + 0x7FFF) / 0xFFFF)); } @@ -1131,3 +1131,4 @@ void cmsTetrahedralInterp8(WORD Input[], } #undef DENS + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c index 1556fa5e8af..7f8cbf06779 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -62,7 +62,7 @@ typedef struct { LPBYTE Block; // Points to allocated memory size_t Size; // Size of allocated memory - int Pointer; // Points to current location + size_t Pointer; // Points to current location int FreeBlockOnClose; // As title } FILEMEM; @@ -70,18 +70,19 @@ typedef struct { static LPVOID MemoryOpen(LPBYTE Block, size_t Size, char Mode) { - FILEMEM* fm = (FILEMEM*) malloc(sizeof(FILEMEM)); + FILEMEM* fm = (FILEMEM*) _cmsMalloc(sizeof(FILEMEM)); + if (fm == NULL) return NULL; + ZeroMemory(fm, sizeof(FILEMEM)); if (Mode == 'r') { - fm ->Block = (LPBYTE) malloc(Size); + fm ->Block = (LPBYTE) _cmsMalloc(Size); if (fm ->Block == NULL) { - free(fm); + _cmsFree(fm); return NULL; } - CopyMemory(fm->Block, Block, Size); fm ->FreeBlockOnClose = TRUE; } @@ -103,13 +104,27 @@ size_t MemoryRead(LPVOID buffer, size_t size, size_t count, struct _lcms_iccprof FILEMEM* ResData = (FILEMEM*) Icc ->stream; LPBYTE Ptr; size_t len = size * count; + size_t extent = ResData -> Pointer + len; + if (len == 0) { + return 0; + } - if (ResData -> Pointer + len > ResData -> Size){ + if (len / size != count) { + cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with count / size."); + return 0; + } + + if (extent < len || extent < ResData -> Pointer) { + cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with len."); + return 0; + } + + if (ResData -> Pointer + len > ResData -> Size) { len = (ResData -> Size - ResData -> Pointer); - cmsSignalError(LCMS_ERRC_WARNING, "Read from memory error. Got %d bytes, block should be of %d bytes", len * size, count * size); - + cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Got %d bytes, block should be of %d bytes", len * size, count * size); + return 0; } Ptr = ResData -> Block; @@ -123,7 +138,7 @@ size_t MemoryRead(LPVOID buffer, size_t size, size_t count, struct _lcms_iccprof // SEEK_CUR is assumed static -BOOL MemorySeek(struct _lcms_iccprofile_struct* Icc, size_t offset) +LCMSBOOL MemorySeek(struct _lcms_iccprofile_struct* Icc, size_t offset) { FILEMEM* ResData = (FILEMEM*) Icc ->stream; @@ -147,18 +162,19 @@ size_t MemoryTell(struct _lcms_iccprofile_struct* Icc) } -// Writes data to memory, also keeps used space for further reference +// Writes data to memory, also keeps used space for further reference. NO CHECK IS PERFORMED static -BOOL MemoryWrite(struct _lcms_iccprofile_struct* Icc, size_t size, void *Ptr) +LCMSBOOL MemoryWrite(struct _lcms_iccprofile_struct* Icc, size_t size, void *Ptr) { FILEMEM* ResData = (FILEMEM*) Icc ->stream; if (size == 0) return TRUE; if (ResData != NULL) - CopyMemory(ResData ->Block + Icc ->UsedSpace, Ptr, size); + CopyMemory(ResData ->Block + ResData ->Pointer, Ptr, size); + ResData->Pointer += size; Icc->UsedSpace += size; return TRUE; @@ -166,15 +182,37 @@ BOOL MemoryWrite(struct _lcms_iccprofile_struct* Icc, size_t size, void *Ptr) static -BOOL MemoryClose(struct _lcms_iccprofile_struct* Icc) +LCMSBOOL MemoryGrow(struct _lcms_iccprofile_struct* Icc, size_t size) +{ + FILEMEM* ResData = (FILEMEM*) Icc->stream; + + void* newBlock = NULL; + + /* Follow same policies as functions in lcms.h */ + if (ResData->Size + size < 0) return NULL; + if (ResData->Size + size > ((size_t)1024*1024*500)) return NULL; + + newBlock = realloc(ResData->Block, ResData->Size + size); + + if (!newBlock) { + return FALSE; + } + ResData->Block = newBlock; + ResData->Size += size; + return TRUE; +} + + +static +LCMSBOOL MemoryClose(struct _lcms_iccprofile_struct* Icc) { FILEMEM* ResData = (FILEMEM*) Icc ->stream; if (ResData ->FreeBlockOnClose) { - if (ResData ->Block) free(ResData ->Block); + if (ResData ->Block) _cmsFree(ResData ->Block); } - free(ResData); + _cmsFree(ResData); return 0; } @@ -192,7 +230,7 @@ size_t FileRead(void *buffer, size_t size, size_t count, struct _lcms_iccprofile { size_t nReaded = fread(buffer, size, count, (FILE*) Icc->stream); if (nReaded != count) { - cmsSignalError(LCMS_ERRC_WARNING, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size); + cmsSignalError(LCMS_ERRC_ABORTED, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size); return 0; } @@ -201,7 +239,7 @@ size_t FileRead(void *buffer, size_t size, size_t count, struct _lcms_iccprofile static -BOOL FileSeek(struct _lcms_iccprofile_struct* Icc, size_t offset) +LCMSBOOL FileSeek(struct _lcms_iccprofile_struct* Icc, size_t offset) { if (fseek((FILE*) Icc ->stream, (long) offset, SEEK_SET) != 0) { @@ -223,7 +261,7 @@ size_t FileTell(struct _lcms_iccprofile_struct* Icc) static -BOOL FileWrite(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr) +LCMSBOOL FileWrite(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr) { if (size == 0) return TRUE; @@ -239,7 +277,14 @@ BOOL FileWrite(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr) static -BOOL FileClose(struct _lcms_iccprofile_struct* Icc) +LCMSBOOL FileGrow(struct _lcms_iccprofile_struct* Icc, size_t size) +{ + return TRUE; +} + + +static +LCMSBOOL FileClose(struct _lcms_iccprofile_struct* Icc) { return fclose((FILE*) Icc ->stream); } @@ -252,7 +297,7 @@ BOOL FileClose(struct _lcms_iccprofile_struct* Icc) cmsHPROFILE _cmsCreateProfilePlaceholder(void) { - LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) malloc(sizeof(LCMSICCPROFILE)); + LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) _cmsMalloc(sizeof(LCMSICCPROFILE)); if (Icc == NULL) return NULL; // Empty values @@ -290,7 +335,7 @@ icTagSignature LCMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, icInt32Number // Search for a specific tag in tag dictionary // Returns position or -1 if tag not found -icInt32Number _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, BOOL lSignalError) +icInt32Number _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, LCMSBOOL lSignalError) { icInt32Number i; @@ -311,7 +356,7 @@ icInt32Number _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, BOOL l // Check existance -BOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig) +LCMSBOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; return _cmsSearchTag(Icc, sig, FALSE) >= 0; @@ -330,7 +375,7 @@ LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const if (i >=0) { - if (Icc -> TagPtrs[i]) free(Icc -> TagPtrs[i]); + if (Icc -> TagPtrs[i]) _cmsFree(Icc -> TagPtrs[i]); } else { @@ -341,11 +386,14 @@ LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const cmsSignalError(LCMS_ERRC_ABORTED, "Too many tags (%d)", MAX_TABLE_TAG); Icc ->TagCount = MAX_TABLE_TAG-1; + return NULL; } } - Ptr = malloc(size); + Ptr = _cmsMalloc(size); + if (Ptr == NULL) return NULL; + CopyMemory(Ptr, Init, size); Icc ->TagNames[i] = sig; @@ -376,12 +424,15 @@ LPLCMSICCPROFILE _cmsCreateProfileFromFilePlaceholder(const char* FileName) if (NewIcc == NULL) return NULL; strncpy(NewIcc -> PhysicalFile, FileName, MAX_PATH-1); + NewIcc -> PhysicalFile[MAX_PATH-1] = 0; + NewIcc ->stream = ICCfile; NewIcc ->Read = FileRead; NewIcc ->Seek = FileSeek; NewIcc ->Tell = FileTell; NewIcc ->Close = FileClose; + NewIcc ->Grow = FileGrow; NewIcc ->Write = NULL; NewIcc ->IsWrite = FALSE; @@ -419,7 +470,8 @@ LPLCMSICCPROFILE _cmsCreateProfileFromMemPlaceholder(LPVOID MemPtr, DWORD dwSize NewIcc ->Seek = MemorySeek; NewIcc ->Tell = MemoryTell; NewIcc ->Close = MemoryClose; - NewIcc ->Write = NULL; + NewIcc ->Grow = MemoryGrow; + NewIcc ->Write = MemoryWrite; NewIcc ->IsWrite = FALSE; @@ -476,7 +528,7 @@ void _cmsSetSaveToMemory(LPLCMSICCPROFILE Icc, LPVOID MemPtr, size_t dwSize) -BOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; *Dest = Icc -> MediaWhitePoint; @@ -484,14 +536,14 @@ BOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) } -BOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; *Dest = Icc -> MediaBlackPoint; return TRUE; } -BOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; *Dest = Icc -> Illuminant; @@ -549,7 +601,7 @@ void LCMSEXPORT cmsSetProfileID(cmsHPROFILE hProfile, LPBYTE ProfileID) } -BOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; CopyMemory(Dest, &Icc ->Created, sizeof(struct tm)); @@ -570,23 +622,18 @@ void LCMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, icColorSpaceSignature pcs) Icc -> PCS = pcs; } - - icColorSpaceSignature LCMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; return Icc -> ColorSpace; } - - void LCMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, icColorSpaceSignature sig) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; Icc -> ColorSpace = sig; } - icProfileClassSignature LCMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; @@ -599,7 +646,6 @@ DWORD LCMSEXPORT cmsGetProfileICCversion(cmsHPROFILE hProfile) return (DWORD) Icc -> Version; } - void LCMSEXPORT cmsSetProfileICCversion(cmsHPROFILE hProfile, DWORD Version) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; @@ -638,7 +684,7 @@ LPVOID DupBlock(LPLCMSICCPROFILE Icc, LPVOID Block, size_t size) // This is tricky, since LUT structs does have pointers -BOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut) +LCMSBOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; LPLUT Orig, Stored; @@ -666,7 +712,7 @@ BOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const vo } -BOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ) +LCMSBOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -675,7 +721,7 @@ BOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cm } -BOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text) +LCMSBOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -683,7 +729,7 @@ BOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const c return TRUE; } -BOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction) +LCMSBOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -692,7 +738,7 @@ BOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMM } -BOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm) +LCMSBOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -701,7 +747,7 @@ BOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, } -BOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ pseq) +LCMSBOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ pseq) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -711,28 +757,40 @@ BOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignatu } -BOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc) +LCMSBOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; _cmsInitTag(Icc, sig, sizeof(cmsNAMEDCOLORLIST) + (nc ->nColors - 1) * sizeof(cmsNAMEDCOLOR), nc); - return FALSE; + return TRUE; } -BOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime) +LCMSBOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; _cmsInitTag(Icc, sig, sizeof(struct tm), DateTime); - return FALSE; + return TRUE; } -BOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc) +LCMSBOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; _cmsInitTag(Icc, sig, sizeof(cmsNAMEDCOLORLIST) + (nc ->nColors - 1) * sizeof(cmsNAMEDCOLOR), nc); - return FALSE; + return TRUE; } + + +LCMSBOOL LCMSEXPORT _cmsAddChromaticAdaptationTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* mat) +{ + LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; + + _cmsInitTag(Icc, sig, 3*sizeof(cmsCIEXYZ), mat); + return TRUE; + +} + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c index 77419f809f3..16aec6c5362 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -149,6 +149,7 @@ void AdjustEndianessArray16(LPWORD p, size_t num_words) #endif + // Transports to properly encoded values - note that icc profiles does use // big endian notation. @@ -216,7 +217,8 @@ icTagTypeSignature ReadBase(LPLCMSICCPROFILE Icc) { icTagBase Base; - Icc -> Read(&Base, sizeof(icTagBase), 1, Icc); + if (Icc -> Read(&Base, sizeof(icTagBase), 1, Icc) != 1) + return (icTagTypeSignature) 0; AdjustEndianess32((LPBYTE) &Base.sig); return Base.sig; @@ -288,13 +290,15 @@ void EvalCHRM(LPcmsCIEXYZ Dest, LPMAT3 Chrm, LPcmsCIEXYZ Src) // Read profile header and validate it static -LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) +LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, LCMSBOOL lIsFromMemory) { icTag Tag; icHeader Header; icInt32Number TagCount, i; + icUInt32Number extent; - Icc -> Read(&Header, sizeof(icHeader), 1, Icc); + if (Icc -> Read(&Header, sizeof(icHeader), 1, Icc) != 1) + goto ErrorCleanup; // Convert endian @@ -306,14 +310,13 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) AdjustEndianess32((LPBYTE) &Header.pcs); AdjustEndianess32((LPBYTE) &Header.magic); AdjustEndianess32((LPBYTE) &Header.flags); - AdjustEndianess32((LPBYTE) &Header.attributes[0]); + AdjustEndianess32((LPBYTE) &Header.attributes[0]); AdjustEndianess32((LPBYTE) &Header.renderingIntent); // Validate it if (Header.magic != icMagicNumber) goto ErrorCleanup; - if (Icc ->Read(&TagCount, sizeof(icInt32Number), 1, Icc) != 1) goto ErrorCleanup; @@ -324,7 +327,7 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) Icc -> PCS = Header.pcs; Icc -> RenderingIntent = (icRenderingIntent) Header.renderingIntent; Icc -> flags = Header.flags; - Icc -> attributes = Header.attributes[0]; + Icc -> attributes = Header.attributes[0]; Icc -> Illuminant.X = Convert15Fixed16(Header.illuminant.X); Icc -> Illuminant.Y = Convert15Fixed16(Header.illuminant.Y); Icc -> Illuminant.Z = Convert15Fixed16(Header.illuminant.Z); @@ -348,7 +351,7 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) // Read tag directory - if (TagCount > MAX_TABLE_TAG) { + if (TagCount > MAX_TABLE_TAG || TagCount < 0) { cmsSignalError(LCMS_ERRC_ABORTED, "Too many tags (%d)", TagCount); goto ErrorCleanup; @@ -357,12 +360,18 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) Icc -> TagCount = TagCount; for (i=0; i < TagCount; i++) { - Icc ->Read(&Tag, sizeof(icTag), 1, Icc); + if (Icc ->Read(&Tag, sizeof(icTag), 1, Icc) != 1) + goto ErrorCleanup; AdjustEndianess32((LPBYTE) &Tag.offset); AdjustEndianess32((LPBYTE) &Tag.size); AdjustEndianess32((LPBYTE) &Tag.sig); // Signature + // Perform some sanity check. Offset + size should fall inside file. + extent = Tag.offset + Tag.size; + if (extent > Header.size || extent < Tag.offset) + goto ErrorCleanup; + Icc -> TagNames[i] = Tag.sig; Icc -> TagOffsets[i] = Tag.offset; Icc -> TagSizes[i] = Tag.size; @@ -381,13 +390,10 @@ ErrorCleanup: cmsSignalError(LCMS_ERRC_ABORTED, "Corrupted profile: '%s'", Icc->PhysicalFile); - free(Icc); + _cmsFree(Icc); return NULL; } - - - static unsigned int uipow(unsigned int a, unsigned int b) { unsigned int rv = 1; @@ -497,7 +503,7 @@ void FixLUT8bothSides(LPLUT Lut, size_t nTabSize) // The infamous LUT 8 static -void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) +LCMSBOOL ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) { icLut8 LUT8; LPBYTE Temp; @@ -506,7 +512,7 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) unsigned int AllLinear; LPWORD PtrW; - Icc ->Read(&LUT8, sizeof(icLut8) - SIZEOF_UINT8_ALIGNED, 1, Icc); + if (Icc ->Read(&LUT8, sizeof(icLut8) - SIZEOF_UINT8_ALIGNED, 1, Icc) != 1) return FALSE; NewLUT -> wFlags = LUT_HASTL1|LUT_HASTL2|LUT_HAS3DGRID; NewLUT -> cLutPoints = LUT8.clutPoints; @@ -515,6 +521,10 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) NewLUT -> InputEntries = 256; NewLUT -> OutputEntries = 256; + // Do some checking + if (!_cmsValidateLUT(NewLUT)) { + return FALSE; + } AdjustEndianess32((LPBYTE) &LUT8.e00); AdjustEndianess32((LPBYTE) &LUT8.e01); @@ -550,13 +560,24 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) // Copy input tables - Temp = (LPBYTE) malloc(256); + Temp = (LPBYTE) _cmsMalloc(256); + if (Temp == NULL) return FALSE; + AllLinear = 0; for (i=0; i < NewLUT -> InputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * 256); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * 256); + if (PtrW == NULL) { + _cmsFree(Temp); + return FALSE; + } + NewLUT -> L1[i] = PtrW; - Icc ->Read(Temp, 1, 256, Icc); + if (Icc ->Read(Temp, 1, 256, Icc) != 256) { + _cmsFree(Temp); + return FALSE; + } + for (j=0; j < 256; j++) PtrW[j] = TO16_TAB(Temp[j]); AllLinear += cmsIsLinear(NewLUT -> L1[i], NewLUT -> InputEntries); @@ -569,7 +590,7 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) NewLUT -> wFlags &= ~LUT_HASTL1; } - free(Temp); + _cmsFree(Temp); // Copy 3D CLUT @@ -578,9 +599,20 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) if (nTabSize > 0) { - PtrW = (LPWORD) malloc(sizeof(WORD) * nTabSize); - Temp = (LPBYTE) malloc(nTabSize); - Icc ->Read(Temp, 1, nTabSize, Icc); + PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize); + if (PtrW == NULL) return FALSE; + + Temp = (LPBYTE) _cmsMalloc(nTabSize); + if (Temp == NULL) { + _cmsFree(PtrW); + return FALSE; + } + + if (Icc ->Read(Temp, 1, nTabSize, Icc) != nTabSize) { + _cmsFree(Temp); + _cmsFree(PtrW); + return FALSE; + } NewLUT -> T = PtrW; NewLUT -> Tsize = (unsigned int) (nTabSize * sizeof(WORD)); @@ -589,25 +621,37 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) *PtrW++ = TO16_TAB(Temp[i]); } - free(Temp); + _cmsFree(Temp); } else { NewLUT ->T = NULL; NewLUT ->Tsize = 0; - NewLUT -> wFlags &= ~LUT_HAS3DGRID; + NewLUT ->wFlags &= ~LUT_HAS3DGRID; } - // Copy output tables - Temp = (LPBYTE) malloc(256); + Temp = (LPBYTE) _cmsMalloc(256); + if (Temp == NULL) { + return FALSE; + } + AllLinear = 0; for (i=0; i < NewLUT -> OutputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * 256); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * 256); + if (PtrW == NULL) { + _cmsFree(Temp); + return FALSE; + } + NewLUT -> L2[i] = PtrW; - Icc ->Read(Temp, 1, 256, Icc); + if (Icc ->Read(Temp, 1, 256, Icc) != 256) { + _cmsFree(Temp); + return FALSE; + } + for (j=0; j < 256; j++) PtrW[j] = TO16_TAB(Temp[j]); AllLinear += cmsIsLinear(NewLUT -> L2[i], 256); @@ -621,7 +665,7 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) } - free(Temp); + _cmsFree(Temp); cmsCalcL16Params(NewLUT -> InputEntries, &NewLUT -> In16params); cmsCalcL16Params(NewLUT -> OutputEntries, &NewLUT -> Out16params); @@ -646,6 +690,15 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) // some profiles does claim to do that. Poor lcms will try // to detect such condition and fix up "on the fly". + switch (sig) { + + case icSigBToA0Tag: + case icSigBToA1Tag: + case icSigBToA2Tag: + case icSigGamutTag: + case icSigPreview0Tag: + case icSigPreview1Tag: + case icSigPreview2Tag: { LPWORD WhiteLab, ExpectedWhite; WORD WhiteFixed[MAXCHANNELS], WhiteUnfixed[MAXCHANNELS]; @@ -685,9 +738,13 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) } } + break; + default:; + } } + return TRUE; } @@ -696,7 +753,7 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) // Case LUT 16 static -void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) +LCMSBOOL ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) { icLut16 LUT16; size_t nTabSize; @@ -705,7 +762,8 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) LPWORD PtrW; - Icc ->Read(&LUT16, sizeof(icLut16)- SIZEOF_UINT16_ALIGNED, 1, Icc); + if (Icc ->Read(&LUT16, sizeof(icLut16)- SIZEOF_UINT16_ALIGNED, 1, Icc) != 1) + return FALSE; NewLUT -> wFlags = LUT_HASTL1 | LUT_HASTL2 | LUT_HAS3DGRID; NewLUT -> cLutPoints = LUT16.clutPoints; @@ -718,6 +776,9 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) NewLUT -> InputEntries = LUT16.inputEnt; NewLUT -> OutputEntries = LUT16.outputEnt; + if (!_cmsValidateLUT(NewLUT)) { + return FALSE; + } // Matrix handling @@ -754,9 +815,14 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) AllLinear = 0; for (i=0; i < NewLUT -> InputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> InputEntries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> InputEntries); + if (PtrW == NULL) return FALSE; + NewLUT -> L1[i] = PtrW; - Icc ->Read(PtrW, sizeof(WORD), NewLUT -> InputEntries, Icc); + if (Icc ->Read(PtrW, sizeof(WORD), NewLUT -> InputEntries, Icc) != NewLUT -> InputEntries) { + return FALSE; + } + AdjustEndianessArray16(PtrW, NewLUT -> InputEntries); AllLinear += cmsIsLinear(NewLUT -> L1[i], NewLUT -> InputEntries); } @@ -775,12 +841,17 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) NewLUT->InputChan)); if (nTabSize > 0) { - PtrW = (LPWORD) malloc(sizeof(WORD) * nTabSize); + PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize); + if (PtrW == NULL) + return FALSE; NewLUT -> T = PtrW; NewLUT -> Tsize = (unsigned int) (nTabSize * sizeof(WORD)); - Icc -> Read(PtrW, sizeof(WORD), nTabSize, Icc); + if (Icc -> Read(PtrW, sizeof(WORD), nTabSize, Icc) != nTabSize) { + return FALSE; + } + AdjustEndianessArray16(NewLUT -> T, nTabSize); } else { @@ -794,9 +865,16 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) AllLinear = 0; for (i=0; i < NewLUT -> OutputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> OutputEntries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> OutputEntries); + if (PtrW == NULL) { + return FALSE; + } + NewLUT -> L2[i] = PtrW; - Icc ->Read(PtrW, sizeof(WORD), NewLUT -> OutputEntries, Icc); + if (Icc ->Read(PtrW, sizeof(WORD), NewLUT -> OutputEntries, Icc) != NewLUT -> OutputEntries) { + return FALSE; + } + AdjustEndianessArray16(PtrW, NewLUT -> OutputEntries); AllLinear += cmsIsLinear(NewLUT -> L2[i], NewLUT -> OutputEntries); } @@ -814,6 +892,8 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) cmsCalcCLUT16Params(NewLUT -> cLutPoints, NewLUT -> InputChan, NewLUT -> OutputChan, &NewLUT -> CLut16params); + + return TRUE; } @@ -830,17 +910,15 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) BaseType = ReadBase(Icc); - switch (BaseType) { - case 0x9478ee00L: // Monaco 2 profiler is BROKEN! + case ((icTagTypeSignature) 0x9478ee00): // Monaco 2 profiler is BROKEN! case icSigCurveType: - Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return NULL; AdjustEndianess32((LPBYTE) &Count); - switch (Count) { case 0: // Linear. @@ -855,7 +933,7 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) { WORD SingleGammaFixed; - Icc ->Read(&SingleGammaFixed, sizeof(WORD), 1, Icc); + if (Icc ->Read(&SingleGammaFixed, sizeof(WORD), 1, Icc) != 1) return NULL; AdjustEndianess16((LPBYTE) &SingleGammaFixed); return cmsBuildGamma(4096, Convert8Fixed8(SingleGammaFixed)); } @@ -865,10 +943,9 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) NewGamma = cmsAllocGamma(Count); if (!NewGamma) return NULL; - Icc ->Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc); - + if (Icc ->Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc) != Count) + return NULL; AdjustEndianessArray16(NewGamma -> GammaTable, Count); - return NewGamma; } } @@ -885,11 +962,11 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) icUInt16Number Type; int i; - Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc); - Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc); + if (Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc) != 1) return NULL; + if (Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc) != 1) return NULL; AdjustEndianess16((LPBYTE) &Type); - if (Type > 5) { + if (Type > 4) { cmsSignalError(LCMS_ERRC_ABORTED, "Unknown parametric curve type '%d' found.", Type); return NULL; @@ -900,7 +977,7 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) for (i=0; i < n; i++) { Num = 0; - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); + if (Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc) != 1) return NULL; Params[i] = Convert15Fixed16(Num); } @@ -938,7 +1015,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) case 0x9478ee00L: // Monaco 2 profiler is BROKEN! case icSigCurveType: - Icc -> Read(&Count, sizeof(icUInt32Number), 1, Icc); + if (Icc -> Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return NULL; AdjustEndianess32((LPBYTE) &Count); @@ -948,6 +1025,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) NewGamma = cmsAllocGamma(2); if (!NewGamma) return NULL; + NewGamma -> GammaTable[0] = 0; NewGamma -> GammaTable[1] = 0xFFFF; return NewGamma; @@ -955,7 +1033,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) case 1: { WORD SingleGammaFixed; - Icc -> Read(&SingleGammaFixed, sizeof(WORD), 1, Icc); + if (Icc -> Read(&SingleGammaFixed, sizeof(WORD), 1, Icc) != 1) return NULL; AdjustEndianess16((LPBYTE) &SingleGammaFixed); return cmsBuildGamma(4096, 1./Convert8Fixed8(SingleGammaFixed)); } @@ -965,7 +1043,8 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) NewGamma = cmsAllocGamma(Count); if (!NewGamma) return NULL; - Icc -> Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc); + if (Icc -> Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc) != Count) + return NULL; AdjustEndianessArray16(NewGamma -> GammaTable, Count); @@ -992,11 +1071,11 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) int i; - Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc); - Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc); + if (Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc) != 1) return NULL; + if (Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc) != 1) return NULL; AdjustEndianess16((LPBYTE) &Type); - if (Type > 5) { + if (Type > 4) { cmsSignalError(LCMS_ERRC_ABORTED, "Unknown parametric curve type '%d' found.", Type); return NULL; @@ -1006,7 +1085,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) n = ParamsByType[Type]; for (i=0; i < n; i++) { - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); + if (Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc) != 1) return NULL; Params[i] = Convert15Fixed16(Num); } @@ -1028,7 +1107,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) // V4 stuff. Read matrix for LutAtoB and LutBtoA static -BOOL ReadMatrixOffset(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, DWORD dwFlags) +LCMSBOOL ReadMatrixOffset(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, DWORD dwFlags) { icS15Fixed16Number All[12]; @@ -1038,7 +1117,8 @@ BOOL ReadMatrixOffset(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, DWORD d if (Icc -> Seek(Icc, Offset)) return FALSE; - Icc ->Read(All, sizeof(icS15Fixed16Number), 12, Icc); + if (Icc ->Read(All, sizeof(icS15Fixed16Number), 12, Icc) != 12) + return FALSE; for (i=0; i < 12; i++) AdjustEndianess32((LPBYTE) &All[i]); @@ -1067,17 +1147,26 @@ BOOL ReadMatrixOffset(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, DWORD d // V4 stuff. Read CLUT part for LutAtoB and LutBtoA static -BOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) +LCMSBOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) { - + unsigned int j; icCLutStruct CLUT; if (Icc -> Seek(Icc, Offset)) return FALSE; - Icc ->Read(&CLUT, sizeof(icCLutStruct), 1, Icc); + if (Icc ->Read(&CLUT, sizeof(icCLutStruct), 1, Icc) != 1) return FALSE; - cmsAlloc3DGrid(NewLUT, CLUT.gridPoints[0], NewLUT ->InputChan, - NewLUT ->OutputChan); + for (j=1; j < NewLUT ->InputChan; j++) { + if (CLUT.gridPoints[0] != CLUT.gridPoints[j]) { + cmsSignalError(LCMS_ERRC_ABORTED, "CLUT with different granulatity is currently unsupported."); + return FALSE; + } + + + } + + if (cmsAlloc3DGrid(NewLUT, CLUT.gridPoints[0], NewLUT ->InputChan, + NewLUT ->OutputChan) == NULL) return FALSE; // Precission can be 1 or 2 bytes @@ -1087,7 +1176,7 @@ BOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) unsigned int i; for (i=0; i < NewLUT->Tsize / sizeof(WORD); i++) { - Icc ->Read(&v, sizeof(BYTE), 1, Icc); + if (Icc ->Read(&v, sizeof(BYTE), 1, Icc) != 1) return FALSE; NewLUT->T[i] = TO16_TAB(v); } @@ -1095,10 +1184,10 @@ BOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) else if (CLUT.prec == 2) { - Icc ->Read(NewLUT ->T, sizeof(WORD), - NewLUT->Tsize / sizeof(WORD), Icc); + size_t n = NewLUT->Tsize / sizeof(WORD); - AdjustEndianessArray16(NewLUT ->T, NewLUT->Tsize / sizeof(WORD)); + if (Icc ->Read(NewLUT ->T, sizeof(WORD), n, Icc) != n) return FALSE; + AdjustEndianessArray16(NewLUT ->T, NewLUT->Tsize / sizeof(WORD)); } else { cmsSignalError(LCMS_ERRC_ABORTED, "Unknow precission of '%d'", CLUT.prec); @@ -1109,6 +1198,22 @@ BOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) } +static +void ResampleCurves(LPGAMMATABLE Curves[], int nCurves) +{ + int i; + LPSAMPLEDCURVE sc; + + for (i=0; i < nCurves; i++) { + sc = cmsConvertGammaToSampledCurve(Curves[i], 4096); + cmsFreeGamma(Curves[i]); + Curves[i] = cmsConvertSampledCurveToGamma(sc, 0xFFFF); + cmsFreeSampledCurve(sc); + } + +} + + static void SkipAlignment(LPLCMSICCPROFILE Icc) { @@ -1121,7 +1226,7 @@ void SkipAlignment(LPLCMSICCPROFILE Icc) // Read a set of curves from specific offset static -BOOL ReadSetOfCurves(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, int nLocation) +LCMSBOOL ReadSetOfCurves(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, int nLocation) { LPGAMMATABLE Curves[MAXCHANNELS]; unsigned int i, nCurves; @@ -1134,20 +1239,41 @@ BOOL ReadSetOfCurves(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, int nLoc else nCurves = NewLUT ->OutputChan; + ZeroMemory(Curves, sizeof(Curves)); for (i=0; i < nCurves; i++) { Curves[i] = ReadCurve(Icc); + if (Curves[i] == NULL) goto Error; SkipAlignment(Icc); + } + // March-26'08: some V4 profiles may have different sampling + // rates, in this case resample all curves to maximum + + for (i=1; i < nCurves; i++) { + if (Curves[i]->nEntries != Curves[0]->nEntries) { + ResampleCurves(Curves, nCurves); + break; + } } NewLUT = cmsAllocLinearTable(NewLUT, Curves, nLocation); + if (NewLUT == NULL) goto Error; for (i=0; i < nCurves; i++) cmsFreeGamma(Curves[i]); return TRUE; +Error: + + for (i=0; i < nCurves; i++) + if (Curves[i]) + cmsFreeGamma(Curves[i]); + + return FALSE; + + } // V4 stuff. LutAtoB type @@ -1160,22 +1286,28 @@ BOOL ReadSetOfCurves(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, int nLoc // L2 = B curves static -BOOL ReadLUT_A2B(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig) +LCMSBOOL ReadLUT_A2B(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig) { icLutAtoB LUT16; - Icc ->Read(&LUT16, sizeof(icLutAtoB), 1, Icc); + if (Icc ->Read(&LUT16, sizeof(icLutAtoB), 1, Icc) != 1) return FALSE; NewLUT -> InputChan = LUT16.inputChan; NewLUT -> OutputChan = LUT16.outputChan; + // Validate the NewLUT here to avoid excessive number of channels + // (leading to stack-based buffer overflow in ReadSetOfCurves). + // Needs revalidation after table size is filled in. + if (!_cmsValidateLUT(NewLUT)) { + return FALSE; + } + AdjustEndianess32((LPBYTE) &LUT16.offsetB); AdjustEndianess32((LPBYTE) &LUT16.offsetMat); AdjustEndianess32((LPBYTE) &LUT16.offsetM); AdjustEndianess32((LPBYTE) &LUT16.offsetC); AdjustEndianess32((LPBYTE) &LUT16.offsetA); - if (LUT16.offsetB != 0) ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetB, NewLUT, 2); @@ -1220,15 +1352,22 @@ BOOL ReadLUT_A2B(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSig // V4 stuff. LutBtoA type static -BOOL ReadLUT_B2A(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig) +LCMSBOOL ReadLUT_B2A(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig) { icLutBtoA LUT16; - Icc ->Read(&LUT16, sizeof(icLutBtoA), 1, Icc); + if (Icc ->Read(&LUT16, sizeof(icLutBtoA), 1, Icc) != 1) return FALSE; NewLUT -> InputChan = LUT16.inputChan; NewLUT -> OutputChan = LUT16.outputChan; + // Validate the NewLUT here to avoid excessive number of channels + // (leading to stack-based buffer overflow in ReadSetOfCurves). + // Needs revalidation after table size is filled in. + if (!_cmsValidateLUT(NewLUT)) { + return FALSE; + } + AdjustEndianess32((LPBYTE) &LUT16.offsetB); AdjustEndianess32((LPBYTE) &LUT16.offsetMat); AdjustEndianess32((LPBYTE) &LUT16.offsetM); @@ -1242,7 +1381,6 @@ BOOL ReadLUT_B2A(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSi if (LUT16.offsetMat != 0) ReadMatrixOffset(Icc, BaseOffset + LUT16.offsetMat, NewLUT, LUT_HASMATRIX3); - if (LUT16.offsetM != 0) ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetM, NewLUT, 3); @@ -1294,7 +1432,7 @@ LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig) // If is in memory, the LUT is already there, so throw a copy - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { return cmsDupLUT((LPLUT) Icc ->TagPtrs[n]); } @@ -1308,8 +1446,8 @@ LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig) NewLUT = cmsAllocLUT(); - if (!NewLUT) - { + if (!NewLUT) { + cmsSignalError(LCMS_ERRC_ABORTED, "cmsAllocLUT() failed"); return NULL; } @@ -1317,11 +1455,29 @@ LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig) switch (BaseType) { - case icSigLut8Type: ReadLUT8(Icc, NewLUT, sig); break; - case icSigLut16Type: ReadLUT16(Icc, NewLUT); break; + case icSigLut8Type: if (!ReadLUT8(Icc, NewLUT, sig)) { + cmsFreeLUT(NewLUT); + return NULL; + } + break; - case icSiglutAtoBType: ReadLUT_A2B(Icc, NewLUT, offset, sig); break; - case icSiglutBtoAType: ReadLUT_B2A(Icc, NewLUT, offset, sig); break; + case icSigLut16Type: if (!ReadLUT16(Icc, NewLUT)) { + cmsFreeLUT(NewLUT); + return NULL; + } + break; + + case icSiglutAtoBType: if (!ReadLUT_A2B(Icc, NewLUT, offset, sig)) { + cmsFreeLUT(NewLUT); + return NULL; + } + break; + + case icSiglutBtoAType: if (!ReadLUT_B2A(Icc, NewLUT, offset, sig)) { + cmsFreeLUT(NewLUT); + return NULL; + } + break; default: cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature %lx found.", BaseType); cmsFreeLUT(NewLUT); @@ -1335,16 +1491,23 @@ LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig) // Sets the language & country preferences. Used only in ICC 4.0 profiles -void LCMSEXPORT cmsSetLanguage(int LanguageCode, int CountryCode) +void LCMSEXPORT cmsSetLanguage(const char LanguageCode[4], const char CountryCode[4]) { - GlobalLanguageCode = LanguageCode; - GlobalCountryCode = CountryCode; + + int LanguageCodeInt = *(int *) LanguageCode; + int CountryCodeInt = *(int *) CountryCode; + + AdjustEndianess32((LPBYTE) &LanguageCodeInt); + AdjustEndianess32((LPBYTE) &CountryCodeInt); + + GlobalLanguageCode = LanguageCodeInt; + GlobalCountryCode = CountryCodeInt; } // Some tags (e.g, 'pseq') can have text tags embedded. This function -// handles such special case. +// handles such special case. Returns -1 on error, or the number of bytes left on success. static int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t size_max) @@ -1353,7 +1516,6 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si BaseType = ReadBase(Icc); - size -= sizeof(icTagBase); switch (BaseType) { @@ -1365,50 +1527,54 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si icUInt16Number ScriptCodeCode, Dummy; icUInt8Number ScriptCodeCount; - Icc ->Read(&AsciiCount, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&AsciiCount, sizeof(icUInt32Number), 1, Icc) != 1) return -1; - if (size < sizeof(icUInt32Number)) return (int) size; + if (size < sizeof(icUInt32Number)) return (int) size; size -= sizeof(icUInt32Number); AdjustEndianess32((LPBYTE) &AsciiCount); Icc ->Read(Name, 1, (AsciiCount >= size_max) ? (size_max-1) : AsciiCount, Icc); - if (size < AsciiCount) return (int) size; + if (size < AsciiCount) return (int) size; size -= AsciiCount; // Skip Unicode code - Icc ->Read(&UnicodeCode, sizeof(icUInt32Number), 1, Icc); - if (size < sizeof(icUInt32Number)) return (int) size; + if (Icc ->Read(&UnicodeCode, sizeof(icUInt32Number), 1, Icc) != 1) return -1; + if (size < sizeof(icUInt32Number)) return (int) size; size -= sizeof(icUInt32Number); - Icc ->Read(&UnicodeCount, sizeof(icUInt32Number), 1, Icc); - if (size < sizeof(icUInt32Number)) return (int) size; + if (Icc ->Read(&UnicodeCount, sizeof(icUInt32Number), 1, Icc) != 1) return -1; + if (size < sizeof(icUInt32Number)) return (int) size; size -= sizeof(icUInt32Number); AdjustEndianess32((LPBYTE) &UnicodeCount); if (UnicodeCount > size) return (int) size; - for (i=0; i < UnicodeCount; i++) - Icc ->Read(&Dummy, sizeof(icUInt16Number), 1, Icc); - - size -= UnicodeCount * sizeof(icUInt16Number); + for (i=0; i < UnicodeCount; i++) { + size_t nread = Icc ->Read(&Dummy, sizeof(icUInt16Number), 1, Icc); + if (nread != 1) return (int) size; + size -= sizeof(icUInt16Number); + } // Skip ScriptCode code - Icc ->Read(&ScriptCodeCode, sizeof(icUInt16Number), 1, Icc); + if (Icc ->Read(&ScriptCodeCode, sizeof(icUInt16Number), 1, Icc) != 1) return -1; size -= sizeof(icUInt16Number); - Icc ->Read(&ScriptCodeCount, sizeof(icUInt8Number), 1, Icc); + if (Icc ->Read(&ScriptCodeCount, sizeof(icUInt8Number), 1, Icc) != 1) return -1; size -= sizeof(icUInt8Number); + // Should remain 67 bytes as filler + if (size < 67) return (int) size; - for (i=0; i < 67; i++) - Icc ->Read(&Dummy, sizeof(icUInt8Number), 1, Icc); - - size -= 67; + for (i=0; i < 67; i++) { + size_t nread = Icc ->Read(&Dummy, sizeof(icUInt8Number), 1, Icc); + if (nread != 1) return (int) size; + size --; + } } break; @@ -1425,7 +1591,7 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si size = size_max - 1; } - Icc -> Read(Name, 1, size, Icc); + if (Icc -> Read(Name, 1, size, Icc) != size) return -1; for (i=0; i < Missing; i++) Icc -> Read(&Dummy, 1, 1, Icc); @@ -1445,9 +1611,9 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si wchar_t* wchar = L""; - Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return -1; AdjustEndianess32((LPBYTE) &Count); - Icc ->Read(&RecLen, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&RecLen, sizeof(icUInt32Number), 1, Icc) != 1) return -1; AdjustEndianess32((LPBYTE) &RecLen); if (RecLen != 12) { @@ -1458,15 +1624,15 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si for (i=0; i < Count; i++) { - Icc ->Read(&Language, sizeof(icUInt16Number), 1, Icc); + if (Icc ->Read(&Language, sizeof(icUInt16Number), 1, Icc) != 1) return -1; AdjustEndianess16((LPBYTE) &Language); - Icc ->Read(&Country, sizeof(icUInt16Number), 1, Icc); + if (Icc ->Read(&Country, sizeof(icUInt16Number), 1, Icc) != 1) return -1; AdjustEndianess16((LPBYTE) &Country); - Icc ->Read(&ThisLen, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&ThisLen, sizeof(icUInt32Number), 1, Icc) != 1) return -1; AdjustEndianess32((LPBYTE) &ThisLen); - Icc ->Read(&ThisOffset, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&ThisOffset, sizeof(icUInt32Number), 1, Icc) != 1) return -1; AdjustEndianess32((LPBYTE) &ThisOffset); if (Language == GlobalLanguageCode || Offset == 0) { @@ -1492,14 +1658,18 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si for (i=0; i < Offset; i++) { char Discard; - - Icc ->Read(&Discard, 1, 1, Icc); + if (Icc ->Read(&Discard, 1, 1, Icc) != 1) return -1; } - wchar = (wchar_t*) malloc(Len+2); + + // Bound len + if (Len < 0) Len = 0; + if (Len > 20*1024) Len = 20 * 1024; + + wchar = (wchar_t*) _cmsMalloc(Len*sizeof(wchar_t)+2); if (!wchar) return -1; - Icc ->Read(wchar, 1, Len, Icc); + if (Icc ->Read(wchar, 1, Len, Icc) != Len) return -1; AdjustEndianessArray16((LPWORD) wchar, Len / 2); wchar[Len / 2] = L'\0'; @@ -1509,7 +1679,7 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si Name[0] = 0; // Error } - free((void*) wchar); + _cmsFree((void*) wchar); } break; @@ -1522,8 +1692,7 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si } -// Take an ASCII item. Takes at most LCMS_DESC_MAX - +// Take an ASCII item. Takes at most size_max bytes int LCMSEXPORT cmsReadICCTextEx(cmsHPROFILE hProfile, icTagSignature sig, char *Name, size_t size_max) { @@ -1535,19 +1704,27 @@ int LCMSEXPORT cmsReadICCTextEx(cmsHPROFILE hProfile, icTagSignature sig, char * if (n < 0) return -1; - if (!Icc -> stream) { + size = Icc -> TagSizes[n]; + + if (Icc -> TagPtrs[n]) { + + if (size > size_max) + size = size_max; + + CopyMemory(Name, Icc -> TagPtrs[n], size); - CopyMemory(Name, Icc -> TagPtrs[n], Icc -> TagSizes[n]); return (int) Icc -> TagSizes[n]; } offset = Icc -> TagOffsets[n]; - size = Icc -> TagSizes[n]; + if (Icc -> Seek(Icc, offset)) return -1; - return ReadEmbeddedTextTag(Icc, size, Name, size_max); + if (ReadEmbeddedTextTag(Icc, size, Name, size_max) < 0) return -1; + + return size; } // Keep compatibility with older versions @@ -1561,7 +1738,7 @@ int LCMSEXPORT cmsReadICCText(cmsHPROFILE hProfile, icTagSignature sig, char *Te // Take an XYZ item static -int ReadICCXYZ(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIEXYZ Value, BOOL lIsFatal) +int ReadICCXYZ(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIEXYZ Value, LCMSBOOL lIsFatal) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; icTagTypeSignature BaseType; @@ -1573,7 +1750,7 @@ int ReadICCXYZ(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIEXYZ Value, BOOL if (n < 0) return -1; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { CopyMemory(Value, Icc -> TagPtrs[n], Icc -> TagSizes[n]); return (int) Icc -> TagSizes[n]; @@ -1628,7 +1805,7 @@ int ReadICCXYZArray(cmsHPROFILE hProfile, icTagSignature sig, LPMAT3 v) if (n < 0) return -1; // Not found - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { CopyMemory(v, Icc -> TagPtrs[n], Icc -> TagSizes[n]); return (int) Icc -> TagSizes[n]; @@ -1677,7 +1854,7 @@ int ReadICCXYZArray(cmsHPROFILE hProfile, icTagSignature sig, LPMAT3 v) // Primaries are to be in xyY notation -BOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile) { if (ReadICCXYZ(hProfile, icSigRedColorantTag, &Dest -> Red, TRUE) < 0) return FALSE; if (ReadICCXYZ(hProfile, icSigGreenColorantTag, &Dest -> Green, TRUE) < 0) return FALSE; @@ -1687,7 +1864,7 @@ BOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile) } -BOOL cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile) +LCMSBOOL cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile) { cmsCIEXYZTRIPLE Primaries; @@ -1704,7 +1881,7 @@ BOOL cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile) // Always return a suitable matrix -BOOL cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile) +LCMSBOOL cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile) { if (ReadICCXYZArray(hProfile, icSigChromaticAdaptationTag, r) < 0) { @@ -1741,7 +1918,7 @@ LPGAMMATABLE LCMSEXPORT cmsReadICCGamma(cmsHPROFILE hProfile, icTagSignature sig if (n < 0) return NULL; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { return cmsDupGamma((LPGAMMATABLE) Icc -> TagPtrs[n]); } @@ -1769,7 +1946,7 @@ LPGAMMATABLE LCMSEXPORT cmsReadICCGammaReversed(cmsHPROFILE hProfile, icTagSigna if (n < 0) return NULL; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { return cmsReverseGamma(256, (LPGAMMATABLE) Icc -> TagPtrs[n]); } @@ -1785,7 +1962,7 @@ LPGAMMATABLE LCMSEXPORT cmsReadICCGammaReversed(cmsHPROFILE hProfile, icTagSigna // Check Named color header static -BOOL CheckHeader(LPcmsNAMEDCOLORLIST v, icNamedColor2* nc2) +LCMSBOOL CheckHeader(LPcmsNAMEDCOLORLIST v, icNamedColor2* nc2) { if (v ->Prefix[0] == 0 && v ->Suffix[0] == 0 && v ->ColorantCount == 0) return TRUE; @@ -1809,13 +1986,13 @@ int cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSig if (n < 0) return 0; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { // This replaces actual named color list. size_t size = Icc -> TagSizes[n]; if (v ->NamedColorList) cmsFreeNamedColorList(v ->NamedColorList); - v -> NamedColorList = (LPcmsNAMEDCOLORLIST) malloc(size); + v -> NamedColorList = (LPcmsNAMEDCOLORLIST) _cmsMalloc(size); CopyMemory(v -> NamedColorList, Icc ->TagPtrs[n], size); return v ->NamedColorList->nColors; } @@ -1844,7 +2021,7 @@ int cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSig icNamedColor2 nc2; unsigned int i, j; - Icc -> Read(&nc2, sizeof(icNamedColor2) - SIZEOF_UINT8_ALIGNED, 1, Icc); + if (Icc -> Read(&nc2, sizeof(icNamedColor2) - SIZEOF_UINT8_ALIGNED, 1, Icc) != 1) return 0; AdjustEndianess32((LPBYTE) &nc2.vendorFlag); AdjustEndianess32((LPBYTE) &nc2.count); AdjustEndianess32((LPBYTE) &nc2.nDeviceCoords); @@ -1854,6 +2031,11 @@ int cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSig return 0; } + if (nc2.nDeviceCoords > MAXCHANNELS) { + cmsSignalError(LCMS_ERRC_WARNING, "Too many device coordinates."); + return 0; + } + strncpy(v ->NamedColorList->Prefix, (const char*) nc2.prefix, 32); strncpy(v ->NamedColorList->Suffix, (const char*) nc2.suffix, 32); v ->NamedColorList->Prefix[32] = v->NamedColorList->Suffix[32] = 0; @@ -1900,7 +2082,8 @@ int cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSig LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagSignature sig) { - icInt32Number n, Count, i; + icInt32Number n; + icUInt32Number Count, i; size_t offset; icTagTypeSignature BaseType; LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -1910,10 +2093,12 @@ LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagS if (n < 0) return NULL; // Not found - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { size_t size = Icc -> TagSizes[n]; - void* v = malloc(size); + void* v = _cmsMalloc(size); + + if (v == NULL) return NULL; CopyMemory(v, Icc -> TagPtrs[n], size); return (LPcmsNAMEDCOLORLIST) v; } @@ -1932,13 +2117,17 @@ LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagS } - Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return NULL; AdjustEndianess32((LPBYTE) &Count); + if (Count > MAXCHANNELS) { + cmsSignalError(LCMS_ERRC_ABORTED, "Too many colorants '%lx'", Count); + return NULL; + } + List = cmsAllocNamedColorList(Count); for (i=0; i < Count; i++) { - if (!Icc ->Read(List->List[i].Name, 1, 32 , Icc)) goto Error; if (!Icc ->Read(List->List[i].PCS, sizeof(icUInt16Number), 3, Icc)) goto Error; AdjustEndianessArray16(List->List[i].PCS, 3); @@ -1965,7 +2154,7 @@ const char* LCMSEXPORT cmsTakeManufacturer(cmsHPROFILE hProfile) if (cmsIsTag(hProfile, icSigDeviceMfgDescTag)) { - cmsReadICCText(hProfile, icSigDeviceMfgDescTag, Manufacturer); + cmsReadICCTextEx(hProfile, icSigDeviceMfgDescTag, Manufacturer, LCMS_DESC_MAX); } return Manufacturer; @@ -1982,7 +2171,7 @@ const char* LCMSEXPORT cmsTakeModel(cmsHPROFILE hProfile) if (cmsIsTag(hProfile, icSigDeviceModelDescTag)) { - cmsReadICCText(hProfile, icSigDeviceModelDescTag, Model); + cmsReadICCTextEx(hProfile, icSigDeviceModelDescTag, Model, LCMS_DESC_MAX); } return Model; @@ -1995,10 +2184,9 @@ const char* LCMSEXPORT cmsTakeCopyright(cmsHPROFILE hProfile) static char Copyright[LCMS_DESC_MAX] = ""; Copyright[0] = 0; - if (cmsIsTag(hProfile, icSigCopyrightTag)) { - cmsReadICCText(hProfile, icSigCopyrightTag, Copyright); + cmsReadICCTextEx(hProfile, icSigCopyrightTag, Copyright, LCMS_DESC_MAX); } return Copyright; @@ -2009,7 +2197,7 @@ const char* LCMSEXPORT cmsTakeCopyright(cmsHPROFILE hProfile) const char* LCMSEXPORT cmsTakeProductName(cmsHPROFILE hProfile) { - static char Name[2048]; + static char Name[LCMS_DESC_MAX*2+4]; char Manufacturer[LCMS_DESC_MAX], Model[LCMS_DESC_MAX]; Name[0] = '\0'; @@ -2017,19 +2205,19 @@ const char* LCMSEXPORT cmsTakeProductName(cmsHPROFILE hProfile) if (cmsIsTag(hProfile, icSigDeviceMfgDescTag)) { - cmsReadICCText(hProfile, icSigDeviceMfgDescTag, Manufacturer); + cmsReadICCTextEx(hProfile, icSigDeviceMfgDescTag, Manufacturer, LCMS_DESC_MAX); } if (cmsIsTag(hProfile, icSigDeviceModelDescTag)) { - cmsReadICCText(hProfile, icSigDeviceModelDescTag, Model); + cmsReadICCTextEx(hProfile, icSigDeviceModelDescTag, Model, LCMS_DESC_MAX); } if (!Manufacturer[0] && !Model[0]) { if (cmsIsTag(hProfile, icSigProfileDescriptionTag)) { - cmsReadICCText(hProfile, icSigProfileDescriptionTag, Name); + cmsReadICCTextEx(hProfile, icSigProfileDescriptionTag, Name, LCMS_DESC_MAX); return Name; } else return "{no name}"; @@ -2129,7 +2317,7 @@ const char* LCMSEXPORT cmsTakeProductInfo(cmsHPROFILE hProfile) // Extract the target data as a big string. Does not signal if tag is not present. -BOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len) +LCMSBOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; int n; @@ -2142,7 +2330,11 @@ BOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* *len = Icc -> TagSizes[n]; - *Data = (char*) malloc(*len + 1); // Plus zero marker + + // Make sure that is reasonable (600K) + if (*len > 600*1024) *len = 600*1024; + + *Data = (char*) _cmsMalloc(*len + 1); // Plus zero marker if (!*Data) { @@ -2162,7 +2354,7 @@ BOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* -BOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; int n; @@ -2170,8 +2362,8 @@ BOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile n = _cmsSearchTag(Icc, icSigCalibrationDateTimeTag, FALSE); if (n < 0) return FALSE; - if (!Icc ->stream) - { + if (Icc ->TagPtrs[n]) { + CopyMemory(Dest, Icc ->TagPtrs[n], sizeof(struct tm)); } else @@ -2212,9 +2404,10 @@ LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE hProfile) size = Icc -> TagSizes[n]; if (size < 12) return NULL; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { - OutSeq = (LPcmsSEQ) malloc(size); + OutSeq = (LPcmsSEQ) _cmsMalloc(size); + if (OutSeq == NULL) return NULL; CopyMemory(OutSeq, Icc ->TagPtrs[n], size); return OutSeq; } @@ -2231,8 +2424,13 @@ LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE hProfile) Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc); AdjustEndianess32((LPBYTE) &Count); + if (Count > 1000) { + return NULL; + } + size = sizeof(int) + Count * sizeof(cmsPSEQDESC); - OutSeq = (LPcmsSEQ) malloc(size); + OutSeq = (LPcmsSEQ) _cmsMalloc(size); + if (OutSeq == NULL) return NULL; OutSeq ->n = Count; @@ -2268,181 +2466,11 @@ LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE hProfile) void LCMSEXPORT cmsFreeProfileSequenceDescription(LPcmsSEQ pseq) { if (pseq) - free(pseq); + _cmsFree(pseq); } -// Extended gamut -- an HP extension - - -LPcmsGAMUTEX LCMSEXPORT cmsReadExtendedGamut(cmsHPROFILE hProfile, int index) -{ - LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; - size_t size, offset; - icUInt32Number off_samp, off_desc, off_vc; - int n; - icTagTypeSignature BaseType; - icColorSpaceSignature CoordSig; - icUInt16Number Method, Usage; - icUInt32Number GamutCount, SamplesCount; - LPcmsGAMUTEX gex; - size_t Offsets[256]; - size_t i, Actual, Loc; - icS15Fixed16Number Num; - icUInt16Number Surround; - - - n = _cmsSearchTag(Icc, icSigHPGamutDescTag, FALSE); - if (n < 0) return NULL; - - if (!Icc ->stream) return NULL; // In memory is not supported - - // Read the header - - offset = Icc -> TagOffsets[n]; - - if (Icc -> Seek(Icc, offset)) - return NULL; - - // Here is the beginning of tag - Actual = Icc ->Tell(Icc); - - - BaseType = ReadBase(Icc); - - if (BaseType != icSigHPGamutDescType) { - cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature '%lx' found.", BaseType); - return NULL; - } - - - // Read the gamut descriptors count - Icc ->Read(&GamutCount, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &GamutCount); - - - if (GamutCount >= 256) { - cmsSignalError(LCMS_ERRC_ABORTED, "Too many gamut structures '%d'.", GamutCount); - return NULL; - } - - // Read the directory - - for (i=0; i < GamutCount; i++) { - - Icc ->Read(&Offsets[i], sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &Offsets[i]); - } - - - // Is there such element? - if (index >= (int) GamutCount) return NULL; - Loc = Actual + Offsets[index]; - - - // Go to specified index - if (Icc -> Seek(Icc, Loc)) - return NULL; - - - // Read all members - Icc ->Read(&CoordSig, sizeof(icColorSpaceSignature), 1, Icc); - AdjustEndianess32((LPBYTE) &CoordSig); - - Icc ->Read(&Method, sizeof(icUInt16Number), 1, Icc); - AdjustEndianess16((LPBYTE) &Method); - - Icc ->Read(&Usage, sizeof(icUInt16Number), 1, Icc); - AdjustEndianess16((LPBYTE) &Usage); - - Icc ->Read(&SamplesCount, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &SamplesCount); - - Icc ->Read(&off_samp, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &off_samp); - - Icc ->Read(&off_desc, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &off_desc); - - Icc ->Read(&off_vc, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &off_vc); - - - size = sizeof(cmsGAMUTEX) + (SamplesCount - 1) * sizeof(double); - - gex = (LPcmsGAMUTEX) malloc(size); - if (gex == NULL) return NULL; - - - gex ->CoordSig = CoordSig; - gex ->Method = Method; - gex ->Usage = Usage; - gex ->Count = SamplesCount; - - - // Read data - if (Icc -> Seek(Icc, Loc + off_samp)) - return NULL; - - for (i=0; i < SamplesCount; i++) { - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Data[i] = Convert15Fixed16(Num); - } - - - // Read mluc - if (Icc -> Seek(Icc, Loc + off_desc)) { - - free(gex); - return NULL; - } - - ReadEmbeddedTextTag(Icc, 256, gex ->Description, LCMS_DESC_MAX); - - - // Read viewing conditions - if (Icc -> Seek(Icc, Loc + off_vc)) { - free(gex); - return NULL; - } - - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.whitePoint.X = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.whitePoint.Y = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.whitePoint.Z = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.La = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.Yb = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.D_value = Convert15Fixed16(Num); - - Icc -> Read(&Surround, sizeof(icUInt16Number), 1, Icc); - AdjustEndianess16((LPBYTE) &Surround); - gex ->Vc.surround = Surround; - - - // All OK - return gex; - -} - - - -void LCMSEXPORT cmsFreeExtendedGamut(LPcmsGAMUTEX gex) -{ - if (gex) - free(gex); -} // Read a few tags that are hardly required @@ -2564,6 +2592,7 @@ cmsHPROFILE LCMSEXPORT cmsOpenProfileFromFile(const char *lpFileName, const char NewIcc = (LPLCMSICCPROFILE) (LPSTR) hEmpty; NewIcc -> IsWrite = TRUE; strncpy(NewIcc ->PhysicalFile, lpFileName, MAX_PATH-1); + NewIcc ->PhysicalFile[MAX_PATH-1] = 0; // Save LUT as 8 bit @@ -2609,14 +2638,14 @@ cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, DWORD dwSize) -BOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; - BOOL rc = TRUE; + LCMSBOOL rc = TRUE; + icInt32Number i; if (!Icc) return FALSE; - // Was open in write mode? if (Icc ->IsWrite) { @@ -2624,21 +2653,15 @@ BOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) rc = _cmsSaveProfile(hProfile, Icc ->PhysicalFile); } - - if (Icc -> stream == NULL) { // Was a memory (i.e. not serialized) profile? - - - icInt32Number i; // Yes, free tags - - for (i=0; i < Icc -> TagCount; i++) { + for (i=0; i < Icc -> TagCount; i++) { if (Icc -> TagPtrs[i]) free(Icc -> TagPtrs[i]); - } - } - else Icc -> Close(Icc); // No, close the stream + if (Icc -> stream != NULL) { // Was a memory (i.e. not serialized) profile? + Icc -> Close(Icc); // No, close the stream + } free(Icc); // Free placeholder memory @@ -2652,11 +2675,11 @@ BOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) static -BOOL SaveWordsTable(int nEntries, LPWORD Tab, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveWordsTable(int nEntries, LPWORD Tab, LPLCMSICCPROFILE Icc) { size_t nTabSize = sizeof(WORD) * nEntries; - LPWORD PtrW = (LPWORD) malloc(nTabSize); - BOOL rc; + LPWORD PtrW = (LPWORD) _cmsMalloc(nTabSize); + LCMSBOOL rc; if (!PtrW) return FALSE; CopyMemory(PtrW, Tab, nTabSize); @@ -2672,7 +2695,7 @@ BOOL SaveWordsTable(int nEntries, LPWORD Tab, LPLCMSICCPROFILE Icc) // Saves profile header static -BOOL SaveHeader(LPLCMSICCPROFILE Icc) +LCMSBOOL SaveHeader(LPLCMSICCPROFILE Icc) { icHeader Header; time_t now = time(NULL); @@ -2727,7 +2750,7 @@ BOOL SaveHeader(LPLCMSICCPROFILE Icc) // Setup base marker static -BOOL SetupBase(icTagTypeSignature sig, LPLCMSICCPROFILE Icc) +LCMSBOOL SetupBase(icTagTypeSignature sig, LPLCMSICCPROFILE Icc) { icTagBase Base; @@ -2737,10 +2760,10 @@ BOOL SetupBase(icTagTypeSignature sig, LPLCMSICCPROFILE Icc) } -// Store an XYZ tag +// Store a XYZ tag static -BOOL SaveXYZNumber(LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveXYZNumber(LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc) { icXYZNumber XYZ; @@ -2756,72 +2779,97 @@ BOOL SaveXYZNumber(LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc) } +// Store a XYZ array. + +static +LCMSBOOL SaveXYZArray(int n, LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc) +{ + int i; + icXYZNumber XYZ; + + if (!SetupBase(icSigS15Fixed16ArrayType, Icc)) return FALSE; + + for (i=0; i < n; i++) { + + XYZ.X = TransportValue32(DOUBLE_TO_FIXED(Value -> X)); + XYZ.Y = TransportValue32(DOUBLE_TO_FIXED(Value -> Y)); + XYZ.Z = TransportValue32(DOUBLE_TO_FIXED(Value -> Z)); + + if (!Icc -> Write(Icc, sizeof(icXYZNumber), &XYZ)) return FALSE; + + Value++; + } + + return TRUE; +} + + // Save a gamma structure as a table static -BOOL SaveGammaTable(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveGammaTable(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) { - icInt32Number Count; + icInt32Number Count; - if (!SetupBase(icSigCurveType, Icc)) return FALSE; + if (!SetupBase(icSigCurveType, Icc)) return FALSE; - Count = TransportValue32(Gamma->nEntries); + Count = TransportValue32(Gamma->nEntries); - if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE; + if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE; - return SaveWordsTable(Gamma->nEntries, Gamma ->GammaTable, Icc); + return SaveWordsTable(Gamma->nEntries, Gamma ->GammaTable, Icc); } // Save a gamma structure as a one-value static -BOOL SaveGammaOneValue(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveGammaOneValue(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) { - icInt32Number Count; - Fixed32 GammaFixed32; - WORD GammaFixed8; + icInt32Number Count; + Fixed32 GammaFixed32; + WORD GammaFixed8; - if (!SetupBase(icSigCurveType, Icc)) return FALSE; + if (!SetupBase(icSigCurveType, Icc)) return FALSE; - Count = TransportValue32(1); - if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE; + Count = TransportValue32(1); + if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE; - GammaFixed32 = DOUBLE_TO_FIXED(Gamma ->Seed.Params[0]); - GammaFixed8 = (WORD) ((GammaFixed32 >> 8) & 0xFFFF); - GammaFixed8 = TransportValue16(GammaFixed8); + GammaFixed32 = DOUBLE_TO_FIXED(Gamma ->Seed.Params[0]); + GammaFixed8 = (WORD) ((GammaFixed32 >> 8) & 0xFFFF); + GammaFixed8 = TransportValue16(GammaFixed8); - return Icc ->Write(Icc, sizeof(icInt16Number), &GammaFixed8); + return Icc ->Write(Icc, sizeof(icInt16Number), &GammaFixed8); } // Save a gamma structure as a parametric gamma static -BOOL SaveGammaParametric(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveGammaParametric(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) { - icUInt16Number Type, Reserved; - int i, nParams; - int ParamsByType[] = { 1, 3, 4, 5, 7 }; + icUInt16Number Type, Reserved; + int i, nParams; + int ParamsByType[] = { 1, 3, 4, 5, 7 }; - if (!SetupBase(icSigParametricCurveType, Icc)) return FALSE; + if (!SetupBase(icSigParametricCurveType, Icc)) return FALSE; - nParams = ParamsByType[Gamma -> Seed.Type]; + nParams = ParamsByType[Gamma -> Seed.Type]; - Type = (icUInt16Number) TransportValue16((WORD) Gamma -> Seed. Type); - Reserved = (icUInt16Number) TransportValue16((WORD) 0); + Type = (icUInt16Number) TransportValue16((WORD) Gamma -> Seed. Type); + Reserved = (icUInt16Number) TransportValue16((WORD) 0); - Icc -> Write(Icc, sizeof(icInt16Number), &Type); - Icc -> Write(Icc, sizeof(icUInt16Number), &Reserved); + Icc -> Write(Icc, sizeof(icInt16Number), &Type); + Icc -> Write(Icc, sizeof(icUInt16Number), &Reserved); - for (i=0; i < nParams; i++) { + for (i=0; i < nParams; i++) { - icInt32Number val = TransportValue32(DOUBLE_TO_FIXED(Gamma -> Seed.Params[i])); - Icc ->Write(Icc, sizeof(icInt32Number), &val); - } + icInt32Number val = TransportValue32(DOUBLE_TO_FIXED(Gamma -> Seed.Params[i])); + Icc ->Write(Icc, sizeof(icInt32Number), &val); + } - return TRUE; + return TRUE; } @@ -2829,29 +2877,29 @@ BOOL SaveGammaParametric(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) // Save a gamma table static -BOOL SaveGamma(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveGamma(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) { - // Is the gamma curve type supported by ICC format? + // Is the gamma curve type supported by ICC format? - if (Gamma -> Seed.Type < 0 || Gamma -> Seed.Type > 5 || + if (Gamma -> Seed.Type < 0 || Gamma -> Seed.Type > 5 || - // has been modified by user? + // has been modified by user? - _cmsCrc32OfGammaTable(Gamma) != Gamma -> Seed.Crc32) { + _cmsCrc32OfGammaTable(Gamma) != Gamma -> Seed.Crc32) { - return SaveGammaTable(Gamma, Icc); - } + return SaveGammaTable(Gamma, Icc); + } - if (Gamma -> Seed.Type == 1) return SaveGammaOneValue(Gamma, Icc); + if (Gamma -> Seed.Type == 1) return SaveGammaOneValue(Gamma, Icc); - // Only v4 profiles are allowed to hold parametric curves + // Only v4 profiles are allowed to hold parametric curves - if (cmsGetProfileICCversion((cmsHPROFILE) Icc) >= 0x4000000) - return SaveGammaParametric(Gamma, Icc); + if (cmsGetProfileICCversion((cmsHPROFILE) Icc) >= 0x4000000) + return SaveGammaParametric(Gamma, Icc); - // Defaults to save as table + // Defaults to save as table - return SaveGammaTable(Gamma, Icc); + return SaveGammaTable(Gamma, Icc); } @@ -2861,7 +2909,7 @@ BOOL SaveGamma(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) // Save an DESC Tag static -BOOL SaveDescription(const char *Text, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveDescription(const char *Text, LPLCMSICCPROFILE Icc) { icUInt32Number len, Count, TotalSize, AlignedSize; @@ -2893,6 +2941,11 @@ BOOL SaveDescription(const char *Text, LPLCMSICCPROFILE Icc) if (!Icc ->Write(Icc, len, (LPVOID)Text)) return FALSE; AlignedSize -= len; + if (AlignedSize < 0) + AlignedSize = 0; + if (AlignedSize > 255) + AlignedSize = 255; + ZeroMemory(Filler, AlignedSize); if (!Icc ->Write(Icc, AlignedSize, Filler)) return FALSE; @@ -2902,7 +2955,7 @@ BOOL SaveDescription(const char *Text, LPLCMSICCPROFILE Icc) // Save an ASCII Tag static -BOOL SaveText(const char *Text, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveText(const char *Text, LPLCMSICCPROFILE Icc) { size_t len = strlen(Text) + 1; @@ -2915,7 +2968,7 @@ BOOL SaveText(const char *Text, LPLCMSICCPROFILE Icc) // Save one of these new chromaticity values static -BOOL SaveOneChromaticity(double x, double y, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveOneChromaticity(double x, double y, LPLCMSICCPROFILE Icc) { Fixed32 xf, yf; @@ -2932,7 +2985,7 @@ BOOL SaveOneChromaticity(double x, double y, LPLCMSICCPROFILE Icc) // New tag added in Addendum II of old spec. static -BOOL SaveChromaticities(LPcmsCIExyYTRIPLE chrm, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveChromaticities(LPcmsCIExyYTRIPLE chrm, LPLCMSICCPROFILE Icc) { WORD nChans, Table; @@ -2952,7 +3005,7 @@ BOOL SaveChromaticities(LPcmsCIExyYTRIPLE chrm, LPLCMSICCPROFILE Icc) static -BOOL SaveSequenceDescriptionTag(LPcmsSEQ seq, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveSequenceDescriptionTag(LPcmsSEQ seq, LPLCMSICCPROFILE Icc) { icUInt32Number nSeqs; icDescStruct DescStruct; @@ -2989,7 +3042,7 @@ BOOL SaveSequenceDescriptionTag(LPcmsSEQ seq, LPLCMSICCPROFILE Icc) // Saves a timestamp tag static -BOOL SaveDateTimeNumber(const struct tm *DateTime, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveDateTimeNumber(const struct tm *DateTime, LPLCMSICCPROFILE Icc) { icDateTimeNumber Dest; @@ -3003,14 +3056,14 @@ BOOL SaveDateTimeNumber(const struct tm *DateTime, LPLCMSICCPROFILE Icc) // Saves a named color list into a named color profile static -BOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) { icUInt32Number vendorFlag; // Bottom 16 bits for IC use icUInt32Number count; // Count of named colors icUInt32Number nDeviceCoords; // Num of device coordinates - icInt8Number prefix[32]; // Prefix for each color name - icInt8Number suffix[32]; // Suffix for each color name + char prefix[32]; // Prefix for each color name + char suffix[32]; // Suffix for each color name int i; if (!SetupBase(icSigNamedColor2Type, Icc)) return FALSE; @@ -3019,8 +3072,10 @@ BOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc count = TransportValue32(NamedColorList ->nColors); nDeviceCoords = TransportValue32(NamedColorList ->ColorantCount); - strncpy(prefix, (const char*) NamedColorList->Prefix, 32); - strncpy(suffix, (const char*) NamedColorList->Suffix, 32); + strncpy(prefix, (const char*) NamedColorList->Prefix, 31); + strncpy(suffix, (const char*) NamedColorList->Suffix, 31); + + suffix[31] = prefix[31] = 0; if (!Icc ->Write(Icc, sizeof(icUInt32Number), &vendorFlag)) return FALSE; if (!Icc ->Write(Icc, sizeof(icUInt32Number), &count)) return FALSE; @@ -3030,15 +3085,17 @@ BOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc for (i=0; i < NamedColorList ->nColors; i++) { - icUInt16Number PCS[3]; - icUInt16Number Colorant[MAXCHANNELS]; - icInt8Number root[32]; + icUInt16Number PCS[3]; + icUInt16Number Colorant[MAXCHANNELS]; + char root[32]; LPcmsNAMEDCOLOR Color; int j; Color = NamedColorList ->List + i; - strncpy((char*) root, Color ->Name, 32); + strncpy(root, Color ->Name, 32); + Color ->Name[32] = 0; + if (!Icc ->Write(Icc, 32 , root)) return FALSE; for (j=0; j < 3; j++) @@ -3062,7 +3119,7 @@ BOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc // Saves a colorant table. It is using the named color structure for simplicity sake static -BOOL SaveColorantTable(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveColorantTable(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) { icUInt32Number count; // Count of named colors int i; @@ -3076,13 +3133,15 @@ BOOL SaveColorantTable(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) for (i=0; i < NamedColorList ->nColors; i++) { icUInt16Number PCS[3]; - icInt8Number root[32]; + icInt8Number root[33]; LPcmsNAMEDCOLOR Color; int j; Color = NamedColorList ->List + i; strncpy((char*) root, Color ->Name, 32); + root[32] = 0; + if (!Icc ->Write(Icc, 32 , root)) return FALSE; for (j=0; j < 3; j++) @@ -3099,7 +3158,7 @@ BOOL SaveColorantTable(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) // Does serialization of LUT16 and writes it. static -BOOL SaveLUT(const LUT* NewLUT, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveLUT(const LUT* NewLUT, LPLCMSICCPROFILE Icc) { icLut16 LUT16; unsigned int i; @@ -3189,7 +3248,7 @@ BOOL SaveLUT(const LUT* NewLUT, LPLCMSICCPROFILE Icc) // Does serialization of LUT8 and writes it static -BOOL SaveLUT8(const LUT* NewLUT, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveLUT8(const LUT* NewLUT, LPLCMSICCPROFILE Icc) { icLut8 LUT8; unsigned int i, j; @@ -3323,7 +3382,7 @@ void LCMSEXPORT _cmsSetLUTdepth(cmsHPROFILE hProfile, int depth) // Saves Tag directory static -BOOL SaveTagDirectory(LPLCMSICCPROFILE Icc) +LCMSBOOL SaveTagDirectory(LPLCMSICCPROFILE Icc) { icInt32Number i; icTag Tag; @@ -3356,7 +3415,7 @@ BOOL SaveTagDirectory(LPLCMSICCPROFILE Icc) // Dump tag contents static -BOOL SaveTags(LPLCMSICCPROFILE Icc) +LCMSBOOL SaveTags(LPLCMSICCPROFILE Icc, LPLCMSICCPROFILE FileOrig) { LPBYTE Data; @@ -3384,8 +3443,31 @@ BOOL SaveTags(LPLCMSICCPROFILE Icc) Icc -> TagOffsets[i] = Begin = Icc ->UsedSpace; Data = (LPBYTE) Icc -> TagPtrs[i]; - if (!Data) + if (!Data) { + + // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user. + // In this case a blind copy of the block data is performed + + if (Icc -> TagOffsets[i]) { + + size_t TagSize = FileOrig -> TagSizes[i]; + size_t TagOffset = FileOrig -> TagOffsets[i]; + void* Mem; + + if (FileOrig ->Seek(FileOrig, TagOffset)) return FALSE; + + Mem = _cmsMalloc(TagSize); + + if (FileOrig ->Read(Mem, TagSize, 1, FileOrig) != 1) return FALSE; + if (!Icc ->Write(Icc, TagSize, Mem)) return FALSE; + + Icc -> TagSizes[i] = (Icc ->UsedSpace - Begin); + free(Mem); + } + continue; + } + switch (Icc -> TagNames[i]) { @@ -3464,6 +3546,10 @@ BOOL SaveTags(LPLCMSICCPROFILE Icc) break; + case icSigChromaticAdaptationTag: + if (!SaveXYZArray(3, (LPcmsCIEXYZ) Data, Icc)) return FALSE; + break; + default: return FALSE; } @@ -3480,9 +3566,9 @@ BOOL SaveTags(LPLCMSICCPROFILE Icc) // Add tags to profile structure -BOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* Tag) +LCMSBOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* Tag) { - BOOL rc; + LCMSBOOL rc; switch (sig) { @@ -3543,6 +3629,11 @@ BOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* rc = _cmsAddColorantTableTag(hProfile, sig, (LPcmsNAMEDCOLORLIST) Tag); break; + + case icSigChromaticAdaptationTag: + rc = _cmsAddChromaticAdaptationTag(hProfile, sig, (const cmsCIEXYZ*) Tag); + break; + default: cmsSignalError(LCMS_ERRC_ABORTED, "cmsAddTag: Tag '%x' is unsupported", sig); return FALSE; @@ -3568,11 +3659,11 @@ BOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* // Low-level save to disk. It closes the profile on exit -BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) +LCMSBOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; LCMSICCPROFILE Keep; - BOOL rc; + LCMSBOOL rc; CopyMemory(&Keep, Icc, sizeof(LCMSICCPROFILE)); _cmsSetSaveToDisk(Icc, NULL); @@ -3581,7 +3672,7 @@ BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) if (!SaveHeader(Icc)) return FALSE; if (!SaveTagDirectory(Icc)) return FALSE; - if (!SaveTags(Icc)) return FALSE; + if (!SaveTags(Icc, &Keep)) return FALSE; _cmsSetSaveToDisk(Icc, FileName); @@ -3591,7 +3682,7 @@ BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) if (!SaveHeader(Icc)) goto CleanUp; if (!SaveTagDirectory(Icc)) goto CleanUp; - if (!SaveTags(Icc)) goto CleanUp; + if (!SaveTags(Icc, &Keep)) goto CleanUp; rc = (Icc ->Close(Icc) == 0); CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); @@ -3608,7 +3699,7 @@ BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) // Low-level save from open stream -BOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, +LCMSBOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, size_t* BytesNeeded) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -3623,20 +3714,20 @@ BOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, if (!SaveHeader(Icc)) return FALSE; if (!SaveTagDirectory(Icc)) return FALSE; - if (!SaveTags(Icc)) return FALSE; + if (!SaveTags(Icc, &Keep)) return FALSE; if (!MemPtr) { // update BytesSaved so caller knows how many bytes are needed for MemPtr *BytesNeeded = Icc ->UsedSpace; - CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); + CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); return TRUE; } if (*BytesNeeded < Icc ->UsedSpace) { // need at least UsedSpace in MemPtr to continue - CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); + CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); return FALSE; } @@ -3646,7 +3737,7 @@ BOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, // Pass #2 does save to file into supplied stream if (!SaveHeader(Icc)) goto CleanUp; if (!SaveTagDirectory(Icc)) goto CleanUp; - if (!SaveTags(Icc)) goto CleanUp; + if (!SaveTags(Icc, &Keep)) goto CleanUp; // update BytesSaved so caller knows how many bytes put into stream *BytesNeeded = Icc ->UsedSpace; @@ -3661,3 +3752,4 @@ CleanUp: CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); return FALSE; } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c index 43032109121..1a222febf86 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -118,7 +118,7 @@ LPLUT LCMSEXPORT cmsAllocLUT(void) { LPLUT NewLUT; - NewLUT = (LPLUT) malloc(sizeof(LUT)); + NewLUT = (LPLUT) _cmsMalloc(sizeof(LUT)); if (NewLUT) ZeroMemory(NewLUT, sizeof(LUT)); @@ -171,9 +171,10 @@ void LCMSEXPORT cmsFreeLUT(LPLUT Lut) static LPVOID DupBlockTab(LPVOID Org, size_t size) { - LPVOID mem = malloc(size); + LPVOID mem = _cmsMalloc(size); + if (mem != NULL) + CopyMemory(mem, Org, size); - CopyMemory(mem, Org, size); return mem; } @@ -211,6 +212,37 @@ unsigned int UIpow(unsigned int a, unsigned int b) } +LCMSBOOL _cmsValidateLUT(LPLUT NewLUT) +{ + unsigned int calc = 1; + unsigned int oldCalc; + unsigned int power = NewLUT -> InputChan; + + if (NewLUT -> cLutPoints > 100) return FALSE; + if (NewLUT -> InputChan > MAXCHANNELS) return FALSE; + if (NewLUT -> OutputChan > MAXCHANNELS) return FALSE; + + if (NewLUT -> cLutPoints == 0) return TRUE; + + for (; power > 0; power--) { + + oldCalc = calc; + calc *= NewLUT -> cLutPoints; + + if (calc / NewLUT -> cLutPoints != oldCalc) { + return FALSE; + } + } + + oldCalc = calc; + calc *= NewLUT -> OutputChan; + if (NewLUT -> OutputChan && calc / NewLUT -> OutputChan != oldCalc) { + return FALSE; + } + + return TRUE; +} + LPLUT LCMSEXPORT cmsAlloc3DGrid(LPLUT NewLUT, int clutPoints, int inputChan, int outputChan) { DWORD nTabSize; @@ -220,12 +252,17 @@ LPLUT LCMSEXPORT cmsAlloc3DGrid(LPLUT NewLUT, int clutPoints, int inputChan, int NewLUT -> InputChan = inputChan; NewLUT -> OutputChan = outputChan; + if (!_cmsValidateLUT(NewLUT)) { + return NULL; + } - nTabSize = (NewLUT -> OutputChan * UIpow(NewLUT->cLutPoints, - NewLUT->InputChan) - * sizeof(WORD)); + nTabSize = NewLUT -> OutputChan * UIpow(NewLUT->cLutPoints, + NewLUT->InputChan); + + NewLUT -> T = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize); + nTabSize *= sizeof(WORD); + if (NewLUT -> T == NULL) return NULL; - NewLUT -> T = (LPWORD) malloc(nTabSize); ZeroMemory(NewLUT -> T, nTabSize); NewLUT ->Tsize = nTabSize; @@ -254,10 +291,12 @@ LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nT for (i=0; i < NewLUT -> InputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> InputEntries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> InputEntries); + if (PtrW == NULL) return NULL; + NewLUT -> L1[i] = PtrW; CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> InputEntries); - CopyMemory(&NewLUT -> LCurvesSeed[0][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); + CopyMemory(&NewLUT -> LCurvesSeed[0][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); } @@ -268,10 +307,12 @@ LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nT NewLUT -> OutputEntries = Tables[0] -> nEntries; for (i=0; i < NewLUT -> OutputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> OutputEntries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> OutputEntries); + if (PtrW == NULL) return NULL; + NewLUT -> L2[i] = PtrW; CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> OutputEntries); - CopyMemory(&NewLUT -> LCurvesSeed[1][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); + CopyMemory(&NewLUT -> LCurvesSeed[1][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); } break; @@ -285,10 +326,12 @@ LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nT for (i=0; i < NewLUT -> InputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> L3Entries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> L3Entries); + if (PtrW == NULL) return NULL; + NewLUT -> L3[i] = PtrW; CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> L3Entries); - CopyMemory(&NewLUT -> LCurvesSeed[2][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); + CopyMemory(&NewLUT -> LCurvesSeed[2][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); } break; @@ -298,10 +341,12 @@ LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nT NewLUT -> L4Entries = Tables[0] -> nEntries; for (i=0; i < NewLUT -> OutputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> L4Entries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> L4Entries); + if (PtrW == NULL) return NULL; + NewLUT -> L4[i] = PtrW; CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> L4Entries); - CopyMemory(&NewLUT -> LCurvesSeed[3][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); + CopyMemory(&NewLUT -> LCurvesSeed[3][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); } break; @@ -580,7 +625,7 @@ LPLUT _cmsBlessLUT8(LPLUT Lut) LPL16PARAMS p = &Lut ->CLut16params; - p8 = (LPL8PARAMS) malloc(sizeof(L8PARAMS)); + p8 = (LPL8PARAMS) _cmsMalloc(sizeof(L8PARAMS)); if (p8 == NULL) return NULL; // values comes * 257, so we can safely take first byte (x << 8 + x) @@ -593,8 +638,8 @@ LPLUT _cmsBlessLUT8(LPLUT Lut) if (Lut ->wFlags & LUT_HASTL1) { for (j=0; j < 3; j++) - StageABC[i] = cmsLinearInterpLUT16(StageABC[i], - Lut -> L1[i], + StageABC[j] = cmsLinearInterpLUT16(StageABC[j], + Lut -> L1[j], &Lut -> In16params); Lut ->wFlags &= ~LUT_HASTL1; } @@ -697,7 +742,7 @@ void EvalLUTdoubleKLab(LPLUT Lut, const VEC3* In, WORD FixedK, LPcmsCIELab Out) wIn[3] = FixedK; cmsEvalLUT(Lut, wIn, wOut); - cmsLabEncoded2Float(Out, wOut); + cmsLabEncoded2Float(Out, wOut); } // Builds a Jacobian CMY->Lab @@ -722,9 +767,9 @@ void ComputeJacobianLab(LPLUT Lut, LPMAT3 Jacobian, const VEC3* Colorant, WORD K EvalLUTdoubleKLab(Lut, &ColorantD, K, &LabD); - Jacobian->v[0].n[j] = ((LabD.L - Lab.L) / JACOBIAN_EPSILON); - Jacobian->v[1].n[j] = ((LabD.a - Lab.a) / JACOBIAN_EPSILON); - Jacobian->v[2].n[j] = ((LabD.b - Lab.b) / JACOBIAN_EPSILON); + Jacobian->v[0].n[j] = ((LabD.L - Lab.L) / JACOBIAN_EPSILON); + Jacobian->v[1].n[j] = ((LabD.a - Lab.a) / JACOBIAN_EPSILON); + Jacobian->v[2].n[j] = ((LabD.b - Lab.b) / JACOBIAN_EPSILON); } } @@ -797,18 +842,18 @@ LCMSAPI double LCMSEXPORT cmsEvalLUTreverse(LPLUT Lut, WORD Target[], WORD Resul // Obtain slope ComputeJacobianLab(Lut, &Jacobian, &x, FixedK); - // Solve system - tmp2.n[0] = fx.L - Goal.L; - tmp2.n[1] = fx.a - Goal.a; - tmp2.n[2] = fx.b - Goal.b; + // Solve system + tmp2.n[0] = fx.L - Goal.L; + tmp2.n[1] = fx.a - Goal.a; + tmp2.n[2] = fx.b - Goal.b; - if (!MAT3solve(&tmp, &Jacobian, &tmp2)) - break; + if (!MAT3solve(&tmp, &Jacobian, &tmp2)) + break; // Move our guess - x.n[0] -= tmp.n[0]; - x.n[1] -= tmp.n[1]; - x.n[2] -= tmp.n[2]; + x.n[0] -= tmp.n[0]; + x.n[1] -= tmp.n[1]; + x.n[2] -= tmp.n[2]; // Some clipping.... VEC3saturate(&x); @@ -822,3 +867,6 @@ LCMSAPI double LCMSEXPORT cmsEvalLUTreverse(LPLUT Lut, WORD Target[], WORD Resul return LastError; } + + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c index c70829989b2..9a6576bce23 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -62,6 +62,7 @@ // data yet in fixed point, so no additional process is required. // Then, we obtain data on 15.16, so we need to shift >> by 1 to // obtain 1.15 PCS format. + // On OUTPUT profiles, things are inverse, we must first expand 1 bit // by shifting left, and then convert result between 0 and 1.000 to // RGB, so FromFixedDomain() must be called before pass values to @@ -71,6 +72,7 @@ // input is encoded from 0 to 0xffff, we must first use the shaper and // then the matrix, an additional FromFixedDomain() must be used to // accomodate output values. + // For a sake of simplicity, I will handle this three behaviours // with different routines, so the flags MATSHAPER_INPUT and MATSHAPER_OUTPUT // can be conbined to signal smelted matrix-shapers @@ -89,7 +91,7 @@ int ComputeTables(LPGAMMATABLE Table[3], LPWORD Out[3], LPL16PARAMS p16) { LPWORD PtrW; - PtrW = (LPWORD) malloc(sizeof(WORD) * p16 -> nSamples); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * p16 -> nSamples); if (PtrW == NULL) return -1; // Signal error @@ -119,7 +121,7 @@ LPMATSHAPER cmsAllocMatShaper2(LPMAT3 Matrix, LPGAMMATABLE In[], LPGAMMATABLE Ou LPMATSHAPER NewMatShaper; int rc; - NewMatShaper = (LPMATSHAPER) malloc(sizeof(MATSHAPER)); + NewMatShaper = (LPMATSHAPER) _cmsMalloc(sizeof(MATSHAPER)); if (NewMatShaper) ZeroMemory(NewMatShaper, sizeof(MATSHAPER)); @@ -171,7 +173,13 @@ LPMATSHAPER cmsAllocMatShaper(LPMAT3 Matrix, LPGAMMATABLE Tables[], DWORD Behavi LPMATSHAPER NewMatShaper; int i, AllLinear; - NewMatShaper = (LPMATSHAPER) malloc(sizeof(MATSHAPER)); + if (Matrix == NULL) return NULL; + for (i=0; i < 3; i++) { + + if (Tables[i] == NULL) return NULL; + } + + NewMatShaper = (LPMATSHAPER) _cmsMalloc(sizeof(MATSHAPER)); if (NewMatShaper) ZeroMemory(NewMatShaper, sizeof(MATSHAPER)); @@ -187,17 +195,16 @@ LPMATSHAPER cmsAllocMatShaper(LPMAT3 Matrix, LPGAMMATABLE Tables[], DWORD Behavi NewMatShaper -> dwFlags |= MATSHAPER_HASMATRIX; // Now, on the table characteristics - cmsCalcL16Params(Tables[0] -> nEntries, &NewMatShaper -> p16); // Copy tables AllLinear = 0; - for (i=0; i < 3; i++) - { + for (i=0; i < 3; i++) { + LPWORD PtrW; - PtrW = (LPWORD) malloc(sizeof(WORD) * NewMatShaper -> p16.nSamples); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewMatShaper -> p16.nSamples); if (PtrW == NULL) { cmsFreeMatShaper(NewMatShaper); @@ -235,11 +242,11 @@ void cmsFreeMatShaper(LPMATSHAPER MatShaper) for (i=0; i < 3; i++) { - if (MatShaper -> L[i]) free(MatShaper ->L[i]); - if (MatShaper -> L2[i]) free(MatShaper ->L2[i]); + if (MatShaper -> L[i]) _cmsFree(MatShaper ->L[i]); + if (MatShaper -> L2[i]) _cmsFree(MatShaper ->L2[i]); } - free(MatShaper); + _cmsFree(MatShaper); } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c index b404fdc6924..f6bc3cb5a59 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -71,16 +71,16 @@ double cdecl VEC3length(LPVEC3 a); double cdecl VEC3distance(LPVEC3 a, LPVEC3 b); -void cdecl MAT3identity(LPMAT3 a); -void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b); -int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b); -BOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b); -double cdecl MAT3det(LPMAT3 m); -void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v); -void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v); -void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v); -void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d); -void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d); +void cdecl MAT3identity(LPMAT3 a); +void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b); +int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b); +LCMSBOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b); +double cdecl MAT3det(LPMAT3 m); +void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v); +void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v); +void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v); +void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d); +void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d); // --------------------- Implementation ---------------------------- @@ -345,13 +345,13 @@ void VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b) // Check id two vectors are the same, allowing tolerance static -BOOL RangeCheck(double l, double h, double v) +LCMSBOOL RangeCheck(double l, double h, double v) { return (v >= l && v <= h); } -BOOL VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance) +LCMSBOOL VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance) { int i; double c; @@ -367,7 +367,7 @@ BOOL VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance) return TRUE; } -BOOL VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance) +LCMSBOOL VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance) { int i; double c; @@ -462,7 +462,7 @@ void MAT3identity(LPMAT3 a) // Check if matrix is Identity. Allow a tolerance as % -BOOL MAT3isIdentity(LPWMAT3 a, double Tolerance) +LCMSBOOL MAT3isIdentity(LPWMAT3 a, double Tolerance) { int i; MAT3 Idd; @@ -545,16 +545,16 @@ int MAT3inverse(LPMAT3 a, LPMAT3 b) // Solve a system in the form Ax = b -BOOL MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b) +LCMSBOOL MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b) { - MAT3 m, a_1; + MAT3 m, a_1; - CopyMemory(&m, a, sizeof(MAT3)); + CopyMemory(&m, a, sizeof(MAT3)); - if (!MAT3inverse(&m, &a_1)) return FALSE; // Singular matrix + if (!MAT3inverse(&m, &a_1)) return FALSE; // Singular matrix - MAT3eval(x, &a_1, b); - return TRUE; + MAT3eval(x, &a_1, b); + return TRUE; } @@ -839,3 +839,7 @@ void MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d) VEC3scaleAndCut(&r -> v[1], &v -> v[1], d); VEC3scaleAndCut(&r -> v[2], &v -> v[2], d); } + + + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c index c943badcb3b..c47d002f7cf 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -74,7 +74,7 @@ LPcmsNAMEDCOLORLIST GrowNamedColorList(LPcmsNAMEDCOLORLIST v, int ByElements) NewElements *= 2; size = sizeof(cmsNAMEDCOLORLIST) + (sizeof(cmsNAMEDCOLOR) * NewElements); - TheNewList = (LPcmsNAMEDCOLORLIST) malloc(size); + TheNewList = (LPcmsNAMEDCOLORLIST) _cmsMalloc(size); if (TheNewList == NULL) { @@ -86,7 +86,7 @@ LPcmsNAMEDCOLORLIST GrowNamedColorList(LPcmsNAMEDCOLORLIST v, int ByElements) CopyMemory(TheNewList, v, sizeof(cmsNAMEDCOLORLIST) + (v ->nColors - 1) * sizeof(cmsNAMEDCOLOR)); TheNewList -> Allocated = NewElements; - free(v); + _cmsFree(v); return TheNewList; } } @@ -99,7 +99,7 @@ LPcmsNAMEDCOLORLIST cmsAllocNamedColorList(int n) { size_t size = sizeof(cmsNAMEDCOLORLIST) + (n - 1) * sizeof(cmsNAMEDCOLOR); - LPcmsNAMEDCOLORLIST v = (LPcmsNAMEDCOLORLIST) malloc(size); + LPcmsNAMEDCOLORLIST v = (LPcmsNAMEDCOLORLIST) _cmsMalloc(size); if (v == NULL) { @@ -124,10 +124,10 @@ void cmsFreeNamedColorList(LPcmsNAMEDCOLORLIST v) return; } - free(v); + _cmsFree(v); } -BOOL cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]) +LCMSBOOL cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]) { _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform; LPcmsNAMEDCOLORLIST List; @@ -146,6 +146,7 @@ BOOL cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WOR List ->List[List ->nColors].PCS[i] = PCS[i]; strncpy(List ->List[List ->nColors].Name, Name, MAX_PATH-1); + List ->List[List ->nColors].Name[MAX_PATH-1] = 0; List ->nColors++; return TRUE; @@ -164,18 +165,17 @@ int LCMSEXPORT cmsNamedColorCount(cmsHTRANSFORM xform) } -BOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix) +LCMSBOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix) { _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform; - if (v ->NamedColorList == NULL) return FALSE; if (nColor < 0 || nColor >= cmsNamedColorCount(xform)) return FALSE; - if (Name) strncpy(Name, v ->NamedColorList->List[nColor].Name, 31); - if (Prefix) strncpy(Prefix, v ->NamedColorList->Prefix, 31); - if (Suffix) strncpy(Suffix, v ->NamedColorList->Suffix, 31); + if (Name) { strncpy(Name, v ->NamedColorList->List[nColor].Name, 31); Name[31] = 0; } + if (Prefix) { strncpy(Prefix, v ->NamedColorList->Prefix, 31); Prefix[31] = 0; } + if (Suffix) { strncpy(Suffix, v ->NamedColorList->Suffix, 31); Suffix[31] = 0; } return TRUE; } @@ -196,3 +196,5 @@ int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name) return -1; } + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c index ca76c07844a..6c5ef725635 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c @@ -28,7 +28,7 @@ // file: // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -639,9 +639,81 @@ LPBYTE UnrollDouble(register _LPcmsTRANSFORM info, register WORD wIn[], register +static +LPBYTE UnrollDouble1Chan(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum) +{ + double* Inks = (double*) accum; + double v; + + + v = floor(Inks[0] * 65535.0 + 0.5); + + if (v > 65535.0) v = 65535.0; + if (v < 0) v = 0; + + + wIn[0] = wIn[1] = wIn[2] = (WORD) v; + + return accum + sizeof(double); +} + + // ----------------------------------------------------------- Packing routines +// Generic N-bytes plus dither 16-to-8 conversion. Currently is just a quick hack + +static int err[MAXCHANNELS]; + +static +LPBYTE PackNBytesDither(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + register int i; + unsigned int n, pe, pf; + + for (i=0; i < nChan; i++) { + + n = wOut[i] + err[i]; // Value + + pe = (n / 257); // Whole part + pf = (n % 257); // Fractional part + + err[i] = pf; // Store it for next pixel + + *output++ = (BYTE) pe; + } + + return output + T_EXTRA(info ->OutputFormat); +} + + + +static +LPBYTE PackNBytesSwapDither(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + register int i; + unsigned int n, pe, pf; + + for (i=nChan-1; i >= 0; --i) { + + n = wOut[i] + err[i]; // Value + + pe = (n / 257); // Whole part + pf = (n % 257); // Fractional part + + err[i] = pf; // Store it for next pixel + + *output++ = (BYTE) pe; + } + + + return output + T_EXTRA(info ->OutputFormat); +} + + + // Generic chunky for byte static @@ -1486,7 +1558,10 @@ _cmsFIXFN _cmsIdentifyInputFormat(_LPcmsTRANSFORM xform, DWORD dwInput) case PT_HSV: case PT_HLS: case PT_Yxy: - FromInput = UnrollDouble; + if (T_CHANNELS(dwInput) == 1) + FromInput = UnrollDouble1Chan; + else + FromInput = UnrollDouble; break; // Inks (%) 0.0 .. 100.0 @@ -1749,6 +1824,9 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) switch (T_CHANNELS(dwOutput)) { case 1: + if (T_DITHER(dwOutput)) + ToOutput = PackNBytesDither; + else ToOutput = Pack1Byte; if (T_EXTRA(dwOutput) == 1) { if (T_SWAPFIRST(dwOutput)) @@ -1766,8 +1844,12 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) else if (T_COLORSPACE(dwOutput) == PT_Lab) ToOutput = Pack3BytesLab; + else { + if (T_DITHER(dwOutput)) + ToOutput = PackNBytesDither; else ToOutput = Pack3Bytes; + } break; case 1: // TODO: ALab8 should be handled here @@ -1793,12 +1875,22 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) case 4: if (T_EXTRA(dwOutput) == 0) { + if (T_DOSWAP(dwOutput)) { - if (T_SWAPFIRST(dwOutput)) + + if (T_SWAPFIRST(dwOutput)) { ToOutput = Pack4BytesSwapSwapFirst; - else + } + else { + + if (T_DITHER(dwOutput)) { + ToOutput = PackNBytesSwapDither; + } + else { ToOutput = Pack4BytesSwap; + } + } } else { if (T_SWAPFIRST(dwOutput)) @@ -1807,11 +1899,15 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) if (T_FLAVOR(dwOutput)) ToOutput = Pack4BytesReverse; + else { + if (T_DITHER(dwOutput)) + ToOutput = PackNBytesDither; else ToOutput = Pack4Bytes; } } } + } else { if (!T_DOSWAP(dwOutput) && !T_SWAPFIRST(dwOutput)) ToOutput = PackNBytes; @@ -1833,7 +1929,7 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) } break; - case 2: + case 2: case 5: case 7: case 8: @@ -1849,8 +1945,13 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) { if (T_DOSWAP(dwOutput)) ToOutput = PackNBytesSwap; + else { + + if (T_DITHER(dwOutput)) + ToOutput = PackNBytesDither; else ToOutput = PackNBytes; + } } break; @@ -1984,7 +2085,7 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) break; - case 2: + case 2: case 5: case 7: case 8: diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c index 4ad975550c3..e9b3d2ed545 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -624,3 +624,7 @@ void LCMSEXPORT cmsXYZEncoded2Float(LPcmsCIEXYZ fXYZ, const WORD XYZ[3]) fXYZ -> Z = XYZ2float(XYZ[2]); } + + + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c index f3bf7ec6fe8..22a67c0772d 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -144,6 +144,8 @@ LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, int Intent, /Table [ p p p [<...>]] /RangeABC [ 0 1 0 1 0 1] /DecodeABC[ <postlinearization> ] + /RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ] + % -128/500 1+127/500 0 1 -127/200 1+128/200 /MatrixABC [ 1 1 1 1 0 0 0 0 -1] /WhitePoint [D50] /BlackPoint [BP] @@ -347,7 +349,8 @@ typedef struct { static LPMEMSTREAM CreateMemStream(LPBYTE Buffer, DWORD dwMax, int MaxCols) { - LPMEMSTREAM m = (LPMEMSTREAM) malloc(sizeof(MEMSTREAM)); + LPMEMSTREAM m = (LPMEMSTREAM) _cmsMalloc(sizeof(MEMSTREAM)); + if (m == NULL) return NULL; ZeroMemory(m, sizeof(MEMSTREAM)); @@ -376,9 +379,9 @@ BYTE Word2Byte(WORD w) static BYTE L2Byte(WORD w) { - int ww = w + 0x0080; + int ww = w + 0x0080; - if (ww > 0xFFFF) return 0xFF; + if (ww > 0xFFFF) return 0xFF; return (BYTE) ((WORD) (ww >> 8) & 0xFF); } @@ -387,7 +390,6 @@ BYTE L2Byte(WORD w) static void WriteRawByte(LPMEMSTREAM m, BYTE b) { - if (m -> dwUsed + 1 > m -> dwMax) { m -> HasError = 1; } @@ -422,7 +424,7 @@ void WriteByte(LPMEMSTREAM m, BYTE b) } -// Does write a formatted string +// Does write a formatted string. Guaranteed to be 2048 bytes at most. static void Writef(LPMEMSTREAM m, const char *frm, ...) { @@ -432,7 +434,7 @@ void Writef(LPMEMSTREAM m, const char *frm, ...) va_start(args, frm); - vsprintf((char*) Buffer, frm, args); + vsnprintf((char*) Buffer, 2048, frm, args); for (pt = Buffer; *pt; pt++) { @@ -562,7 +564,7 @@ void EmitLab2XYZ(LPMEMSTREAM m) Writef(m, "{255 mul 128 sub 200 div } bind\n"); Writef(m, "]\n"); Writef(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n"); - Writef(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); + Writef(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n"); Writef(m, "/DecodeLMN [\n"); Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n"); Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n"); @@ -584,7 +586,11 @@ void Emit1Gamma(LPMEMSTREAM m, LPWORD Table, int nEntries) if (nEntries <= 0) return; // Empty table // Suppress whole if identity - if (cmsIsLinear(Table, nEntries)) return; + if (cmsIsLinear(Table, nEntries)) { + Writef(m, "{} "); + return; + } + // Check if is really an exponential. If so, emit "exp" gamma = cmsEstimateGammaEx(Table, nEntries, 0.001); @@ -646,7 +652,7 @@ void Emit1Gamma(LPMEMSTREAM m, LPWORD Table, int nEntries) // Compare gamma table static -BOOL GammaTableEquals(LPWORD g1, LPWORD g2, int nEntries) +LCMSBOOL GammaTableEquals(LPWORD g1, LPWORD g2, int nEntries) { return memcmp(g1, g2, nEntries* sizeof(WORD)) == 0; } @@ -676,7 +682,7 @@ void EmitNGamma(LPMEMSTREAM m, int n, LPWORD g[], int nEntries) // Check whatever a profile has CLUT tables (only on input) static -BOOL IsLUTbased(cmsHPROFILE hProfile, int Intent) +LCMSBOOL IsLUTbased(cmsHPROFILE hProfile, int Intent) { icTagSignature Tag; @@ -718,10 +724,10 @@ int OutputValueSampler(register WORD In[], register WORD Out[], register LPVOID if (sc -> FixWhite) { - if (In[0] == 0xFFFF) { // Only in L* = 100 + if (In[0] == 0xFFFF) { // Only in L* = 100, ab = [-8..8] - if ((In[1] >= 0x8000 && In[1] <= 0x87FF) || - (In[2] >= 0x8000 && In[2] <= 0x87FF)) { + if ((In[1] >= 0x7800 && In[1] <= 0x8800) && + (In[2] >= 0x7800 && In[2] <= 0x8800)) { WORD* Black; WORD* White; @@ -829,8 +835,8 @@ void WriteCLUT(LPMEMSTREAM m, LPLUT Lut, int bps, const char* PreMaj, sc.PreMaj = PreMaj; sc.PostMaj= PostMaj; - sc.PreMin = PreMin; - sc.PostMin= PostMin; + sc.PreMin = PreMin; + sc.PostMin = PostMin; sc.lIsInput = lIsInput; sc.FixWhite = FixWhite; sc.ColorSpace = ColorSpace; @@ -1231,7 +1237,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, if (!WriteNamedColorCSA(mem, hProfile, Intent)) { - free((void*) mem); + _cmsFree((void*) mem); return 0; } } @@ -1246,7 +1252,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, ColorSpace != icSigLabData) { cmsSignalError(LCMS_ERRC_ABORTED, "Invalid output color space"); - free((void*) mem); + _cmsFree((void*) mem); return 0; } @@ -1256,7 +1262,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, // Yes, so handle as LUT-based if (!WriteInputLUT(mem, hProfile, Intent)) { - free((void*) mem); + _cmsFree((void*) mem); return 0; } } @@ -1266,7 +1272,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, if (!WriteInputMatrixShaper(mem, hProfile)) { - free((void*) mem); // Something went wrong + _cmsFree((void*) mem); // Something went wrong return 0; } } @@ -1277,7 +1283,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, dwBytesUsed = mem ->dwUsed; // Get rid of memory stream - free((void*) mem); + _cmsFree((void*) mem); // Finally, return used byte count return dwBytesUsed; @@ -1350,27 +1356,40 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, static -void EmitPQRStage(LPMEMSTREAM m, int DoBPC, int lIsAbsolute) +void EmitPQRStage(LPMEMSTREAM m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute) { + if (lIsAbsolute) { + + // For absolute colorimetric intent, encode back to relative + // and generate a relative LUT + + // Relative encoding is obtained across XYZpcs*(D50/WhitePoint) + + cmsCIEXYZ White; + + cmsTakeMediaWhitePoint(&White, hProfile); + + Writef(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n"); + Writef(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); + + Writef(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n" + "/TransformPQR [\n" + "{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n" + "{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n" + "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n", + White.X, White.Y, White.Z); + return; + } + + Writef(m,"%% Bradford Cone Space\n" "/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] \n"); Writef(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); - if (lIsAbsolute) { - - // For absolute colorimetric intent, do nothing - - Writef(m, "%% Absolute colorimetric -- no transformation\n" - "/TransformPQR [\n" - "{exch pop exch pop exch pop exch pop} bind dup dup]\n"); - return; - } - - // No BPC if (!DoBPC) { @@ -1414,6 +1433,7 @@ void EmitPQRStage(LPMEMSTREAM m, int DoBPC, int lIsAbsolute) static void EmitXYZ2Lab(LPMEMSTREAM m) { + Writef(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n"); Writef(m, "/EncodeLMN [\n"); Writef(m, "{ 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); Writef(m, "{ 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); @@ -1423,18 +1443,11 @@ void EmitXYZ2Lab(LPMEMSTREAM m) Writef(m, "/EncodeABC [\n"); - Writef(m, "{ 116 mul 16 sub 100 div } bind\n"); - Writef(m, "{ 500 mul 128 add 255 div } bind\n"); - Writef(m, "{ 200 mul 128 add 255 div } bind\n"); + Writef(m, "{ 500 mul 128 add 256 div } bind\n"); + Writef(m, "{ 200 mul 128 add 256 div } bind\n"); - /* - Writef(m, "{ 116 mul 16 sub 256 mul 25700 div } bind\n"); - Writef(m, "{ 500 mul 128 add 256 mul 65535 div } bind\n"); - Writef(m, "{ 200 mul 128 add 256 mul 65535 div } bind\n"); - */ - Writef(m, "]\n"); @@ -1458,20 +1471,27 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag LPLUT DeviceLink; cmsHPROFILE Profiles[3]; cmsCIEXYZ BlackPointAdaptedToD50; - BOOL lFreeDeviceLink = FALSE; - BOOL lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); + LCMSBOOL lFreeDeviceLink = FALSE; + LCMSBOOL lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); + LCMSBOOL lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP); + int RelativeEncodingIntent; - // Trick our v4 profile as it were v2. This prevents the ajusting done - // in perceptual & saturation. We only neew v4 encoding! - hLab = cmsCreateLab4Profile(NULL); - cmsSetProfileICCversion(hLab, 0); + hLab = cmsCreateLabProfile(NULL); ColorSpace = cmsGetColorSpace(hProfile); nChannels = _cmsChannelsOf(ColorSpace); OutputFormat = CHANNELS_SH(nChannels) | BYTES_SH(2); + // For absolute colorimetric, the LUT is encoded as relative + // in order to preserve precission. + + RelativeEncodingIntent = Intent; + if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC) + RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC; + + // Is a devicelink profile? if (cmsGetDeviceClass(hProfile) == icSigLinkClass) { @@ -1479,13 +1499,14 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag if (ColorSpace == icSigLabData) { - // adjust input to Lab to out v4 + // adjust input to Lab to our v4 Profiles[0] = hLab; Profiles[1] = hProfile; xform = cmsCreateMultiprofileTransform(Profiles, 2, TYPE_Lab_DBL, - OutputFormat, Intent, cmsFLAGS_NOPRELINEARIZATION); + OutputFormat, RelativeEncodingIntent, + dwFlags|cmsFLAGS_NOWHITEONWHITEFIXUP|cmsFLAGS_NOPRELINEARIZATION); } else { @@ -1499,7 +1520,7 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag // This is a normal profile xform = cmsCreateTransform(hLab, TYPE_Lab_DBL, hProfile, - OutputFormat, Intent, cmsFLAGS_NOPRELINEARIZATION); + OutputFormat, RelativeEncodingIntent, dwFlags|cmsFLAGS_NOWHITEONWHITEFIXUP|cmsFLAGS_NOPRELINEARIZATION); } if (xform == NULL) { @@ -1515,7 +1536,7 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag if (!DeviceLink) { - DeviceLink = _cmsPrecalculateDeviceLink(xform, 0); + DeviceLink = _cmsPrecalculateDeviceLink(xform, cmsFLAGS_NOPRELINEARIZATION); lFreeDeviceLink = TRUE; } @@ -1527,7 +1548,7 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag // Emit headers, etc. EmitWhiteBlackD50(m, &BlackPointAdaptedToD50); - EmitPQRStage(m, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); + EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); EmitXYZ2Lab(m); if (DeviceLink ->wFlags & LUT_HASTL1) { @@ -1544,10 +1565,13 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag // zero. This would sacrifice a bit of highlights, but failure to do so would cause // scum dot. Ouch. + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) + lFixWhite = FALSE; + Writef(m, "/RenderTable "); WriteCLUT(m, DeviceLink, 8, "<", ">\n", "", "", FALSE, - (Intent != INTENT_ABSOLUTE_COLORIMETRIC), ColorSpace); + lFixWhite, ColorSpace); Writef(m, " %d {} bind ", nChannels); @@ -1582,6 +1606,9 @@ void BuildColorantList(char *Colorant, int nColorant, WORD Out[]) int j; Colorant[0] = 0; + if (nColorant > MAXCHANNELS) + nColorant = MAXCHANNELS; + for (j=0; j < nColorant; j++) { sprintf(Buff, "%.3f", Out[j] / 65535.0); @@ -1677,7 +1704,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) { - free((void*) mem); + _cmsFree((void*) mem); return 0; } } @@ -1687,7 +1714,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) { - free((void*) mem); + _cmsFree((void*) mem); return 0; } } @@ -1702,7 +1729,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, dwBytesUsed = mem ->dwUsed; // Get rid of memory stream - free((void*) mem); + _cmsFree((void*) mem); // Finally, return used byte count return dwBytesUsed; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c index 023a732dfeb..2b52b2daf88 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -120,7 +120,7 @@ int ComponentOf(int n, int clut, int nColorant) // This routine does a sweep on whole input space, and calls its callback // function on knots. returns TRUE if all ok, FALSE otherwise. -BOOL LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DWORD dwFlags) +LCMSBOOL LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DWORD dwFlags) { int i, t, nTotalPoints, Colorant, index; WORD In[MAXCHANNELS], Out[MAXCHANNELS]; @@ -145,12 +145,16 @@ BOOL LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DW &Lut -> In16params); } + for (t=0; t < (int) Lut -> OutputChan; t++) + Out[t] = Lut->T[index + t]; - // if (dwFlags & SAMPLER_INSPECT) { + if (dwFlags & SAMPLER_HASTL2) { for (t=0; t < (int) Lut -> OutputChan; t++) - Out[t] = Lut->T[index + t]; - // } + Out[t] = cmsLinearInterpLUT16(Out[t], + Lut -> L2[t], + &Lut -> Out16params); + } if (!Sampler(In, Out, Cargo)) @@ -255,9 +259,11 @@ LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags) LPLUT Grid; int nGridPoints; DWORD dwFormatIn, dwFormatOut; + DWORD SaveFormatIn, SaveFormatOut; int ChannelsIn, ChannelsOut; LPLUT SaveGamutLUT; + // Remove any gamut checking SaveGamutLUT = p ->Gamut; p ->Gamut = NULL; @@ -276,8 +282,13 @@ LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags) dwFormatIn = (CHANNELS_SH(ChannelsIn)|BYTES_SH(2)); dwFormatOut = (CHANNELS_SH(ChannelsOut)|BYTES_SH(2)); - p -> FromInput = _cmsIdentifyInputFormat(p, dwFormatIn); - p -> ToOutput = _cmsIdentifyOutputFormat(p, dwFormatOut); + SaveFormatIn = p ->InputFormat; + SaveFormatOut = p ->OutputFormat; + + p -> InputFormat = dwFormatIn; + p -> OutputFormat = dwFormatOut; + p -> FromInput = _cmsIdentifyInputFormat(p, dwFormatIn); + p -> ToOutput = _cmsIdentifyOutputFormat(p, dwFormatOut); // Fix gamut & gamma possible mismatches. @@ -289,7 +300,6 @@ LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags) _cmsComputePrelinearizationTablesFromXFORM(hOne, 1, Grid); } - // Attention to this typecast! we can take the luxury to // do this since cmsHTRANSFORM is only an alias to a pointer // to the transform struct. @@ -297,11 +307,13 @@ LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags) if (!cmsSample3DGrid(Grid, XFormSampler, (LPVOID) p, Grid -> wFlags)) { cmsFreeLUT(Grid); - return NULL; + Grid = NULL; } + p ->Gamut = SaveGamutLUT; + p ->InputFormat = SaveFormatIn; + p ->OutputFormat = SaveFormatOut; - p ->Gamut = SaveGamutLUT; return Grid; } @@ -348,7 +360,7 @@ int BlackPreservingGrayOnlySampler(register WORD In[], register WORD Out[], regi -// That is our K-preserving callback. +// Preserve all K plane. static int BlackPreservingSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) { @@ -469,6 +481,7 @@ int LCMSEXPORT cmsSetCMYKPreservationStrategy(int n) return OldVal; } +#pragma warning(disable: 4550) // Get a pointer to callback on depending of strategy static @@ -504,11 +517,10 @@ LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD if (p -> dwOriginalFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) LocalFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION; - // Fill in cargo struct Cargo.cmyk2cmyk = hCMYK2CMYK; - // Compute tone curve + // Compute tone curve. Cargo.KTone = _cmsBuildKToneCurve(hCMYK2CMYK, 256); if (Cargo.KTone == NULL) return NULL; cmsCalcL16Params(Cargo.KTone ->nEntries, &Cargo.KToneParams); @@ -522,11 +534,11 @@ LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD Cargo.LabK2cmyk = cmsReadICCLut(p->OutputProfile, Device2PCS[p->Intent]); // Is there any table available? - if (Cargo.LabK2cmyk == NULL) { + if (Cargo.LabK2cmyk == NULL) { - Grid = NULL; + Grid = NULL; goto Cleanup; - } + } // Setup a roundtrip on output profile for TAC estimation Cargo.hRoundTrip = cmsCreateTransform(p ->OutputProfile, TYPE_CMYK_16, @@ -654,7 +666,7 @@ void PatchLUT(LPLUT Grid, WORD At[], WORD Value[], -BOOL _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p) +LCMSBOOL _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p) { WORD *WhitePointIn, *WhitePointOut, *BlackPointIn, *BlackPointOut; @@ -682,3 +694,4 @@ BOOL _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p) return TRUE; } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c index cd128dab6a4..9c3afc451dd 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -320,7 +320,7 @@ cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD d cmsHPROFILE hICC; _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) hTransform; LPLUT Lut; - BOOL MustFreeLUT; + LCMSBOOL MustFreeLUT; LPcmsNAMEDCOLORLIST InputColorant = NULL; LPcmsNAMEDCOLORLIST OutputColorant = NULL; @@ -373,10 +373,8 @@ cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD d if (cmsGetDeviceClass(hICC) == icSigOutputClass) { - cmsAddTag(hICC, icSigBToA0Tag, (LPVOID) Lut); } - else cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); @@ -404,7 +402,7 @@ cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD d OutputColorant = cmsReadColorantTable(v ->OutputProfile, icSigColorantTableTag); } - } + } if (InputColorant) cmsAddTag(hICC, icSigColorantTableTag, InputColorant); @@ -446,6 +444,7 @@ cmsHPROFILE LCMSEXPORT cmsCreateLinearizationDeviceLink(icColorSpaceSignature Co // Creates a LUT with prelinearization step only Lut = cmsAllocLUT(); + if (Lut == NULL) return NULL; // Set up channels Lut ->InputChan = Lut ->OutputChan = _cmsChannelsOf(ColorSpace); @@ -548,6 +547,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateInkLimitingDeviceLink(icColorSpaceSignature Colo // Creates a LUT with 3D grid only Lut = cmsAllocLUT(); + if (Lut == NULL) { + cmsCloseProfile(hICC); + return NULL; + } cmsAlloc3DGrid(Lut, 17, _cmsChannelsOf(ColorSpace), @@ -584,8 +587,9 @@ static LPLUT Create3x3EmptyLUT(void) { LPLUT AToB0 = cmsAllocLUT(); - AToB0 -> InputChan = AToB0 -> OutputChan = 3; + if (AToB0 == NULL) return NULL; + AToB0 -> InputChan = AToB0 -> OutputChan = 3; return AToB0; } @@ -597,8 +601,8 @@ cmsHPROFILE LCMSEXPORT cmsCreateLabProfile(LPcmsCIExyY WhitePoint) cmsHPROFILE hProfile; LPLUT Lut; - hProfile = cmsCreateRGBProfile(WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; cmsSetDeviceClass(hProfile, icSigAbstractClass); cmsSetColorSpace(hProfile, icSigLabData); @@ -611,7 +615,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateLabProfile(LPcmsCIExyY WhitePoint) // An empty LUTs is all we need Lut = Create3x3EmptyLUT(); - if (Lut == NULL) return NULL; + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut); cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut); @@ -628,8 +635,8 @@ cmsHPROFILE LCMSEXPORT cmsCreateLab4Profile(LPcmsCIExyY WhitePoint) cmsHPROFILE hProfile; LPLUT Lut; - hProfile = cmsCreateRGBProfile(WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; cmsSetProfileICCversion(hProfile, 0x4000000); @@ -644,7 +651,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateLab4Profile(LPcmsCIExyY WhitePoint) // An empty LUTs is all we need Lut = Create3x3EmptyLUT(); - if (Lut == NULL) return NULL; + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } Lut -> wFlags |= LUT_V4_INPUT_EMULATE_V2; cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut); @@ -666,6 +676,7 @@ cmsHPROFILE LCMSEXPORT cmsCreateXYZProfile(void) LPLUT Lut; hProfile = cmsCreateRGBProfile(cmsD50_xyY(), NULL, NULL); + if (hProfile == NULL) return NULL; cmsSetDeviceClass(hProfile, icSigAbstractClass); cmsSetColorSpace(hProfile, icSigXYZData); @@ -677,15 +688,16 @@ cmsHPROFILE LCMSEXPORT cmsCreateXYZProfile(void) // An empty LUTs is all we need Lut = Create3x3EmptyLUT(); - if (Lut == NULL) return NULL; + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut); cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut); cmsAddTag(hProfile, icSigPreview0Tag, (LPVOID) Lut); cmsFreeLUT(Lut); - - return hProfile; } @@ -723,6 +735,7 @@ LPGAMMATABLE Build_sRGBGamma(void) return cmsBuildParametricGamma(1024, 4, Parameters); } +// Create the ICC virtual profile for sRGB space cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void) { cmsCIExyY D65; @@ -739,6 +752,7 @@ cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void) hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma22); cmsFreeGamma(Gamma22[0]); + if (hsRGB == NULL) return NULL; cmsAddTag(hsRGB, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); @@ -750,7 +764,6 @@ cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void) - typedef struct { double Brightness; double Contrast; @@ -793,7 +806,6 @@ int bchswSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) cmsFloat2LabEncoded(Out, &LabOut); - return TRUE; } @@ -839,7 +851,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, // Creates a LUT with 3D grid only Lut = cmsAllocLUT(); - + if (Lut == NULL) { + cmsCloseProfile(hICC); + return NULL; + } cmsAlloc3DGrid(Lut, nLUTPoints, 3, 3); @@ -890,7 +905,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateNULLProfile(void) // An empty LUTs is all we need Lut = cmsAllocLUT(); - if (Lut == NULL) return NULL; + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } Lut -> InputChan = 3; Lut -> OutputChan = 1; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c index 3f3beb76665..b7e38844de1 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -51,10 +51,6 @@ #include "lcms.h" -// Uncomment this line if you want lcms to use the black point tag in profile, -// if commented, lcms will compute the black point by its own. -// It is safer to leve it commented out -// #define HONOR_BLACK_POINT_TAG // Conversions @@ -79,10 +75,9 @@ void LCMSEXPORT cmsxyY2XYZ(LPcmsCIEXYZ Dest, const cmsCIExyY* Source) } - // Obtains WhitePoint from Temperature -BOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint) +LCMSBOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint) { double x, y; double T, T2, T3; @@ -147,7 +142,7 @@ BOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint) // - Then, I apply these coeficients to the original matrix -BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt, +LCMSBOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt, LPcmsCIExyYTRIPLE Primrs) { VEC3 WhitePoint, Coef; @@ -169,14 +164,12 @@ BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt, // Build Primaries matrix - VEC3init(&Primaries.v[0], xr, xg, xb); VEC3init(&Primaries.v[1], yr, yg, yb); VEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb)); // Result = Primaries ^ (-1) inverse matrix - if (!MAT3inverse(&Primaries, &Result)) return FALSE; @@ -184,11 +177,9 @@ BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt, VEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn); // Across inverse primaries ... - MAT3eval(&Coef, &Result, &WhitePoint); // Give us the Coefs, then I build transformation matrix - VEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb); VEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb); VEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb)); @@ -246,7 +237,7 @@ void ComputeChromaticAdaptation(LPMAT3 Conversion, // Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll // The cone matrix can be specified in ConeMatrix. If NULL, Bradford is assumed -BOOL cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll) +LCMSBOOL cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll) { MAT3 LamRigg = {{ // Bradford matrix {{ 0.8951, 0.2664, -0.1614 }}, @@ -265,7 +256,7 @@ BOOL cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcms // Same as anterior, but assuming D50 destination. White point is given in xyY -BOOL cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt) +LCMSBOOL cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt) { cmsCIEXYZ Dn; MAT3 Bradford; @@ -284,7 +275,7 @@ BOOL cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt) // Same as anterior, but assuming D50 source. White point is given in xyY -BOOL cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt) +LCMSBOOL cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt) { cmsCIEXYZ Dn; MAT3 Bradford; @@ -304,7 +295,7 @@ BOOL cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt) // Adapts a color to a given illuminant. Original color is expected to have // a SourceWhitePt white point. -BOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, +LCMSBOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, LPcmsCIEXYZ SourceWhitePt, LPcmsCIEXYZ Illuminant, LPcmsCIEXYZ Value) @@ -404,8 +395,6 @@ double Robertson(LPcmsCIExyY v) dj = ((vs - vj) - tj * (us - uj)) / sqrt(1 + tj*tj); - - if ((j!=0) && (di/dj < 0.0)) { Tc = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi)); break; @@ -423,7 +412,7 @@ double Robertson(LPcmsCIExyY v) static -BOOL InRange(LPcmsCIExyY a, LPcmsCIExyY b, double tolerance) +LCMSBOOL InRange(LPcmsCIExyY a, LPcmsCIExyY b, double tolerance) { double dist_x, dist_y; @@ -458,6 +447,7 @@ int FromD40toD150(LPWHITEPOINTS pts) } +// To be removed in future versions void _cmsIdentifyWhitePoint(char *Buffer, LPcmsCIEXYZ WhitePt) { int i, n; @@ -518,7 +508,6 @@ int BlackPointAsDarkerColorant(cmsHPROFILE hInput, cmsCIEXYZ BlackXYZ, MediaWhite; // If the profile does not support input direction, assume Black point 0 - if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; @@ -527,7 +516,6 @@ int BlackPointAsDarkerColorant(cmsHPROFILE hInput, // Try to get black by using black colorant - Space = cmsGetColorSpace(hInput); if (!_cmsEndPointsBySpace(Space, &White, &Black, &nChannels)) { @@ -576,7 +564,7 @@ int BlackPointAsDarkerColorant(cmsHPROFILE hInput, // Get a black point of output CMYK profile, discounting any ink-limiting embedded -// in the profile. Fou doing that, use perceptual intent in input direction: +// in the profile. For doing that, use perceptual intent in input direction: // Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab static @@ -651,6 +639,8 @@ int GetV4PerceptualBlack(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, DWORD dwF D50BlackPoint.X = PERCEPTUAL_BLACK_X; D50BlackPoint.Y = PERCEPTUAL_BLACK_Y; D50BlackPoint.Z = PERCEPTUAL_BLACK_Z; + + // Obtain the absolute XYZ. Adapt perceptual black back from D50 to whatever media white cmsAdaptToIlluminant(BlackPoint, cmsD50_XYZ(), &MediaWhite, &D50BlackPoint); } @@ -662,26 +652,24 @@ int GetV4PerceptualBlack(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, DWORD dwF // This function shouldn't exist at all -- there is such quantity of broken // profiles on black point tag, that we must somehow fix chromaticity to // avoid huge tint when doing Black point compensation. This function does -// just that. If BP is specified, then forces it to neutral and uses only L -// component. If does not exist, computes it by taking 400% of ink or RGB=0 This -// works well on relative intent and is undefined on perceptual & saturation. -// However, I will support all intents for tricking & trapping. - +// just that. There is a special flag for using black point tag, but turned +// off by default because it is bogus on most profiles. The detection algorithm +// involves to turn BP to neutral and to use only L component. int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent, DWORD dwFlags) { - // v4 + perceptual & saturation intents does have its own black point + // v4 + perceptual & saturation intents does have its own black point, and it is + // well specified enough to use it. if ((cmsGetProfileICCversion(hProfile) >= 0x4000000) && (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { // Matrix shaper share MRC & perceptual intents - if (_cmsIsMatrixShaper(hProfile)) return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, cmsFLAGS_NOTPRECALC); - // Get fixed value + // CLUT based - Get perceptual black point (fixed value) return GetV4PerceptualBlack(BlackPoint, hProfile, dwFlags); } @@ -701,7 +689,6 @@ int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent cmsTakeMediaWhitePoint(&MediaWhite, hProfile); // Black point is absolute XYZ, so adapt to D50 to get PCS value - cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ); // Force a=b=0 to get rid of any chroma @@ -713,7 +700,6 @@ int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab); // Return BP as D50 relative or absolute XYZ (depends on flags) - if (!(dwFlags & LCMS_BPFLAGS_D50_ADAPTED)) cmsAdaptToIlluminant(BlackPoint, cmsD50_XYZ(), &MediaWhite, &TrustedBlackPoint); else @@ -724,15 +710,15 @@ int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent #endif - // If output profile, discount ink-limiting + // That is about v2 profiles. + // If output profile, discount ink-limiting and that's all if (Intent == INTENT_RELATIVE_COLORIMETRIC && (cmsGetDeviceClass(hProfile) == icSigOutputClass) && (cmsGetColorSpace(hProfile) == icSigCmykData)) return BlackPointUsingPerceptualBlack(BlackPoint, hProfile, dwFlags); // Nope, compute BP using current intent. - return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags); } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c index 8b82f26c5f2..ec37bebb1e3 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -52,7 +52,6 @@ #include "lcms.h" -// #define DEBUG 1 // Transformations stuff // ----------------------------------------------------------------------- @@ -85,7 +84,7 @@ void LCMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, void LCMSEXPORT cmsGetAlarmCodes(int *r, int *g, int *b); void LCMSEXPORT cmsSetAlarmCodes(int r, int g, int b); -BOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, +LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection); // ------------------------------------------------------------------------- @@ -343,7 +342,7 @@ void PrecalculatedXFORM(_LPcmsTRANSFORM p, p ->DeviceLink ->CLut16params.Interp3D(wIn, wOut, p ->DeviceLink -> T, &p ->DeviceLink -> CLut16params); - } + } else cmsEvalLUT(p -> DeviceLink, wIn, wOut); @@ -414,7 +413,7 @@ void CachedXFORM(_LPcmsTRANSFORM p, register LPBYTE output; WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS]; register unsigned int i, n; - WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; + WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; accum = (LPBYTE) in; @@ -427,10 +426,10 @@ void CachedXFORM(_LPcmsTRANSFORM p, ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS); - LCMS_READ_LOCK(&p ->rwlock); - CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); + LCMS_READ_LOCK(&p ->rwlock); + CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); for (i=0; i < n; i++) { @@ -443,14 +442,14 @@ void CachedXFORM(_LPcmsTRANSFORM p, } else { - // Try to speedup things on plain devicelinks + // Try to speedup things on plain devicelinks - if (p ->DeviceLink ->wFlags == LUT_HAS3DGRID) { + if (p ->DeviceLink ->wFlags == LUT_HAS3DGRID) { p ->DeviceLink ->CLut16params.Interp3D(wIn, wOut, p ->DeviceLink -> T, &p ->DeviceLink -> CLut16params); - } + } else cmsEvalLUT(p -> DeviceLink, wIn, wOut); @@ -463,10 +462,10 @@ void CachedXFORM(_LPcmsTRANSFORM p, } - LCMS_WRITE_LOCK(&p ->rwlock); - CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); + LCMS_WRITE_LOCK(&p ->rwlock); + CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); } @@ -483,7 +482,7 @@ void CachedXFORMGamutCheck(_LPcmsTRANSFORM p, register LPBYTE output; WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS]; register unsigned int i, n; - WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; + WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; accum = (LPBYTE) in; @@ -495,10 +494,10 @@ void CachedXFORMGamutCheck(_LPcmsTRANSFORM p, ZeroMemory(wIn, sizeof(WORD) * MAXCHANNELS); ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS); - LCMS_READ_LOCK(&p ->rwlock); - CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); + LCMS_READ_LOCK(&p ->rwlock); + CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); for (i=0; i < n; i++) { @@ -520,10 +519,10 @@ void CachedXFORMGamutCheck(_LPcmsTRANSFORM p, output = p -> ToOutput(p, wOut, output); } - LCMS_WRITE_LOCK(&p ->rwlock); - CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); + LCMS_WRITE_LOCK(&p ->rwlock); + CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); } @@ -635,6 +634,8 @@ LPMATSHAPER cmsBuildGrayInputMatrixShaper(cmsHPROFILE hProfile) MAT3 Scale; GrayTRC = cmsReadICCGamma(hProfile, icSigGrayTRCTag); // Y + if (GrayTRC == NULL) return NULL; + cmsTakeIluminant(&Illuminant, hProfile); if (cmsGetPCS(hProfile) == icSigLabData) { @@ -789,6 +790,10 @@ LPMATSHAPER cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile) InverseShapes[1] = cmsReadICCGammaReversed(OutputProfile, icSigGreenTRCTag); InverseShapes[2] = cmsReadICCGammaReversed(OutputProfile, icSigBlueTRCTag); + if (InverseShapes[0] == NULL || + InverseShapes[1] == NULL || + InverseShapes[2] == NULL) return NULL; + OutMatSh = cmsAllocMatShaper(&DoubleInv, InverseShapes, MATSHAPER_OUTPUT); cmsFreeGammaTriple(InverseShapes); @@ -801,7 +806,7 @@ LPMATSHAPER cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile) // This function builds a transform matrix chaining parameters static -BOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) +LCMSBOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) { MAT3 From, To, ToInv, Transfer; LPGAMMATABLE In[3], InverseOut[3]; @@ -814,7 +819,6 @@ BOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) if (!cmsReadICCMatrixRGB2XYZ(&To, p -> OutputProfile)) return FALSE; - // invert dest if (MAT3inverse(&To, &ToInv) < 0) @@ -838,10 +842,14 @@ BOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) InverseOut[1] = cmsReadICCGammaReversed(p -> OutputProfile, icSigGreenTRCTag); InverseOut[2] = cmsReadICCGammaReversed(p -> OutputProfile, icSigBlueTRCTag); + if (!InverseOut[0] || !InverseOut[1] || !InverseOut[2]) { + cmsFreeGammaTriple(In); + return FALSE; + } + p -> SmeltMatShaper = cmsAllocMatShaper2(&Transfer, In, InverseOut, MATSHAPER_ALLSMELTED); cmsFreeGammaTriple(In); - cmsFreeGammaTriple(InverseOut); return (p -> SmeltMatShaper != NULL); @@ -1029,7 +1037,7 @@ void TakeConversionRoutines(_LPcmsTRANSFORM p, int DoBPC) // Check colorspace static -BOOL IsProperColorSpace(cmsHPROFILE hProfile, DWORD dwFormat, BOOL lUsePCS) +LCMSBOOL IsProperColorSpace(cmsHPROFILE hProfile, DWORD dwFormat, LCMSBOOL lUsePCS) { int Space = T_COLORSPACE(dwFormat); @@ -1049,10 +1057,10 @@ _LPcmsTRANSFORM AllocEmptyTransform(void) { // Allocate needed memory - _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) malloc(sizeof(_cmsTRANSFORM)); + _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) _cmsMalloc(sizeof(_cmsTRANSFORM)); if (!p) { - cmsSignalError(LCMS_ERRC_ABORTED, "cmsCreateTransform: malloc() failed"); + cmsSignalError(LCMS_ERRC_ABORTED, "cmsCreateTransform: _cmsMalloc() failed"); return NULL; } @@ -1078,7 +1086,7 @@ _LPcmsTRANSFORM AllocEmptyTransform(void) p -> ExitColorSpace = (icColorSpaceSignature) 0; p -> AdaptationState = GlobalAdaptationState; - LCMS_CREATE_LOCK(&p->rwlock); + LCMS_CREATE_LOCK(&p->rwlock); return p; } @@ -1269,12 +1277,12 @@ _LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, else { // Can we optimize matrix-shaper only transform? - if (*FromTagPtr == 0 && - *ToTagPtr == 0 && - !p->PreviewProfile && - p -> Intent != INTENT_ABSOLUTE_COLORIMETRIC && + if ((*FromTagPtr == 0) && + (*ToTagPtr == 0) && + (!p->PreviewProfile) && + (p -> Intent != INTENT_ABSOLUTE_COLORIMETRIC) && (p -> EntryColorSpace == icSigRgbData) && - (p -> ExitColorSpace == icSigRgbData) && + (p -> ExitColorSpace == icSigRgbData) && !(p -> dwOriginalFlags & cmsFLAGS_BLACKPOINTCOMPENSATION)) { // Yes... try to smelt matrix-shapers @@ -1530,7 +1538,6 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, TakeConversionRoutines(p, dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); - if (!(p -> dwOriginalFlags & cmsFLAGS_NOTPRECALC)) { LPLUT DeviceLink; @@ -1553,7 +1560,8 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, DeviceLink = _cmsPrecalculateDeviceLink((cmsHTRANSFORM) p, dwFlags); } - if (p -> dwOriginalFlags & cmsFLAGS_GAMUTCHECK) { + // Allow to specify cmsFLAGS_GAMUTCHECK, even if no proofing profile is given + if ((p ->PreviewProfile != NULL) && (p -> dwOriginalFlags & cmsFLAGS_GAMUTCHECK)) { GamutCheck = _cmsPrecalculateGamutCheck((cmsHTRANSFORM) p); } @@ -1561,7 +1569,6 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, // If input colorspace is Rgb, Cmy, then use tetrahedral interpolation // for speed reasons (it only works well on spaces on Luma is diagonal, and // not if luma is in separate channel) - if (p ->EntryColorSpace == icSigRgbData || p ->EntryColorSpace == icSigCmyData) { @@ -1663,12 +1670,12 @@ void LCMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) cmsFreeMatShaper(p -> SmeltMatShaper); if (p ->NamedColorList) cmsFreeNamedColorList(p ->NamedColorList); - if (p -> GamutCheck) - cmsFreeLUT(p -> GamutCheck); + if (p -> GamutCheck) + cmsFreeLUT(p -> GamutCheck); - LCMS_FREE_LOCK(&p->rwlock); + LCMS_FREE_LOCK(&p->rwlock); - free((void *) p); + _cmsFree((void *) p); } @@ -1704,7 +1711,7 @@ void LCMSEXPORT cmsGetAlarmCodes(int *r, int *g, int *b) // Returns TRUE if the profile is implemented as matrix-shaper -BOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile) { switch (cmsGetColorSpace(hProfile)) { @@ -1728,7 +1735,7 @@ BOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile) } -BOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, +LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection) { @@ -1774,6 +1781,16 @@ int MultiprofileSampler(register WORD In[], register WORD Out[], register LPVOID } +static +int IsAllowedInSingleXform(icProfileClassSignature aClass) +{ + return (aClass == icSigInputClass) || + (aClass == icSigDisplayClass) || + (aClass == icSigOutputClass) || + (aClass == icSigColorSpaceClass); +} + + // A multiprofile transform does chain several profiles into a single // devicelink. It couls also be used to merge named color profiles into // a single database. @@ -1805,10 +1822,16 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], // There is a simple case with just two profiles, try to catch it in order of getting // black preservation to work on this function, at least with two profiles. + if (nProfiles == 2) { - if ((cmsGetDeviceClass(hProfiles[0]) != icSigLinkClass) && - (cmsGetDeviceClass(hProfiles[1]) != icSigLinkClass)) + icProfileClassSignature Class1 = cmsGetDeviceClass(hProfiles[0]); + icProfileClassSignature Class2 = cmsGetDeviceClass(hProfiles[1]); + + // Only input, output and display are allowed + + if (IsAllowedInSingleXform(Class1) && + IsAllowedInSingleXform(Class2)) return cmsCreateTransform(hProfiles[0], dwInput, hProfiles[1], dwOutput, Intent, dwFlags); } @@ -1984,6 +2007,14 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], if (hLab) cmsCloseProfile(hLab); if (hXYZ) cmsCloseProfile(hXYZ); + + if (p ->EntryColorSpace == icSigRgbData || + p ->EntryColorSpace == icSigCmyData) { + + p->DeviceLink -> CLut16params.Interp3D = cmsTetrahedralInterp16; + } + + if ((Intent != INTENT_ABSOLUTE_COLORIMETRIC) && !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) _cmsFixWhiteMisalignment(p); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/icc34.h b/jdk/src/share/native/sun/java2d/cmm/lcms/icc34.h index 409928362ac..6ae05188889 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/icc34.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/icc34.h @@ -206,6 +206,11 @@ typedef __int32_t icInt64Number[2]; #if defined(__sun) || defined(__hpux) || defined (__MINGW) || defined(__MINGW32__) +#if defined (__MINGW) || defined(__MINGW32__) +#include <stdint.h> +#endif + + typedef uint8_t icUInt8Number; typedef uint16_t icUInt16Number; typedef uint32_t icUInt32Number; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h index 81184b098fb..33b3cca67fd 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -49,8 +49,8 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// Version 1.16 -#undef DEBUG +// Version 1.18 + #ifndef __cms_H // ********** Configuration toggles **************************************** @@ -62,13 +62,8 @@ // virtually any machine. //#define USE_FLOAT 1 -#ifdef _WIN64 -#define USE_C 1 -#undef USE_ASSEMBLER -#else -#undef USE_C +// #define USE_C 1 #define USE_ASSEMBLER 1 -#endif // Define this if you are using this package as a DLL (windows only) @@ -77,15 +72,11 @@ // Uncomment if you are trying the engine in a non-windows environment // like linux, SGI, VAX, FreeBSD, BeOS, etc. -#if !defined(_WIN32) || !defined(_WIN64) #define NON_WINDOWS 1 -#endif // Uncomment this one if you are using big endian machines (only meaningful // when NON_WINDOWS is used) -#ifndef _LITTLE_ENDIAN -#define USE_BIG_ENDIAN 1 -#endif +// #define USE_BIG_ENDIAN 1 // Uncomment this one if your compiler/machine does support the // "long long" type This will speedup fixed point math. (USE_C only) @@ -104,18 +95,24 @@ // Uncomment this line on multithreading environments // #define USE_PTHREADS 1 +// Uncomment this line if you want lcms to use the black point tag in profile, +// if commented, lcms will compute the black point by its own. +// It is safer to leve it commented out +// #define HONOR_BLACK_POINT_TAG 1 + // ********** End of configuration toggles ****************************** -#define LCMS_VERSION 116 +#define LCMS_VERSION 118 // Microsoft VisualC++ // Deal with Microsoft's attempt at deprecating C standard runtime functions - #ifdef _MSC_VER # undef NON_WINDOWS # if (_MSC_VER >= 1400) +# ifndef _CRT_SECURE_NO_DEPRECATE # define _CRT_SECURE_NO_DEPRECATE 1 +# endif # endif #endif @@ -125,7 +122,6 @@ # undef NON_WINDOWS #endif - #include <stdio.h> #include <stdlib.h> #include <math.h> @@ -134,11 +130,11 @@ #include <time.h> // Metroworks CodeWarrior - #ifdef __MWERKS__ # define unlink remove # if WIN32 # define USE_CUSTOM_SWAB 1 +# undef NON_WINDOWS # else # define NON_WINDOWS 1 # endif @@ -172,15 +168,21 @@ typedef pthread_rwlock_t LCMS_RWLOCK_T; # define USE_BIG_ENDIAN 1 #endif -#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) || defined(__ppc__) +#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) || defined(__ppc__) || defined(__s390__) || defined(__s390x__) # define USE_BIG_ENDIAN 1 #endif -#ifdef TARGET_CPU_PPC +#if TARGET_CPU_PPC # define USE_BIG_ENDIAN 1 #endif -#ifdef macintosh +#if macintosh +# ifndef __LITTLE_ENDIAN__ +# define USE_BIG_ENDIAN 1 +# endif +#endif + +#ifdef __BIG_ENDIAN__ # define USE_BIG_ENDIAN 1 #endif @@ -217,11 +219,8 @@ typedef pthread_rwlock_t LCMS_RWLOCK_T; typedef unsigned char BYTE, *LPBYTE; typedef unsigned short WORD, *LPWORD; typedef unsigned long DWORD, *LPDWORD; -typedef int BOOL; typedef char *LPSTR; typedef void *LPVOID; -typedef void* LCMSHANDLE; - #define ZeroMemory(p,l) memset((p),0,(l)) #define CopyMemory(d,s,l) memcpy((d),(s),(l)) @@ -263,8 +262,12 @@ typedef void* LCMSHANDLE; #include <windows.h> -typedef HANDLE LCMSHANDLE; - +#ifdef _WIN64 +# ifdef USE_ASSEMBLER +# undef USE_ASSEMBLER +# define USE_C 1 +# endif +#endif #ifdef USE_INT64 # ifndef LCMSULONGLONG @@ -296,6 +299,10 @@ typedef int LCMS_RWLOCK_T; # define LCMS_UNLOCK(x) #endif +// Base types + +typedef int LCMSBOOL; +typedef void* LCMSHANDLE; #include "icc34.h" // ICC header file @@ -322,16 +329,10 @@ typedef int LCMS_RWLOCK_T; #define icSigMCHEData ((icColorSpaceSignature) 0x4d434845L) // MCHE #define icSigMCHFData ((icColorSpaceSignature) 0x4d434846L) // MCHF -#define icSigCAM97JABData ((icColorSpaceSignature) 0x4A616231L) // 'Jab1' H. Zeng -#define icSigCAM02JABData ((icColorSpaceSignature) 0x4A616232L) // 'Jab2' H. Zeng -#define icSigCAM02JCHData ((icColorSpaceSignature) 0x4A636A32L) // 'Jch2' H. Zeng - #define icSigChromaticityTag ((icTagSignature) 0x6368726dL) // As per Addendum 2 to Spec. ICC.1:1998-09 #define icSigChromaticAdaptationTag ((icTagSignature) 0x63686164L) // 'chad' #define icSigColorantTableTag ((icTagSignature) 0x636c7274L) // 'clrt' #define icSigColorantTableOutTag ((icTagSignature) 0x636c6f74L) // 'clot' -#define icSigHPGamutDescTag ((icTagSignature) 0x676D7441L) // 'gmtA' H. Zeng - #define icSigParametricCurveType ((icTagTypeSignature) 0x70617261L) // parametric (ICC 4.0) #define icSigMultiLocalizedUnicodeType ((icTagTypeSignature) 0x6D6C7563L) @@ -340,7 +341,6 @@ typedef int LCMS_RWLOCK_T; #define icSiglutAtoBType ((icTagTypeSignature) 0x6d414220L) // mAB #define icSiglutBtoAType ((icTagTypeSignature) 0x6d424120L) // mBA #define icSigColorantTableType ((icTagTypeSignature) 0x636c7274L) // clrt -#define icSigHPGamutDescType ((icTagTypeSignature) 0x676D7441L) // gmtA H. Zeng typedef struct { @@ -438,9 +438,6 @@ extern "C" { #ifndef itoa # define itoa _itoa #endif -#ifndef filelength -# define filelength _filelength -#endif #ifndef fileno # define fileno _fileno #endif @@ -450,6 +447,14 @@ extern "C" { #ifndef hypot # define hypot _hypot #endif +#ifndef snprintf +# define snprintf _snprintf +#endif +#ifndef vsnprintf +# define vsnprintf _vsnprintf +#endif + + #endif @@ -470,8 +475,9 @@ typedef LCMSHANDLE cmsHTRANSFORM; // Format of pixel is defined by one DWORD, using bit fields as follows // -// TTTTT U Y F P X S EEE CCCC BBB +// D TTTTT U Y F P X S EEE CCCC BBB // +// D: Use dither (8 bits only) // T: Pixeltype // F: Flavor 0=MinIsBlack(Chocolate) 1=MinIsWhite(Vanilla) // P: Planar? 0=Chunky, 1=Planar @@ -483,6 +489,7 @@ typedef LCMSHANDLE cmsHTRANSFORM; // Y: Swap first - changes ABGR to BGRA and KCMY to CMYK +#define DITHER_SH(s) ((s) << 22) #define COLORSPACE_SH(s) ((s) << 16) #define SWAPFIRST_SH(s) ((s) << 14) #define FLAVOR_SH(s) ((s) << 13) @@ -711,20 +718,20 @@ typedef LCMSHANDLE cmsHTRANSFORM; typedef struct { - unsigned int Crc32; // Has my table been touched? + unsigned int Crc32; // Has my table been touched? - // Keep initial parameters for further serialization + // Keep initial parameters for further serialization int Type; double Params[10]; - } LCMSGAMMAPARAMS, FAR* LPLCMSGAMMAPARAMS; + } LCMSGAMMAPARAMS, FAR* LPLCMSGAMMAPARAMS; // Gamma tables. typedef struct { - LCMSGAMMAPARAMS Seed; // Parameters used for table creation + LCMSGAMMAPARAMS Seed; // Parameters used for table creation // Table-based representation follows @@ -858,7 +865,7 @@ LCMSAPI LPcmsCIExyY LCMSEXPORT cmsD50_xyY(void); LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess); LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, DWORD dwSize); -LCMSAPI BOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); // Predefined run-time profiles @@ -915,14 +922,14 @@ LCMSAPI double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab LCMSAPI void LCMSEXPORT cmsClampLab(LPcmsCIELab Lab, double amax, double amin, double bmax, double bmin); -LCMSAPI BOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint); +LCMSAPI LCMSBOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint); -LCMSAPI BOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, +LCMSAPI LCMSBOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, LPcmsCIEXYZ SourceWhitePt, LPcmsCIEXYZ Illuminant, LPcmsCIEXYZ Value); -LCMSAPI BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, +LCMSAPI LCMSBOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePoint, LPcmsCIExyYTRIPLE Primaries); @@ -976,7 +983,7 @@ LCMSAPI LPGAMMATABLE LCMSEXPORT cmsDupGamma(LPGAMMATABLE Src); LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma); LCMSAPI LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma); LCMSAPI LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma, int nPoints); -LCMSAPI BOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); +LCMSAPI LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); LCMSAPI double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t); LCMSAPI double LCMSEXPORT cmsEstimateGammaEx(LPWORD Table, int nEntries, double Thereshold); LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReadICCGamma(cmsHPROFILE hProfile, icTagSignature sig); @@ -984,14 +991,14 @@ LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReadICCGammaReversed(cmsHPROFILE hProfile, i // Access to Profile data. -LCMSAPI BOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile); LCMSAPI DWORD LCMSEXPORT cmsTakeHeaderFlags(cmsHPROFILE hProfile); LCMSAPI DWORD LCMSEXPORT cmsTakeHeaderAttributes(cmsHPROFILE hProfile); -LCMSAPI void LCMSEXPORT cmsSetLanguage(int LanguageCode, int CountryCode); +LCMSAPI void LCMSEXPORT cmsSetLanguage(const char LanguageCode[4], const char CountryCode[4]); LCMSAPI const char* LCMSEXPORT cmsTakeProductName(cmsHPROFILE hProfile); LCMSAPI const char* LCMSEXPORT cmsTakeProductDesc(cmsHPROFILE hProfile); LCMSAPI const char* LCMSEXPORT cmsTakeProductInfo(cmsHPROFILE hProfile); @@ -1000,13 +1007,13 @@ LCMSAPI const char* LCMSEXPORT cmsTakeModel(cmsHPROFILE hProfile); LCMSAPI const char* LCMSEXPORT cmsTakeCopyright(cmsHPROFILE hProfile); LCMSAPI const BYTE* LCMSEXPORT cmsTakeProfileID(cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig); LCMSAPI int LCMSEXPORT cmsTakeRenderingIntent(cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len); LCMSAPI int LCMSEXPORT cmsReadICCTextEx(cmsHPROFILE hProfile, icTagSignature sig, char *Text, size_t size); LCMSAPI int LCMSEXPORT cmsReadICCText(cmsHPROFILE hProfile, icTagSignature sig, char *Text); @@ -1038,50 +1045,18 @@ LCMSAPI LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE h LCMSAPI void LCMSEXPORT cmsFreeProfileSequenceDescription(LPcmsSEQ pseq); -// Extended gamut tag -- an HP extension - -#define LCMSGAMUTMETHOD_SEGMENTMAXIMA 0 -#define LCMSGAMUTMETHOD_CONVEXHULL 1 -#define LCMSGAMUTMETHOD_ALPHASHAPE 2 - - -#define LCMSGAMUT_PHYSICAL 0 -#define LCMSGAMUT_HP1 1 -#define LCMSGAMUT_HP2 2 - -typedef struct { - - icColorSpaceSignature CoordSig; // Gamut coordinates signature - icUInt16Number Method; // Method used to generate gamut - icUInt16Number Usage; // Gamut usage or intent - - char Description[LCMS_DESC_MAX]; // Textual description - - cmsViewingConditions Vc; // The viewing conditions - - icUInt32Number Count; // Number of entries - double Data[1]; // The current data - - } cmsGAMUTEX, FAR* LPcmsGAMUTEX; - - -LCMSAPI LPcmsGAMUTEX LCMSEXPORT cmsReadExtendedGamut(cmsHPROFILE hProfile, int index); -LCMSAPI void LCMSEXPORT cmsFreeExtendedGamut(LPcmsGAMUTEX gex); - - - - // Translate form/to our notation to ICC LCMSAPI icColorSpaceSignature LCMSEXPORT _cmsICCcolorSpace(int OurNotation); -LCMSAPI int LCMSEXPORT _cmsLCMScolorSpace(icColorSpaceSignature ProfileSpace); -LCMSAPI int LCMSEXPORT _cmsChannelsOf(icColorSpaceSignature ColorSpace); -LCMSAPI BOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile); +LCMSAPI int LCMSEXPORT _cmsLCMScolorSpace(icColorSpaceSignature ProfileSpace); +LCMSAPI int LCMSEXPORT _cmsChannelsOf(icColorSpaceSignature ColorSpace); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile); +// How profiles may be used #define LCMS_USED_AS_INPUT 0 #define LCMS_USED_AS_OUTPUT 1 #define LCMS_USED_AS_PROOF 2 -LCMSAPI BOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection); LCMSAPI icColorSpaceSignature LCMSEXPORT cmsGetPCS(cmsHPROFILE hProfile); LCMSAPI icColorSpaceSignature LCMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile); @@ -1141,7 +1116,7 @@ LCMSAPI void LCMSEXPORT cmsSetProfileID(cmsHPROFILE hProfile, LPBYTE Pr // CRD special -#define cmsFLAGS_NODEFAULTRESOURCEDEF 0x00010000 +#define cmsFLAGS_NODEFAULTRESOURCEDEF 0x01000000 // Gridpoints @@ -1220,9 +1195,9 @@ typedef struct { // Named color support -LCMSAPI int LCMSEXPORT cmsNamedColorCount(cmsHTRANSFORM xform); -LCMSAPI BOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix); -LCMSAPI int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name); +LCMSAPI int LCMSEXPORT cmsNamedColorCount(cmsHTRANSFORM xform); +LCMSAPI LCMSBOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix); +LCMSAPI int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name); // Colorant tables @@ -1230,7 +1205,7 @@ LCMSAPI LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile // Profile creation -LCMSAPI BOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* data); +LCMSAPI LCMSBOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* data); // Converts a transform to a devicelink profile LCMSAPI cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD dwFlags); @@ -1240,8 +1215,8 @@ LCMSAPI void LCMSEXPORT _cmsSetLUTdepth(cmsHPROFILE hProfile, int depth); // Save profile -LCMSAPI BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName); -LCMSAPI BOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, +LCMSAPI LCMSBOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, size_t* BytesNeeded); @@ -1286,6 +1261,7 @@ LCMSAPI double LCMSEXPORT cmsEvalLUTreverse(LPLUT Lut, WORD Target[], WORD Resul LCMSAPI LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig); LCMSAPI LPLUT LCMSEXPORT cmsDupLUT(LPLUT Orig); + // LUT Sampling typedef int (* _cmsSAMPLER)(register WORD In[], @@ -1325,35 +1301,37 @@ LCMSAPI int LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable); // Persistence LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName); LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len); -LCMSAPI BOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName); -LCMSAPI BOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded); // Properties LCMSAPI const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val); - -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char* cSubProp, const char *Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer); LCMSAPI const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* cProp); LCMSAPI double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp); -LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE IT8, char ***PropertyNames); +LCMSAPI const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char *cSubProp); +LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, const char ***PropertyNames); +LCMSAPI int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char*** SubpropertyNames); // Datasets LCMSAPI const char* LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE IT8, int row, int col); LCMSAPI double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE IT8, int row, int col); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val); LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample); @@ -1361,25 +1339,28 @@ LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPa LCMSAPI double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample, const char *Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, const char* cSample, double Val); LCMSAPI int LCMSEXPORT cmsIT8GetDataFormat(LCMSHANDLE hIT8, const char* cSample); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample); LCMSAPI int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames); LCMSAPI const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer); +LCMSAPI int LCMSEXPORT cmsIT8GetPatchByName(LCMSHANDLE hIT8, const char *cSample); // The LABEL extension LCMSAPI int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetIndexColumn(LCMSHANDLE hIT8, const char* cSample); + // Formatter for double LCMSAPI void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE IT8, const char* Formatter); @@ -1405,15 +1386,16 @@ LCMSAPI void LCMSEXPORT cmsFloat2XYZEncoded(WORD XYZ[3], const cmsCIEXY // Profiling Extensions --- Would be removed from API in future revisions -LCMSAPI BOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text); -LCMSAPI BOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ); -LCMSAPI BOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut); -LCMSAPI BOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction); -LCMSAPI BOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm); -LCMSAPI BOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ PSeq); -LCMSAPI BOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); -LCMSAPI BOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime); -LCMSAPI BOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ PSeq); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddChromaticAdaptationTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* mat); // --------------------------------------------------------------------------------------------------- Inline functions @@ -1455,6 +1437,38 @@ LCMS_INLINE WORD _cmsClampWord(int in) return (WORD) in; } +#ifndef LCMS_USER_ALLOC + +// Low-level alloc hook + +LCMS_INLINE void* _cmsMalloc(size_t size) +{ + if (size > ((size_t) 1024*1024*500)) return NULL; // Never allow over 500Mb + if (size < 0) return NULL; // Prevent signed size_t exploits + + return (void*) malloc(size); +} + +LCMS_INLINE void* _cmsCalloc(size_t nmemb, size_t size) +{ + size_t alloc = nmemb * size; + + if (size == 0) { + return _cmsMalloc(0); + } + if (alloc / size != nmemb) { + return NULL; + } + return _cmsMalloc(alloc); +} + +LCMS_INLINE void _cmsFree(void *Ptr) +{ + if (Ptr) free(Ptr); +} + +#endif + // ------------------------------------------------------------------------------------------- end of inline functions // Signal error from inside lcms code @@ -1531,36 +1545,36 @@ typedef struct { // Matrix (Fixed 15.16) -void cdecl VEC3init(LPVEC3 r, double x, double y, double z); // double version -void cdecl VEC3initF(LPWVEC3 r, double x, double y, double z); // Fix32 version -void cdecl VEC3toFix(LPWVEC3 r, LPVEC3 v); -void cdecl VEC3fromFix(LPVEC3 r, LPWVEC3 v); -void cdecl VEC3scaleFix(LPWORD r, LPWVEC3 Scale); -void cdecl VEC3swap(LPVEC3 a, LPVEC3 b); -void cdecl VEC3divK(LPVEC3 r, LPVEC3 v, double d); -void cdecl VEC3perK(LPVEC3 r, LPVEC3 v, double d); -void cdecl VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b); -void cdecl VEC3perComp(LPVEC3 r, LPVEC3 a, LPVEC3 b); -BOOL cdecl VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance); -BOOL cdecl VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance); -void cdecl VEC3scaleAndCut(LPWVEC3 r, LPVEC3 v, double d); -void cdecl VEC3cross(LPVEC3 r, LPVEC3 u, LPVEC3 v); -void cdecl VEC3saturate(LPVEC3 v); -double cdecl VEC3distance(LPVEC3 a, LPVEC3 b); -double cdecl VEC3length(LPVEC3 a); +void cdecl VEC3init(LPVEC3 r, double x, double y, double z); // double version +void cdecl VEC3initF(LPWVEC3 r, double x, double y, double z); // Fix32 version +void cdecl VEC3toFix(LPWVEC3 r, LPVEC3 v); +void cdecl VEC3fromFix(LPVEC3 r, LPWVEC3 v); +void cdecl VEC3scaleFix(LPWORD r, LPWVEC3 Scale); +void cdecl VEC3swap(LPVEC3 a, LPVEC3 b); +void cdecl VEC3divK(LPVEC3 r, LPVEC3 v, double d); +void cdecl VEC3perK(LPVEC3 r, LPVEC3 v, double d); +void cdecl VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b); +void cdecl VEC3perComp(LPVEC3 r, LPVEC3 a, LPVEC3 b); +LCMSBOOL cdecl VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance); +LCMSBOOL cdecl VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance); +void cdecl VEC3scaleAndCut(LPWVEC3 r, LPVEC3 v, double d); +void cdecl VEC3cross(LPVEC3 r, LPVEC3 u, LPVEC3 v); +void cdecl VEC3saturate(LPVEC3 v); +double cdecl VEC3distance(LPVEC3 a, LPVEC3 b); +double cdecl VEC3length(LPVEC3 a); -void cdecl MAT3identity(LPMAT3 a); -void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b); -void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d); -int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b); -BOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b); -double cdecl MAT3det(LPMAT3 m); -void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v); -void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v); -void cdecl MAT3fromFix(LPMAT3 r, LPWMAT3 v); -void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v); -BOOL cdecl MAT3isIdentity(LPWMAT3 a, double Tolerance); -void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d); +void cdecl MAT3identity(LPMAT3 a); +void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b); +void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d); +int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b); +LCMSBOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b); +double cdecl MAT3det(LPMAT3 m); +void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v); +void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v); +void cdecl MAT3fromFix(LPMAT3 r, LPWMAT3 v); +void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v); +LCMSBOOL cdecl MAT3isIdentity(LPWMAT3 a, double Tolerance); +void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d); // Is a table linear? @@ -1608,7 +1622,7 @@ typedef struct _lcms_l16params_struc { // Used on 16 bits interpolations void cdecl cmsCalcL16Params(int nSamples, LPL16PARAMS p); void cdecl cmsCalcCLUT16Params(int nSamples, int InputChan, int OutputChan, LPL16PARAMS p); void cdecl cmsCalcCLUT16ParamsEx(int nSamples, int InputChan, int OutputChan, - BOOL lUseTetrahedral, LPL16PARAMS p); + LCMSBOOL lUseTetrahedral, LPL16PARAMS p); WORD cdecl cmsLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p); Fixed32 cdecl cmsLinearInterpFixed(WORD Value1, WORD LutTable[], LPL16PARAMS p); @@ -1692,18 +1706,18 @@ struct _lcms_LUT_struc { // Gray axes fixup. Only on v2 8-bit Lab LUT - BOOL FixGrayAxes; + LCMSBOOL FixGrayAxes; - // Parameters used for curve creation + // Parameters used for curve creation - LCMSGAMMAPARAMS LCurvesSeed[4][MAXCHANNELS]; + LCMSGAMMAPARAMS LCurvesSeed[4][MAXCHANNELS]; }; // LUT, FAR* LPLUT; -BOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nEntries); +LCMSBOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nEntries); // CRC of gamma tables @@ -1721,7 +1735,7 @@ LPGAMMATABLE cdecl cmsConvertSampledCurveToGamma(LPSAMPLEDCURVE Sampled, doubl void cdecl cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max); void cdecl cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max); -BOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); +LCMSBOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); void cdecl cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints); LPSAMPLEDCURVE cdecl cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints); @@ -1755,19 +1769,19 @@ LPMATSHAPER cdecl cmsAllocMatShaper2(LPMAT3 matrix, LPGAMMATABLE In[], LPGAMMATA void cdecl cmsFreeMatShaper(LPMATSHAPER MatShaper); void cdecl cmsEvalMatShaper(LPMATSHAPER MatShaper, WORD In[], WORD Out[]); -BOOL cdecl cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile); +LCMSBOOL cdecl cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile); -LPMATSHAPER cdecl cmsBuildInputMatrixShaper(cmsHPROFILE InputProfile); -LPMATSHAPER cdecl cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile); +LPMATSHAPER cdecl cmsBuildInputMatrixShaper(cmsHPROFILE InputProfile); +LPMATSHAPER cdecl cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile); // White Point & Primary chromas handling -BOOL cdecl cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll); -BOOL cdecl cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt); -BOOL cdecl cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt); +LCMSBOOL cdecl cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll); +LCMSBOOL cdecl cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt); +LCMSBOOL cdecl cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt); -BOOL cdecl cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile); +LCMSBOOL cdecl cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile); // Inter-PCS conversion routines. They assume D50 as white point. void cdecl cmsXYZ2LabEncoded(WORD XYZ[3], WORD Lab[3]); @@ -1782,7 +1796,7 @@ WORD cdecl _cmsQuantizeVal(double i, int MaxSamples); LPcmsNAMEDCOLORLIST cdecl cmsAllocNamedColorList(int n); int cdecl cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSignature sig); void cdecl cmsFreeNamedColorList(LPcmsNAMEDCOLORLIST List); -BOOL cdecl cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]); +LCMSBOOL cdecl cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]); // I/O @@ -1804,7 +1818,7 @@ typedef struct _lcms_iccprofile_struct { icColorSpaceSignature PCS; icRenderingIntent RenderingIntent; icUInt32Number flags; - icUInt32Number attributes; + icUInt32Number attributes; cmsCIEXYZ Illuminant; // Additions for V4 profiles @@ -1826,22 +1840,23 @@ typedef struct _lcms_iccprofile_struct { char PhysicalFile[MAX_PATH]; - BOOL IsWrite; - BOOL SaveAs8Bits; + LCMSBOOL IsWrite; + LCMSBOOL SaveAs8Bits; struct tm Created; // I/O handlers - size_t (* Read)(void *buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc); + size_t (* Read)(void *buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc); - BOOL (* Seek)(struct _lcms_iccprofile_struct* Icc, size_t offset); - BOOL (* Close)(struct _lcms_iccprofile_struct* Icc); - size_t (* Tell)(struct _lcms_iccprofile_struct* Icc); + LCMSBOOL (* Seek)(struct _lcms_iccprofile_struct* Icc, size_t offset); + LCMSBOOL (* Close)(struct _lcms_iccprofile_struct* Icc); + size_t (* Tell)(struct _lcms_iccprofile_struct* Icc); + LCMSBOOL (* Grow)(struct _lcms_iccprofile_struct* Icc, size_t amount); // Writting - BOOL (* Write)(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr); + LCMSBOOL (* Write)(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr); size_t UsedSpace; @@ -1853,7 +1868,7 @@ typedef struct _lcms_iccprofile_struct { cmsHPROFILE cdecl _cmsCreateProfilePlaceholder(void); // Search into tag dictionary -icInt32Number cdecl _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, BOOL lSignalError); +icInt32Number cdecl _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, LCMSBOOL lSignalError); // Search for a particular tag, replace if found or add new one else LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const void* Init); @@ -1869,6 +1884,7 @@ void _cmsSetSaveToMemory(LPLCMSICCPROFILE Icc, LPVOID MemPtr, size_t dwSize); // These macros unpack format specifiers into integers +#define T_DITHER(s) (((s)>>22)&1) #define T_COLORSPACE(s) (((s)>>16)&31) #define T_SWAPFIRST(s) (((s)>>14)&1) #define T_FLAVOR(s) (((s)>>13)&1) @@ -1965,7 +1981,7 @@ typedef struct _cmstransform_struct { // Flag for transform involving v4 profiles - BOOL lInputV4Lab, lOutputV4Lab; + LCMSBOOL lInputV4Lab, lOutputV4Lab; // 1-pixel cache @@ -1975,7 +1991,7 @@ typedef struct _cmstransform_struct { double AdaptationState; // Figure for v4 incomplete state of adaptation - LCMS_RWLOCK_T rwlock; + LCMS_RWLOCK_T rwlock; } _cmsTRANSFORM,FAR *_LPcmsTRANSFORM; @@ -2012,7 +2028,7 @@ int cdecl cmsChooseCnvrt(int Absolute, // Clamping & Gamut handling -BOOL cdecl _cmsEndPointsBySpace(icColorSpaceSignature Space, +LCMSBOOL cdecl _cmsEndPointsBySpace(icColorSpaceSignature Space, WORD **White, WORD **Black, int *nOutputs); WORD * cdecl _cmsWhiteBySpace(icColorSpaceSignature Space); @@ -2041,7 +2057,7 @@ LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD LPLUT cdecl _cmsPrecalculateGamutCheck(cmsHTRANSFORM h); // Hot fixes bad profiles -BOOL cdecl _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p); +LCMSBOOL cdecl _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p); // Marks LUT as 8 bit on input LPLUT cdecl _cmsBlessLUT8(LPLUT Lut); @@ -2059,6 +2075,10 @@ void cdecl _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTr // Build a tone curve for K->K' if possible (only works on CMYK) LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints); +// Validates a LUT +LCMSBOOL cdecl _cmsValidateLUT(LPLUT NewLUT); + + // These are two VITAL macros, from converting between 8 and 16 bit // representation. @@ -2076,3 +2096,4 @@ LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints); #endif #endif + diff --git a/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c b/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c index 70f95c6c59b..bcd546b1394 100644 --- a/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c +++ b/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,9 +71,9 @@ int main(int argc, const char* argv[]) { out("class SocketOptionRegistry { "); out(" private SocketOptionRegistry() { } "); out(" private static class RegistryKey { "); - out(" private final SocketOption name; "); + out(" private final SocketOption<?> name; "); out(" private final ProtocolFamily family; "); - out(" RegistryKey(SocketOption name, ProtocolFamily family) { "); + out(" RegistryKey(SocketOption<?> name, ProtocolFamily family) { "); out(" this.name = name; "); out(" this.family = family; "); out(" } "); @@ -119,7 +119,7 @@ int main(int argc, const char* argv[]) { out(" return map; "); out(" } "); out(" } "); - out(" public static OptionKey findOption(SocketOption name, ProtocolFamily family) { "); + out(" public static OptionKey findOption(SocketOption<?> name, ProtocolFamily family) { "); out(" RegistryKey key = new RegistryKey(name, family); "); out(" return LazyInitialization.options.get(key); "); out(" } "); diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c index 81ecab813f9..473729437d0 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -89,21 +89,24 @@ jobject ckDatePtrToJDateObject(JNIEnv *env, const CK_DATE *ckpDate) /* load CK_DATE class */ jDateClass = (*env)->FindClass(env, CLASS_DATE); - assert(jDateClass != 0); + if (jDateClass == NULL) { return NULL; } /* load CK_DATE constructor */ jCtrId = (*env)->GetMethodID(env, jDateClass, "<init>", "([C[C[C)V"); - assert(jCtrId != 0); + if (jCtrId == NULL) { return NULL; } /* prep all fields */ jYear = ckCharArrayToJCharArray(env, (CK_CHAR_PTR)(ckpDate->year), 4); + if (jYear == NULL) { return NULL; } jMonth = ckCharArrayToJCharArray(env, (CK_CHAR_PTR)(ckpDate->month), 2); + if (jMonth == NULL) { return NULL; } jDay = ckCharArrayToJCharArray(env, (CK_CHAR_PTR)(ckpDate->day), 2); + if (jDay == NULL) { return NULL; } /* create new CK_DATE object */ jDateObject = (*env)->NewObject(env, jDateClass, jCtrId, jYear, jMonth, jDay); - assert(jDateObject != 0); + if (jDateObject == NULL) { return NULL; } /* free local references */ (*env)->DeleteLocalRef(env, jDateClass); @@ -131,11 +134,11 @@ jobject ckVersionPtrToJVersion(JNIEnv *env, const CK_VERSION_PTR ckpVersion) /* load CK_VERSION class */ jVersionClass = (*env)->FindClass(env, CLASS_VERSION); - assert(jVersionClass != 0); + if (jVersionClass == NULL) { return NULL; } /* load CK_VERSION constructor */ jCtrId = (*env)->GetMethodID(env, jVersionClass, "<init>", "(II)V"); - assert(jCtrId != 0); + if (jCtrId == NULL) { return NULL; } /* prep both fields */ jMajor = ckpVersion->major; @@ -144,7 +147,7 @@ jobject ckVersionPtrToJVersion(JNIEnv *env, const CK_VERSION_PTR ckpVersion) /* create new CK_VERSION object */ jVersionObject = (*env)->NewObject(env, jVersionClass, jCtrId, jMajor, jMinor); - assert(jVersionObject != 0); + if (jVersionObject == NULL) { return NULL; } /* free local references */ (*env)->DeleteLocalRef(env, jVersionClass); @@ -171,11 +174,11 @@ jobject ckSessionInfoPtrToJSessionInfo(JNIEnv *env, const CK_SESSION_INFO_PTR ck /* load CK_SESSION_INFO class */ jSessionInfoClass = (*env)->FindClass(env, CLASS_SESSION_INFO); - assert(jSessionInfoClass != 0); + if (jSessionInfoClass == NULL) { return NULL; } /* load CK_SESSION_INFO constructor */ jCtrId = (*env)->GetMethodID(env, jSessionInfoClass, "<init>", "(JJJJ)V"); - assert(jCtrId != 0); + if (jCtrId == NULL) { return NULL; } /* prep all fields */ jSlotID = ckULongToJLong(ckpSessionInfo->slotID); @@ -187,7 +190,7 @@ jobject ckSessionInfoPtrToJSessionInfo(JNIEnv *env, const CK_SESSION_INFO_PTR ck jSessionInfoObject = (*env)->NewObject(env, jSessionInfoClass, jCtrId, jSlotID, jState, jFlags, jDeviceError); - assert(jSessionInfoObject != 0); + if (jSessionInfoObject == NULL) { return NULL; } /* free local references */ (*env)->DeleteLocalRef(env, jSessionInfoClass); @@ -211,20 +214,21 @@ jobject ckAttributePtrToJAttribute(JNIEnv *env, const CK_ATTRIBUTE_PTR ckpAttrib jobject jPValue = NULL; jAttributeClass = (*env)->FindClass(env, CLASS_ATTRIBUTE); - assert(jAttributeClass != 0); + if (jAttributeClass == NULL) { return NULL; } /* load CK_INFO constructor */ jCtrId = (*env)->GetMethodID(env, jAttributeClass, "<init>", "(JLjava/lang/Object;)V"); - assert(jCtrId != 0); + if (jCtrId == NULL) { return NULL; } /* prep both fields */ jType = ckULongToJLong(ckpAttribute->type); jPValue = ckAttributeValueToJObject(env, ckpAttribute); + if ((*env)->ExceptionCheck(env)) { return NULL; } /* create new CK_ATTRIBUTE object */ jAttributeObject = (*env)->NewObject(env, jAttributeClass, jCtrId, jType, jPValue); - assert(jAttributeObject != 0); + if (jAttributeObject == NULL) { return NULL; } /* free local references */ (*env)->DeleteLocalRef(env, jAttributeClass); @@ -252,23 +256,27 @@ CK_VERSION_PTR jVersionToCKVersionPtr(JNIEnv *env, jobject jVersion) return NULL; } - /* allocate memory for CK_VERSION pointer */ - ckpVersion = (CK_VERSION_PTR) malloc(sizeof(CK_VERSION)); - /* get CK_VERSION class */ jVersionClass = (*env)->GetObjectClass(env, jVersion); - assert(jVersionClass != 0); + if (jVersionClass == NULL) { return NULL; } /* get Major */ jFieldID = (*env)->GetFieldID(env, jVersionClass, "major", "B"); - assert(jFieldID != 0); + if (jFieldID == NULL) { return NULL; } jMajor = (*env)->GetByteField(env, jVersion, jFieldID); - ckpVersion->major = jByteToCKByte(jMajor); /* get Minor */ jFieldID = (*env)->GetFieldID(env, jVersionClass, "minor", "B"); - assert(jFieldID != 0); + if (jFieldID == NULL) { return NULL; } jMinor = (*env)->GetByteField(env, jVersion, jFieldID); + + /* allocate memory for CK_VERSION pointer */ + ckpVersion = (CK_VERSION_PTR) malloc(sizeof(CK_VERSION)); + if (ckpVersion == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } + ckpVersion->major = jByteToCKByte(jMajor); ckpVersion->minor = jByteToCKByte(jMinor); return ckpVersion ; @@ -292,18 +300,36 @@ CK_DATE * jDateObjectPtrToCKDatePtr(JNIEnv *env, jobject jDate) jchar *jTempChars; CK_ULONG i; - /* allocate memory for CK_DATE pointer */ - ckpDate = (CK_DATE *) malloc(sizeof(CK_DATE)); + if (jDate == NULL) { + return NULL; + } /* get CK_DATE class */ jDateClass = (*env)->FindClass(env, CLASS_DATE); - assert(jDateClass != 0); + if (jDateClass == NULL) { return NULL; } /* get Year */ jFieldID = (*env)->GetFieldID(env, jDateClass, "year", "[C"); - assert(jFieldID != 0); + if (jFieldID == NULL) { return NULL; } jYear = (*env)->GetObjectField(env, jDate, jFieldID); + /* get Month */ + jFieldID = (*env)->GetFieldID(env, jDateClass, "month", "[C"); + if (jFieldID == NULL) { return NULL; } + jMonth = (*env)->GetObjectField(env, jDate, jFieldID); + + /* get Day */ + jFieldID = (*env)->GetFieldID(env, jDateClass, "day", "[C"); + if (jFieldID == NULL) { return NULL; } + jDay = (*env)->GetObjectField(env, jDate, jFieldID); + + /* allocate memory for CK_DATE pointer */ + ckpDate = (CK_DATE *) malloc(sizeof(CK_DATE)); + if (ckpDate == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } + if (jYear == NULL) { ckpDate->year[0] = 0; ckpDate->year[1] = 0; @@ -312,43 +338,66 @@ CK_DATE * jDateObjectPtrToCKDatePtr(JNIEnv *env, jobject jDate) } else { ckLength = (*env)->GetArrayLength(env, jYear); jTempChars = (jchar*) malloc((ckLength) * sizeof(jchar)); + if (jTempChars == NULL) { + free(ckpDate); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } (*env)->GetCharArrayRegion(env, jYear, 0, ckLength, jTempChars); + if ((*env)->ExceptionCheck(env)) { + free(ckpDate); + free(jTempChars); + return NULL; + } + for (i = 0; (i < ckLength) && (i < 4) ; i++) { ckpDate->year[i] = jCharToCKChar(jTempChars[i]); } free(jTempChars); } - /* get Month */ - jFieldID = (*env)->GetFieldID(env, jDateClass, "month", "[C"); - assert(jFieldID != 0); - jMonth = (*env)->GetObjectField(env, jDate, jFieldID); - if (jMonth == NULL) { ckpDate->month[0] = 0; ckpDate->month[1] = 0; } else { ckLength = (*env)->GetArrayLength(env, jMonth); jTempChars = (jchar*) malloc((ckLength) * sizeof(jchar)); + if (jTempChars == NULL) { + free(ckpDate); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } (*env)->GetCharArrayRegion(env, jMonth, 0, ckLength, jTempChars); + if ((*env)->ExceptionCheck(env)) { + free(ckpDate); + free(jTempChars); + return NULL; + } + for (i = 0; (i < ckLength) && (i < 4) ; i++) { ckpDate->month[i] = jCharToCKChar(jTempChars[i]); } free(jTempChars); } - /* get Day */ - jFieldID = (*env)->GetFieldID(env, jDateClass, "day", "[C"); - assert(jFieldID != 0); - jDay = (*env)->GetObjectField(env, jDate, jFieldID); - if (jDay == NULL) { ckpDate->day[0] = 0; ckpDate->day[1] = 0; } else { ckLength = (*env)->GetArrayLength(env, jDay); jTempChars = (jchar*) malloc((ckLength) * sizeof(jchar)); + if (jTempChars == NULL) { + free(ckpDate); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } (*env)->GetCharArrayRegion(env, jDay, 0, ckLength, jTempChars); + if ((*env)->ExceptionCheck(env)) { + free(ckpDate); + free(jTempChars); + return NULL; + } + for (i = 0; (i < ckLength) && (i < 4) ; i++) { ckpDate->day[i] = jCharToCKChar(jTempChars[i]); } @@ -374,23 +423,25 @@ CK_ATTRIBUTE jAttributeToCKAttribute(JNIEnv *env, jobject jAttribute) jlong jType; jobject jPValue; + // TBD: what if jAttribute == NULL?! + TRACE0("\nDEBUG: jAttributeToCKAttribute"); /* get CK_ATTRIBUTE class */ TRACE0(", getting attribute object class"); jAttributeClass = (*env)->GetObjectClass(env, jAttribute); - assert(jAttributeClass != 0); + if (jAttributeClass == NULL) { return ckAttribute; } /* get type */ TRACE0(", getting type field"); jFieldID = (*env)->GetFieldID(env, jAttributeClass, "type", "J"); - assert(jFieldID != 0); + if (jFieldID == NULL) { return ckAttribute; } jType = (*env)->GetLongField(env, jAttribute, jFieldID); TRACE1(", type=0x%X", jType); /* get pValue */ TRACE0(", getting pValue field"); jFieldID = (*env)->GetFieldID(env, jAttributeClass, "pValue", "Ljava/lang/Object;"); - assert(jFieldID != 0); + if (jFieldID == NULL) { return ckAttribute; } jPValue = (*env)->GetObjectField(env, jAttribute, jFieldID); TRACE1(", pValue=%p", jPValue); @@ -417,36 +468,50 @@ CK_SSL3_MASTER_KEY_DERIVE_PARAMS jSsl3MasterKeyDeriveParamToCKSsl3MasterKeyDeriv { // XXX don't return structs // XXX prefetch class and field ids - jclass jSsl3MasterKeyDeriveParamsClass = (*env)->FindClass(env, CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS); + jclass jSsl3MasterKeyDeriveParamsClass; CK_SSL3_MASTER_KEY_DERIVE_PARAMS ckParam; jfieldID fieldID; - jobject jObject; jclass jSsl3RandomDataClass; - jobject jRandomInfo; + jobject jRandomInfo, jRIClientRandom, jRIServerRandom, jVersion; /* get RandomInfo */ - jSsl3RandomDataClass = (*env)->FindClass(env, CLASS_SSL3_RANDOM_DATA); + jSsl3MasterKeyDeriveParamsClass = (*env)->FindClass(env, CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS); + if (jSsl3MasterKeyDeriveParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jSsl3MasterKeyDeriveParamsClass, "RandomInfo", "Lsun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA;"); - assert(fieldID != 0); + if (fieldID == NULL) { return ckParam; } jRandomInfo = (*env)->GetObjectField(env, jParam, fieldID); /* get pClientRandom and ulClientRandomLength out of RandomInfo */ + jSsl3RandomDataClass = (*env)->FindClass(env, CLASS_SSL3_RANDOM_DATA); + if (jSsl3RandomDataClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jSsl3RandomDataClass, "pClientRandom", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jRandomInfo, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.RandomInfo.pClientRandom), &(ckParam.RandomInfo.ulClientRandomLen)); + if (fieldID == NULL) { return ckParam; } + jRIClientRandom = (*env)->GetObjectField(env, jRandomInfo, fieldID); /* get pServerRandom and ulServerRandomLength out of RandomInfo */ fieldID = (*env)->GetFieldID(env, jSsl3RandomDataClass, "pServerRandom", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jRandomInfo, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.RandomInfo.pServerRandom), &(ckParam.RandomInfo.ulServerRandomLen)); + if (fieldID == NULL) { return ckParam; } + jRIServerRandom = (*env)->GetObjectField(env, jRandomInfo, fieldID); /* get pVersion */ fieldID = (*env)->GetFieldID(env, jSsl3MasterKeyDeriveParamsClass, "pVersion", "Lsun/security/pkcs11/wrapper/CK_VERSION;"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - ckParam.pVersion = jVersionToCKVersionPtr(env, jObject); + if (fieldID == NULL) { return ckParam; } + jVersion = (*env)->GetObjectField(env, jParam, fieldID); + + /* populate java values */ + ckParam.pVersion = jVersionToCKVersionPtr(env, jVersion); + if ((*env)->ExceptionCheck(env)) { return ckParam; } + jByteArrayToCKByteArray(env, jRIClientRandom, &(ckParam.RandomInfo.pClientRandom), &(ckParam.RandomInfo.ulClientRandomLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pVersion); + return ckParam; + } + jByteArrayToCKByteArray(env, jRIServerRandom, &(ckParam.RandomInfo.pServerRandom), &(ckParam.RandomInfo.ulServerRandomLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pVersion); + free(ckParam.RandomInfo.pClientRandom); + return ckParam; + } return ckParam ; } @@ -457,27 +522,52 @@ CK_SSL3_MASTER_KEY_DERIVE_PARAMS jSsl3MasterKeyDeriveParamToCKSsl3MasterKeyDeriv */ CK_TLS_PRF_PARAMS jTlsPrfParamsToCKTlsPrfParam(JNIEnv *env, jobject jParam) { - jclass jTlsPrfParamsClass = (*env)->FindClass(env, CLASS_TLS_PRF_PARAMS); + jclass jTlsPrfParamsClass; CK_TLS_PRF_PARAMS ckParam; jfieldID fieldID; - jobject jObject; + jobject jSeed, jLabel, jOutput; + // TBD: what if jParam == NULL?! + + /* get pSeed */ + jTlsPrfParamsClass = (*env)->FindClass(env, CLASS_TLS_PRF_PARAMS); + if (jTlsPrfParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jTlsPrfParamsClass, "pSeed", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pSeed), &(ckParam.ulSeedLen)); + if (fieldID == NULL) { return ckParam; } + jSeed = (*env)->GetObjectField(env, jParam, fieldID); + /* get pLabel */ fieldID = (*env)->GetFieldID(env, jTlsPrfParamsClass, "pLabel", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pLabel), &(ckParam.ulLabelLen)); - - ckParam.pulOutputLen = malloc(sizeof(CK_ULONG)); + if (fieldID == NULL) { return ckParam; } + jLabel = (*env)->GetObjectField(env, jParam, fieldID); + /* get pOutput */ fieldID = (*env)->GetFieldID(env, jTlsPrfParamsClass, "pOutput", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pOutput), ckParam.pulOutputLen); + if (fieldID == NULL) { return ckParam; } + jOutput = (*env)->GetObjectField(env, jParam, fieldID); + + /* populate java values */ + jByteArrayToCKByteArray(env, jSeed, &(ckParam.pSeed), &(ckParam.ulSeedLen)); + if ((*env)->ExceptionCheck(env)) { return ckParam; } + jByteArrayToCKByteArray(env, jLabel, &(ckParam.pLabel), &(ckParam.ulLabelLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pSeed); + return ckParam; + } + ckParam.pulOutputLen = malloc(sizeof(CK_ULONG)); + if (ckParam.pulOutputLen == NULL) { + free(ckParam.pSeed); + free(ckParam.pLabel); + JNU_ThrowOutOfMemoryError(env, 0); + return ckParam; + } + jByteArrayToCKByteArray(env, jOutput, &(ckParam.pOutput), ckParam.pulOutputLen); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pSeed); + free(ckParam.pLabel); + free(ckParam.pulOutputLen); + return ckParam; + } return ckParam ; } @@ -493,68 +583,91 @@ CK_SSL3_KEY_MAT_PARAMS jSsl3KeyMatParamToCKSsl3KeyMatParam(JNIEnv *env, jobject { // XXX don't return structs // XXX prefetch class and field ids - jclass jSsl3KeyMatParamsClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_PARAMS); + jclass jSsl3KeyMatParamsClass, jSsl3RandomDataClass, jSsl3KeyMatOutClass; CK_SSL3_KEY_MAT_PARAMS ckParam; jfieldID fieldID; - jlong jLong; - jboolean jBoolean; - jobject jObject; - jobject jRandomInfo; - jobject jReturnedKeyMaterial; - jclass jSsl3RandomDataClass; - jclass jSsl3KeyMatOutClass; + jlong jMacSizeInBits, jKeySizeInBits, jIVSizeInBits; + jboolean jIsExport; + jobject jRandomInfo, jRIClientRandom, jRIServerRandom; + jobject jReturnedKeyMaterial, jRMIvClient, jRMIvServer; CK_ULONG ckTemp; /* get ulMacSizeInBits */ + jSsl3KeyMatParamsClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_PARAMS); + if (jSsl3KeyMatParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jSsl3KeyMatParamsClass, "ulMacSizeInBits", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.ulMacSizeInBits = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jMacSizeInBits = (*env)->GetLongField(env, jParam, fieldID); /* get ulKeySizeInBits */ fieldID = (*env)->GetFieldID(env, jSsl3KeyMatParamsClass, "ulKeySizeInBits", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.ulKeySizeInBits = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jKeySizeInBits = (*env)->GetLongField(env, jParam, fieldID); /* get ulIVSizeInBits */ fieldID = (*env)->GetFieldID(env, jSsl3KeyMatParamsClass, "ulIVSizeInBits", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.ulIVSizeInBits = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jIVSizeInBits = (*env)->GetLongField(env, jParam, fieldID); /* get bIsExport */ fieldID = (*env)->GetFieldID(env, jSsl3KeyMatParamsClass, "bIsExport", "Z"); - assert(fieldID != 0); - jBoolean = (*env)->GetBooleanField(env, jParam, fieldID); - ckParam.bIsExport = jBooleanToCKBBool(jBoolean); + if (fieldID == NULL) { return ckParam; } + jIsExport = (*env)->GetBooleanField(env, jParam, fieldID); /* get RandomInfo */ jSsl3RandomDataClass = (*env)->FindClass(env, CLASS_SSL3_RANDOM_DATA); + if (jSsl3RandomDataClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jSsl3KeyMatParamsClass, "RandomInfo", "Lsun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA;"); - assert(fieldID != 0); + if (fieldID == NULL) { return ckParam; } jRandomInfo = (*env)->GetObjectField(env, jParam, fieldID); /* get pClientRandom and ulClientRandomLength out of RandomInfo */ fieldID = (*env)->GetFieldID(env, jSsl3RandomDataClass, "pClientRandom", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jRandomInfo, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.RandomInfo.pClientRandom), &(ckParam.RandomInfo.ulClientRandomLen)); + if (fieldID == NULL) { return ckParam; } + jRIClientRandom = (*env)->GetObjectField(env, jRandomInfo, fieldID); /* get pServerRandom and ulServerRandomLength out of RandomInfo */ fieldID = (*env)->GetFieldID(env, jSsl3RandomDataClass, "pServerRandom", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jRandomInfo, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.RandomInfo.pServerRandom), &(ckParam.RandomInfo.ulServerRandomLen)); + if (fieldID == NULL) { return ckParam; } + jRIServerRandom = (*env)->GetObjectField(env, jRandomInfo, fieldID); /* get pReturnedKeyMaterial */ jSsl3KeyMatOutClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_OUT); + if (jSsl3KeyMatOutClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jSsl3KeyMatParamsClass, "pReturnedKeyMaterial", "Lsun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT;"); - assert(fieldID != 0); + if (fieldID == NULL) { return ckParam; } jReturnedKeyMaterial = (*env)->GetObjectField(env, jParam, fieldID); + /* get pIVClient out of pReturnedKeyMaterial */ + fieldID = (*env)->GetFieldID(env, jSsl3KeyMatOutClass, "pIVClient", "[B"); + if (fieldID == NULL) { return ckParam; } + jRMIvClient = (*env)->GetObjectField(env, jReturnedKeyMaterial, fieldID); + + /* get pIVServer out of pReturnedKeyMaterial */ + fieldID = (*env)->GetFieldID(env, jSsl3KeyMatOutClass, "pIVServer", "[B"); + if (fieldID == NULL) { return ckParam; } + jRMIvServer = (*env)->GetObjectField(env, jReturnedKeyMaterial, fieldID); + + /* populate java values */ + ckParam.ulMacSizeInBits = jLongToCKULong(jMacSizeInBits); + ckParam.ulKeySizeInBits = jLongToCKULong(jKeySizeInBits); + ckParam.ulIVSizeInBits = jLongToCKULong(jIVSizeInBits); + ckParam.bIsExport = jBooleanToCKBBool(jIsExport); + jByteArrayToCKByteArray(env, jRIClientRandom, &(ckParam.RandomInfo.pClientRandom), &(ckParam.RandomInfo.ulClientRandomLen)); + if ((*env)->ExceptionCheck(env)) { return ckParam; } + jByteArrayToCKByteArray(env, jRIServerRandom, &(ckParam.RandomInfo.pServerRandom), &(ckParam.RandomInfo.ulServerRandomLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.RandomInfo.pClientRandom); + return ckParam; + } /* allocate memory for pRetrunedKeyMaterial */ ckParam.pReturnedKeyMaterial = (CK_SSL3_KEY_MAT_OUT_PTR) malloc(sizeof(CK_SSL3_KEY_MAT_OUT)); + if (ckParam.pReturnedKeyMaterial == NULL) { + free(ckParam.RandomInfo.pClientRandom); + free(ckParam.RandomInfo.pServerRandom); + JNU_ThrowOutOfMemoryError(env, 0); + return ckParam; + } // the handles are output params only, no need to fetch them from Java ckParam.pReturnedKeyMaterial->hClientMacSecret = 0; @@ -562,17 +675,21 @@ CK_SSL3_KEY_MAT_PARAMS jSsl3KeyMatParamToCKSsl3KeyMatParam(JNIEnv *env, jobject ckParam.pReturnedKeyMaterial->hClientKey = 0; ckParam.pReturnedKeyMaterial->hServerKey = 0; - /* get pIVClient out of pReturnedKeyMaterial */ - fieldID = (*env)->GetFieldID(env, jSsl3KeyMatOutClass, "pIVClient", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jReturnedKeyMaterial, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pReturnedKeyMaterial->pIVClient), &ckTemp); - - /* get pIVServer out of pReturnedKeyMaterial */ - fieldID = (*env)->GetFieldID(env, jSsl3KeyMatOutClass, "pIVServer", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jReturnedKeyMaterial, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pReturnedKeyMaterial->pIVServer), &ckTemp); + jByteArrayToCKByteArray(env, jRMIvClient, &(ckParam.pReturnedKeyMaterial->pIVClient), &ckTemp); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.RandomInfo.pClientRandom); + free(ckParam.RandomInfo.pServerRandom); + free(ckParam.pReturnedKeyMaterial); + return ckParam; + } + jByteArrayToCKByteArray(env, jRMIvServer, &(ckParam.pReturnedKeyMaterial->pIVServer), &ckTemp); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.RandomInfo.pClientRandom); + free(ckParam.RandomInfo.pServerRandom); + free(ckParam.pReturnedKeyMaterial); + free(ckParam.pReturnedKeyMaterial->pIVClient); + return ckParam; + } return ckParam ; } @@ -811,7 +928,7 @@ void jMechanismParameterToCKMechanismParameter(JNIEnv *env, jobject jParam, CK_V *ckpParamPtr = jLongObjectToCKULongPtr(env, jParam); *ckpLength = sizeof(CK_ULONG); } else { - /* printf("slow path jMechanismParameterToCKMechanismParameter\n"); */ + TRACE0("\nSLOW PATH jMechanismParameterToCKMechanismParameter\n"); jMechanismParameterToCKMechanismParameterSlow(env, jParam, ckpParamPtr, ckpLength); } } @@ -819,40 +936,24 @@ void jMechanismParameterToCKMechanismParameter(JNIEnv *env, jobject jParam, CK_V void jMechanismParameterToCKMechanismParameterSlow(JNIEnv *env, jobject jParam, CK_VOID_PTR *ckpParamPtr, CK_ULONG *ckpLength) { /* get all Java mechanism parameter classes */ - jclass jVersionClass = (*env)->FindClass(env, CLASS_VERSION); - jclass jRsaPkcsOaepParamsClass = (*env)->FindClass(env, CLASS_RSA_PKCS_OAEP_PARAMS); - jclass jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS); - jclass jPkcs5Pbkd2ParamsClass = (*env)->FindClass(env, CLASS_PKCS5_PBKD2_PARAMS); - - jclass jRsaPkcsPssParamsClass = (*env)->FindClass(env, CLASS_RSA_PKCS_PSS_PARAMS); - jclass jEcdh1DeriveParamsClass = (*env)->FindClass(env, CLASS_ECDH1_DERIVE_PARAMS); - jclass jEcdh2DeriveParamsClass = (*env)->FindClass(env, CLASS_ECDH2_DERIVE_PARAMS); - jclass jX942Dh1DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH1_DERIVE_PARAMS); - jclass jX942Dh2DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH2_DERIVE_PARAMS); - - jclass jSsl3MasterKeyDeriveParamsClass = (*env)->FindClass(env, CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS); - jclass jSsl3KeyMatParamsClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_PARAMS); - jclass jTlsPrfParamsClass = (*env)->FindClass(env, CLASS_TLS_PRF_PARAMS); + jclass jVersionClass, jSsl3MasterKeyDeriveParamsClass, jSsl3KeyMatParamsClass; + jclass jTlsPrfParamsClass, jRsaPkcsOaepParamsClass, jPbeParamsClass; + jclass jPkcs5Pbkd2ParamsClass, jRsaPkcsPssParamsClass; + jclass jEcdh1DeriveParamsClass, jEcdh2DeriveParamsClass; + jclass jX942Dh1DeriveParamsClass, jX942Dh2DeriveParamsClass; + /* get all Java mechanism parameter classes */ TRACE0("\nDEBUG: jMechanismParameterToCKMechanismParameter"); - /* first check the most common cases */ -/* - if (jParam == NULL) { - *ckpParamPtr = NULL; - *ckpLength = 0; - } else if ((*env)->IsInstanceOf(env, jParam, jByteArrayClass)) { - jByteArrayToCKByteArray(env, jParam, (CK_BYTE_PTR *)ckpParamPtr, ckpLength); - } else if ((*env)->IsInstanceOf(env, jParam, jLongClass)) { - *ckpParamPtr = jLongObjectToCKULongPtr(env, jParam); - *ckpLength = sizeof(CK_ULONG); - } else if ((*env)->IsInstanceOf(env, jParam, jVersionClass)) { -*/ + /* most common cases, i.e. NULL/byte[]/long, are already handled by + * jMechanismParameterToCKMechanismParameter before calling this method. + */ + jVersionClass = (*env)->FindClass(env, CLASS_VERSION); + if (jVersionClass == NULL) { return; } if ((*env)->IsInstanceOf(env, jParam, jVersionClass)) { /* * CK_VERSION used by CKM_SSL3_PRE_MASTER_KEY_GEN */ - CK_VERSION_PTR ckpParam; /* convert jParameter to CKParameter */ @@ -861,191 +962,312 @@ void jMechanismParameterToCKMechanismParameterSlow(JNIEnv *env, jobject jParam, /* get length and pointer of parameter */ *ckpLength = sizeof(CK_VERSION); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jSsl3MasterKeyDeriveParamsClass)) { + jSsl3MasterKeyDeriveParamsClass = (*env)->FindClass(env, CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS); + if (jSsl3MasterKeyDeriveParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jSsl3MasterKeyDeriveParamsClass)) { /* * CK_SSL3_MASTER_KEY_DERIVE_PARAMS */ - CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR ckpParam; ckpParam = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR) malloc(sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jSsl3MasterKeyDeriveParamToCKSsl3MasterKeyDeriveParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jSsl3KeyMatParamsClass)) { + jSsl3KeyMatParamsClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_PARAMS); + if (jSsl3KeyMatParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jSsl3KeyMatParamsClass)) { /* * CK_SSL3_KEY_MAT_PARAMS */ - CK_SSL3_KEY_MAT_PARAMS_PTR ckpParam; ckpParam = (CK_SSL3_KEY_MAT_PARAMS_PTR) malloc(sizeof(CK_SSL3_KEY_MAT_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jSsl3KeyMatParamToCKSsl3KeyMatParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_SSL3_KEY_MAT_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jTlsPrfParamsClass)) { - // - // CK_TLS_PRF_PARAMS - // - + jTlsPrfParamsClass = (*env)->FindClass(env, CLASS_TLS_PRF_PARAMS); + if (jTlsPrfParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jTlsPrfParamsClass)) { + /* + * CK_TLS_PRF_PARAMS + */ CK_TLS_PRF_PARAMS_PTR ckpParam; ckpParam = (CK_TLS_PRF_PARAMS_PTR) malloc(sizeof(CK_TLS_PRF_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } - // convert jParameter to CKParameter + /* convert jParameter to CKParameter */ *ckpParam = jTlsPrfParamsToCKTlsPrfParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } - // get length and pointer of parameter + /* get length and pointer of parameter */ *ckpLength = sizeof(CK_TLS_PRF_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jRsaPkcsOaepParamsClass)) { + jRsaPkcsOaepParamsClass = (*env)->FindClass(env, CLASS_RSA_PKCS_OAEP_PARAMS); + if (jRsaPkcsOaepParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jRsaPkcsOaepParamsClass)) { /* * CK_RSA_PKCS_OAEP_PARAMS */ - CK_RSA_PKCS_OAEP_PARAMS_PTR ckpParam; ckpParam = (CK_RSA_PKCS_OAEP_PARAMS_PTR) malloc(sizeof(CK_RSA_PKCS_OAEP_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jRsaPkcsOaepParamToCKRsaPkcsOaepParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_RSA_PKCS_OAEP_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jPbeParamsClass)) { + jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS); + if (jPbeParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jPbeParamsClass)) { /* * CK_PBE_PARAMS */ - CK_PBE_PARAMS_PTR ckpParam; ckpParam = (CK_PBE_PARAMS_PTR) malloc(sizeof(CK_PBE_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jPbeParamToCKPbeParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_PBE_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jPkcs5Pbkd2ParamsClass)) { + jPkcs5Pbkd2ParamsClass = (*env)->FindClass(env, CLASS_PKCS5_PBKD2_PARAMS); + if (jPkcs5Pbkd2ParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jPkcs5Pbkd2ParamsClass)) { /* * CK_PKCS5_PBKD2_PARAMS */ - CK_PKCS5_PBKD2_PARAMS_PTR ckpParam; ckpParam = (CK_PKCS5_PBKD2_PARAMS_PTR) malloc(sizeof(CK_PKCS5_PBKD2_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jPkcs5Pbkd2ParamToCKPkcs5Pbkd2Param(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_PKCS5_PBKD2_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jRsaPkcsPssParamsClass)) { + jRsaPkcsPssParamsClass = (*env)->FindClass(env, CLASS_RSA_PKCS_PSS_PARAMS); + if (jRsaPkcsPssParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jRsaPkcsPssParamsClass)) { /* * CK_RSA_PKCS_PSS_PARAMS */ - CK_RSA_PKCS_PSS_PARAMS_PTR ckpParam; ckpParam = (CK_RSA_PKCS_PSS_PARAMS_PTR) malloc(sizeof(CK_RSA_PKCS_PSS_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jRsaPkcsPssParamToCKRsaPkcsPssParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_RSA_PKCS_PSS_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jEcdh1DeriveParamsClass)) { + jEcdh1DeriveParamsClass = (*env)->FindClass(env, CLASS_ECDH1_DERIVE_PARAMS); + if (jEcdh1DeriveParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jEcdh1DeriveParamsClass)) { /* * CK_ECDH1_DERIVE_PARAMS */ - CK_ECDH1_DERIVE_PARAMS_PTR ckpParam; ckpParam = (CK_ECDH1_DERIVE_PARAMS_PTR) malloc(sizeof(CK_ECDH1_DERIVE_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jEcdh1DeriveParamToCKEcdh1DeriveParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_ECDH1_DERIVE_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jEcdh2DeriveParamsClass)) { + jEcdh2DeriveParamsClass = (*env)->FindClass(env, CLASS_ECDH2_DERIVE_PARAMS); + if (jEcdh2DeriveParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jEcdh2DeriveParamsClass)) { /* * CK_ECDH2_DERIVE_PARAMS */ - CK_ECDH2_DERIVE_PARAMS_PTR ckpParam; ckpParam = (CK_ECDH2_DERIVE_PARAMS_PTR) malloc(sizeof(CK_ECDH2_DERIVE_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jEcdh2DeriveParamToCKEcdh2DeriveParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_ECDH2_DERIVE_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jX942Dh1DeriveParamsClass)) { + jX942Dh1DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH1_DERIVE_PARAMS); + if (jX942Dh1DeriveParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jX942Dh1DeriveParamsClass)) { /* * CK_X9_42_DH1_DERIVE_PARAMS */ - CK_X9_42_DH1_DERIVE_PARAMS_PTR ckpParam; ckpParam = (CK_X9_42_DH1_DERIVE_PARAMS_PTR) malloc(sizeof(CK_X9_42_DH1_DERIVE_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jX942Dh1DeriveParamToCKX942Dh1DeriveParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_X9_42_DH1_DERIVE_PARAMS); *ckpParamPtr = ckpParam; + return; + } - } else if ((*env)->IsInstanceOf(env, jParam, jX942Dh2DeriveParamsClass)) { + jX942Dh2DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH2_DERIVE_PARAMS); + if (jX942Dh2DeriveParamsClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jParam, jX942Dh2DeriveParamsClass)) { /* * CK_X9_42_DH2_DERIVE_PARAMS */ - CK_X9_42_DH2_DERIVE_PARAMS_PTR ckpParam; ckpParam = (CK_X9_42_DH2_DERIVE_PARAMS_PTR) malloc(sizeof(CK_X9_42_DH2_DERIVE_PARAMS)); + if (ckpParam == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } /* convert jParameter to CKParameter */ *ckpParam = jX942Dh2DeriveParamToCKX942Dh2DeriveParam(env, jParam); + if ((*env)->ExceptionCheck(env)) { + free(ckpParam); + return; + } /* get length and pointer of parameter */ *ckpLength = sizeof(CK_X9_42_DH2_DERIVE_PARAMS); *ckpParamPtr = ckpParam; - - } else { - /* if everything faild up to here */ - /* try if the parameter is a primitive Java type */ - jObjectToPrimitiveCKObjectPtrPtr(env, jParam, ckpParamPtr, ckpLength); - /* *ckpParamPtr = jObjectToCKVoidPtr(jParam); */ - /* *ckpLength = 1; */ + return; } + /* if everything faild up to here */ + /* try if the parameter is a primitive Java type */ + jObjectToPrimitiveCKObjectPtrPtr(env, jParam, ckpParamPtr, ckpLength); + /* *ckpParamPtr = jObjectToCKVoidPtr(jParam); */ + /* *ckpLength = 1; */ + TRACE0("FINISHED\n"); } @@ -1061,36 +1283,41 @@ void jMechanismParameterToCKMechanismParameterSlow(JNIEnv *env, jobject jParam, */ CK_RSA_PKCS_OAEP_PARAMS jRsaPkcsOaepParamToCKRsaPkcsOaepParam(JNIEnv *env, jobject jParam) { - jclass jRsaPkcsOaepParamsClass = (*env)->FindClass(env, CLASS_RSA_PKCS_OAEP_PARAMS); + jclass jRsaPkcsOaepParamsClass; CK_RSA_PKCS_OAEP_PARAMS ckParam; jfieldID fieldID; - jlong jLong; - jobject jObject; + jlong jHashAlg, jMgf, jSource; + jobject jSourceData; CK_BYTE_PTR ckpByte; /* get hashAlg */ + jRsaPkcsOaepParamsClass = (*env)->FindClass(env, CLASS_RSA_PKCS_OAEP_PARAMS); + if (jRsaPkcsOaepParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jRsaPkcsOaepParamsClass, "hashAlg", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.hashAlg = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jHashAlg = (*env)->GetLongField(env, jParam, fieldID); /* get mgf */ fieldID = (*env)->GetFieldID(env, jRsaPkcsOaepParamsClass, "mgf", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.mgf = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jMgf = (*env)->GetLongField(env, jParam, fieldID); /* get source */ fieldID = (*env)->GetFieldID(env, jRsaPkcsOaepParamsClass, "source", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.source = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jSource = (*env)->GetLongField(env, jParam, fieldID); /* get sourceData and sourceDataLength */ fieldID = (*env)->GetFieldID(env, jRsaPkcsOaepParamsClass, "pSourceData", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &ckpByte, &(ckParam.ulSourceDataLen)); + if (fieldID == NULL) { return ckParam; } + jSourceData = (*env)->GetObjectField(env, jParam, fieldID); + + /* populate java values */ + ckParam.hashAlg = jLongToCKULong(jHashAlg); + ckParam.mgf = jLongToCKULong(jMgf); + ckParam.source = jLongToCKULong(jSource); + jByteArrayToCKByteArray(env, jSourceData, & ckpByte, &(ckParam.ulSourceDataLen)); + if ((*env)->ExceptionCheck(env)) { return ckParam; } ckParam.pSourceData = (CK_VOID_PTR) ckpByte; return ckParam ; @@ -1105,36 +1332,50 @@ CK_RSA_PKCS_OAEP_PARAMS jRsaPkcsOaepParamToCKRsaPkcsOaepParam(JNIEnv *env, jobje */ CK_PBE_PARAMS jPbeParamToCKPbeParam(JNIEnv *env, jobject jParam) { - jclass jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS); + jclass jPbeParamsClass; CK_PBE_PARAMS ckParam; jfieldID fieldID; - jlong jLong; - jobject jObject; + jlong jIteration; + jobject jInitVector, jPassword, jSalt; CK_ULONG ckTemp; /* get pInitVector */ + jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS); + if (jPbeParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pInitVector", "[C"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jCharArrayToCKCharArray(env, jObject, &(ckParam.pInitVector), &ckTemp); + if (fieldID == NULL) { return ckParam; } + jInitVector = (*env)->GetObjectField(env, jParam, fieldID); /* get pPassword and ulPasswordLength */ fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pPassword", "[C"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jCharArrayToCKCharArray(env, jObject, &(ckParam.pPassword), &(ckParam.ulPasswordLen)); + if (fieldID == NULL) { return ckParam; } + jPassword = (*env)->GetObjectField(env, jParam, fieldID); /* get pSalt and ulSaltLength */ fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pSalt", "[C"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jCharArrayToCKCharArray(env, jObject, &(ckParam.pSalt), &(ckParam.ulSaltLen)); + if (fieldID == NULL) { return ckParam; } + jSalt = (*env)->GetObjectField(env, jParam, fieldID); /* get ulIteration */ fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "ulIteration", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.ulIteration = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jIteration = (*env)->GetLongField(env, jParam, fieldID); + + /* populate java values */ + ckParam.ulIteration = jLongToCKULong(jIteration); + jCharArrayToCKCharArray(env, jInitVector, &(ckParam.pInitVector), &ckTemp); + if ((*env)->ExceptionCheck(env)) { return ckParam; } + jCharArrayToCKCharArray(env, jPassword, &(ckParam.pPassword), &(ckParam.ulPasswordLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pInitVector); + return ckParam; + } + jCharArrayToCKCharArray(env, jSalt, &(ckParam.pSalt), &(ckParam.ulSaltLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pInitVector); + free(ckParam.pPassword); + return ckParam; + } return ckParam ; } @@ -1147,8 +1388,7 @@ CK_PBE_PARAMS jPbeParamToCKPbeParam(JNIEnv *env, jobject jParam) */ void copyBackPBEInitializationVector(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMechanism) { - jclass jMechanismClass= (*env)->FindClass(env, CLASS_MECHANISM); - jclass jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS); + jclass jMechanismClass, jPbeParamsClass; CK_PBE_PARAMS *ckParam; jfieldID fieldID; CK_MECHANISM_TYPE ckMechanismType; @@ -1161,8 +1401,10 @@ void copyBackPBEInitializationVector(JNIEnv *env, CK_MECHANISM *ckMechanism, job jchar* jInitVectorChars; /* get mechanism */ + jMechanismClass = (*env)->FindClass(env, CLASS_MECHANISM); + if (jMechanismClass == NULL) { return; } fieldID = (*env)->GetFieldID(env, jMechanismClass, "mechanism", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jMechanismType = (*env)->GetLongField(env, jMechanism, fieldID); ckMechanismType = jLongToCKULong(jMechanismType); if (ckMechanismType != ckMechanism->mechanism) { @@ -1170,21 +1412,25 @@ void copyBackPBEInitializationVector(JNIEnv *env, CK_MECHANISM *ckMechanism, job return; } + jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS); + if (jPbeParamsClass == NULL) { return; } ckParam = (CK_PBE_PARAMS *) ckMechanism->pParameter; if (ckParam != NULL_PTR) { initVector = ckParam->pInitVector; if (initVector != NULL_PTR) { /* get pParameter */ fieldID = (*env)->GetFieldID(env, jMechanismClass, "pParameter", "Ljava/lang/Object;"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jParameter = (*env)->GetObjectField(env, jMechanism, fieldID); fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pInitVektor", "[C"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jInitVector = (*env)->GetObjectField(env, jParameter, fieldID); if (jInitVector != NULL) { jInitVectorLength = (*env)->GetArrayLength(env, jInitVector); jInitVectorChars = (*env)->GetCharArrayElements(env, jInitVector, NULL); + if (jInitVectorChars == NULL) { return; } + /* copy the chars to the Java buffer */ for (i=0; i < jInitVectorLength; i++) { jInitVectorChars[i] = ckCharToJChar(initVector[i]); @@ -1205,41 +1451,50 @@ void copyBackPBEInitializationVector(JNIEnv *env, CK_MECHANISM *ckMechanism, job */ CK_PKCS5_PBKD2_PARAMS jPkcs5Pbkd2ParamToCKPkcs5Pbkd2Param(JNIEnv *env, jobject jParam) { - jclass jPkcs5Pbkd2ParamsClass = (*env)->FindClass(env, CLASS_PKCS5_PBKD2_PARAMS); + jclass jPkcs5Pbkd2ParamsClass; CK_PKCS5_PBKD2_PARAMS ckParam; jfieldID fieldID; - jlong jLong; - jobject jObject; + jlong jSaltSource, jIteration, jPrf; + jobject jSaltSourceData, jPrfData; /* get saltSource */ + jPkcs5Pbkd2ParamsClass = (*env)->FindClass(env, CLASS_PKCS5_PBKD2_PARAMS); + if (jPkcs5Pbkd2ParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "saltSource", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.saltSource = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jSaltSource = (*env)->GetLongField(env, jParam, fieldID); /* get pSaltSourceData */ fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "pSaltSourceData", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, (CK_BYTE_PTR *) &(ckParam.pSaltSourceData), &(ckParam.ulSaltSourceDataLen)); + if (fieldID == NULL) { return ckParam; } + jSaltSourceData = (*env)->GetObjectField(env, jParam, fieldID); /* get iterations */ fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "iterations", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.iterations = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jIteration = (*env)->GetLongField(env, jParam, fieldID); /* get prf */ fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "prf", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.prf = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jPrf = (*env)->GetLongField(env, jParam, fieldID); /* get pPrfData and ulPrfDataLength in byte */ fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "pPrfData", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, (CK_BYTE_PTR *) &(ckParam.pPrfData), &(ckParam.ulPrfDataLen)); + if (fieldID == NULL) { return ckParam; } + jPrfData = (*env)->GetObjectField(env, jParam, fieldID); + + /* populate java values */ + ckParam.saltSource = jLongToCKULong(jSaltSource); + jByteArrayToCKByteArray(env, jSaltSourceData, (CK_BYTE_PTR *) &(ckParam.pSaltSourceData), &(ckParam.ulSaltSourceDataLen)); + if ((*env)->ExceptionCheck(env)) { return ckParam; } + ckParam.iterations = jLongToCKULong(jIteration); + ckParam.prf = jLongToCKULong(jPrf); + jByteArrayToCKByteArray(env, jPrfData, (CK_BYTE_PTR *) &(ckParam.pPrfData), &(ckParam.ulPrfDataLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pSaltSourceData); + return ckParam; + } return ckParam ; } @@ -1253,28 +1508,32 @@ CK_PKCS5_PBKD2_PARAMS jPkcs5Pbkd2ParamToCKPkcs5Pbkd2Param(JNIEnv *env, jobject j */ CK_RSA_PKCS_PSS_PARAMS jRsaPkcsPssParamToCKRsaPkcsPssParam(JNIEnv *env, jobject jParam) { - jclass jRsaPkcsPssParamsClass = (*env)->FindClass(env, CLASS_RSA_PKCS_PSS_PARAMS); + jclass jRsaPkcsPssParamsClass; CK_RSA_PKCS_PSS_PARAMS ckParam; jfieldID fieldID; - jlong jLong; + jlong jHashAlg, jMgf, jSLen; /* get hashAlg */ + jRsaPkcsPssParamsClass = (*env)->FindClass(env, CLASS_RSA_PKCS_PSS_PARAMS); + if (jRsaPkcsPssParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jRsaPkcsPssParamsClass, "hashAlg", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.hashAlg = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jHashAlg = (*env)->GetLongField(env, jParam, fieldID); /* get mgf */ fieldID = (*env)->GetFieldID(env, jRsaPkcsPssParamsClass, "mgf", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.mgf = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jMgf = (*env)->GetLongField(env, jParam, fieldID); /* get sLen */ fieldID = (*env)->GetFieldID(env, jRsaPkcsPssParamsClass, "sLen", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.sLen = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jSLen = (*env)->GetLongField(env, jParam, fieldID); + + /* populate java values */ + ckParam.hashAlg = jLongToCKULong(jHashAlg); + ckParam.mgf = jLongToCKULong(jMgf); + ckParam.sLen = jLongToCKULong(jSLen); return ckParam ; } @@ -1288,29 +1547,39 @@ CK_RSA_PKCS_PSS_PARAMS jRsaPkcsPssParamToCKRsaPkcsPssParam(JNIEnv *env, jobject */ CK_ECDH1_DERIVE_PARAMS jEcdh1DeriveParamToCKEcdh1DeriveParam(JNIEnv *env, jobject jParam) { - jclass jEcdh1DeriveParamsClass = (*env)->FindClass(env, CLASS_ECDH1_DERIVE_PARAMS); + jclass jEcdh1DeriveParamsClass; CK_ECDH1_DERIVE_PARAMS ckParam; jfieldID fieldID; jlong jLong; - jobject jObject; + jobject jSharedData, jPublicData; /* get kdf */ + jEcdh1DeriveParamsClass = (*env)->FindClass(env, CLASS_ECDH1_DERIVE_PARAMS); + if (jEcdh1DeriveParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jEcdh1DeriveParamsClass, "kdf", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return ckParam; } jLong = (*env)->GetLongField(env, jParam, fieldID); ckParam.kdf = jLongToCKULong(jLong); /* get pSharedData and ulSharedDataLen */ fieldID = (*env)->GetFieldID(env, jEcdh1DeriveParamsClass, "pSharedData", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pSharedData), &(ckParam.ulSharedDataLen)); + if (fieldID == NULL) { return ckParam; } + jSharedData = (*env)->GetObjectField(env, jParam, fieldID); /* get pPublicData and ulPublicDataLen */ fieldID = (*env)->GetFieldID(env, jEcdh1DeriveParamsClass, "pPublicData", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pPublicData), &(ckParam.ulPublicDataLen)); + if (fieldID == NULL) { return ckParam; } + jPublicData = (*env)->GetObjectField(env, jParam, fieldID); + + /* populate java values */ + ckParam.kdf = jLongToCKULong(jLong); + jByteArrayToCKByteArray(env, jSharedData, &(ckParam.pSharedData), &(ckParam.ulSharedDataLen)); + if ((*env)->ExceptionCheck(env)) { return ckParam; } + jByteArrayToCKByteArray(env, jPublicData, &(ckParam.pPublicData), &(ckParam.ulPublicDataLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pSharedData); + return ckParam; + } return ckParam ; } @@ -1324,48 +1593,61 @@ CK_ECDH1_DERIVE_PARAMS jEcdh1DeriveParamToCKEcdh1DeriveParam(JNIEnv *env, jobjec */ CK_ECDH2_DERIVE_PARAMS jEcdh2DeriveParamToCKEcdh2DeriveParam(JNIEnv *env, jobject jParam) { - jclass jEcdh2DeriveParamsClass = (*env)->FindClass(env, CLASS_ECDH2_DERIVE_PARAMS); + jclass jEcdh2DeriveParamsClass; CK_ECDH2_DERIVE_PARAMS ckParam; jfieldID fieldID; - jlong jLong; - jobject jObject; + jlong jKdf, jPrivateDataLen, jPrivateData; + jobject jSharedData, jPublicData, jPublicData2; /* get kdf */ + jEcdh2DeriveParamsClass = (*env)->FindClass(env, CLASS_ECDH2_DERIVE_PARAMS); + if (jEcdh2DeriveParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jEcdh2DeriveParamsClass, "kdf", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.kdf = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jKdf = (*env)->GetLongField(env, jParam, fieldID); /* get pSharedData and ulSharedDataLen */ fieldID = (*env)->GetFieldID(env, jEcdh2DeriveParamsClass, "pSharedData", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pSharedData), &(ckParam.ulSharedDataLen)); + if (fieldID == NULL) { return ckParam; } + jSharedData = (*env)->GetObjectField(env, jParam, fieldID); /* get pPublicData and ulPublicDataLen */ fieldID = (*env)->GetFieldID(env, jEcdh2DeriveParamsClass, "pPublicData", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pPublicData), &(ckParam.ulPublicDataLen)); + if (fieldID == NULL) { return ckParam; } + jPublicData = (*env)->GetObjectField(env, jParam, fieldID); /* get ulPrivateDataLen */ fieldID = (*env)->GetFieldID(env, jEcdh2DeriveParamsClass, "ulPrivateDataLen", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.ulPrivateDataLen = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jPrivateDataLen = (*env)->GetLongField(env, jParam, fieldID); /* get hPrivateData */ fieldID = (*env)->GetFieldID(env, jEcdh2DeriveParamsClass, "hPrivateData", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.hPrivateData = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jPrivateData = (*env)->GetLongField(env, jParam, fieldID); /* get pPublicData2 and ulPublicDataLen2 */ fieldID = (*env)->GetFieldID(env, jEcdh2DeriveParamsClass, "pPublicData2", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pPublicData2), &(ckParam.ulPublicDataLen2)); + if (fieldID == NULL) { return ckParam; } + jPublicData2 = (*env)->GetObjectField(env, jParam, fieldID); + /* populate java values */ + ckParam.kdf = jLongToCKULong(jKdf); + jByteArrayToCKByteArray(env, jSharedData, &(ckParam.pSharedData), &(ckParam.ulSharedDataLen)); + if ((*env)->ExceptionCheck(env)) { return ckParam; } + jByteArrayToCKByteArray(env, jPublicData, &(ckParam.pPublicData), &(ckParam.ulPublicDataLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pSharedData); + return ckParam; + } + ckParam.ulPrivateDataLen = jLongToCKULong(jPrivateDataLen); + ckParam.hPrivateData = jLongToCKULong(jPrivateData); + jByteArrayToCKByteArray(env, jPublicData2, &(ckParam.pPublicData2), &(ckParam.ulPublicDataLen2)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pSharedData); + free(ckParam.pPublicData); + return ckParam; + } return ckParam ; } @@ -1378,29 +1660,38 @@ CK_ECDH2_DERIVE_PARAMS jEcdh2DeriveParamToCKEcdh2DeriveParam(JNIEnv *env, jobjec */ CK_X9_42_DH1_DERIVE_PARAMS jX942Dh1DeriveParamToCKX942Dh1DeriveParam(JNIEnv *env, jobject jParam) { - jclass jX942Dh1DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH1_DERIVE_PARAMS); + jclass jX942Dh1DeriveParamsClass; CK_X9_42_DH1_DERIVE_PARAMS ckParam; jfieldID fieldID; - jlong jLong; - jobject jObject; + jlong jKdf; + jobject jOtherInfo, jPublicData; /* get kdf */ + jX942Dh1DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH1_DERIVE_PARAMS); + if (jX942Dh1DeriveParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jX942Dh1DeriveParamsClass, "kdf", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.kdf = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jKdf = (*env)->GetLongField(env, jParam, fieldID); /* get pOtherInfo and ulOtherInfoLen */ fieldID = (*env)->GetFieldID(env, jX942Dh1DeriveParamsClass, "pOtherInfo", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pOtherInfo), &(ckParam.ulOtherInfoLen)); + if (fieldID == NULL) { return ckParam; } + jOtherInfo = (*env)->GetObjectField(env, jParam, fieldID); /* get pPublicData and ulPublicDataLen */ fieldID = (*env)->GetFieldID(env, jX942Dh1DeriveParamsClass, "pPublicData", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pPublicData), &(ckParam.ulPublicDataLen)); + if (fieldID == NULL) { return ckParam; } + jPublicData = (*env)->GetObjectField(env, jParam, fieldID); + + /* populate java values */ + ckParam.kdf = jLongToCKULong(jKdf); + jByteArrayToCKByteArray(env, jOtherInfo, &(ckParam.pOtherInfo), &(ckParam.ulOtherInfoLen)); + if ((*env)->ExceptionCheck(env)) { return ckParam; } + jByteArrayToCKByteArray(env, jPublicData, &(ckParam.pPublicData), &(ckParam.ulPublicDataLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pOtherInfo); + return ckParam; + } return ckParam ; } @@ -1414,47 +1705,61 @@ CK_X9_42_DH1_DERIVE_PARAMS jX942Dh1DeriveParamToCKX942Dh1DeriveParam(JNIEnv *env */ CK_X9_42_DH2_DERIVE_PARAMS jX942Dh2DeriveParamToCKX942Dh2DeriveParam(JNIEnv *env, jobject jParam) { - jclass jX942Dh2DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH2_DERIVE_PARAMS); + jclass jX942Dh2DeriveParamsClass; CK_X9_42_DH2_DERIVE_PARAMS ckParam; jfieldID fieldID; - jlong jLong; - jobject jObject; + jlong jKdf, jPrivateDataLen, jPrivateData; + jobject jOtherInfo, jPublicData, jPublicData2; /* get kdf */ + jX942Dh2DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH2_DERIVE_PARAMS); + if (jX942Dh2DeriveParamsClass == NULL) { return ckParam; } fieldID = (*env)->GetFieldID(env, jX942Dh2DeriveParamsClass, "kdf", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.kdf = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jKdf = (*env)->GetLongField(env, jParam, fieldID); /* get pOtherInfo and ulOtherInfoLen */ fieldID = (*env)->GetFieldID(env, jX942Dh2DeriveParamsClass, "pOtherInfo", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pOtherInfo), &(ckParam.ulOtherInfoLen)); + if (fieldID == NULL) { return ckParam; } + jOtherInfo = (*env)->GetObjectField(env, jParam, fieldID); /* get pPublicData and ulPublicDataLen */ fieldID = (*env)->GetFieldID(env, jX942Dh2DeriveParamsClass, "pPublicData", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pPublicData), &(ckParam.ulPublicDataLen)); + if (fieldID == NULL) { return ckParam; } + jPublicData = (*env)->GetObjectField(env, jParam, fieldID); /* get ulPrivateDataLen */ fieldID = (*env)->GetFieldID(env, jX942Dh2DeriveParamsClass, "ulPrivateDataLen", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.ulPrivateDataLen = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jPrivateDataLen = (*env)->GetLongField(env, jParam, fieldID); /* get hPrivateData */ fieldID = (*env)->GetFieldID(env, jX942Dh2DeriveParamsClass, "hPrivateData", "J"); - assert(fieldID != 0); - jLong = (*env)->GetLongField(env, jParam, fieldID); - ckParam.hPrivateData = jLongToCKULong(jLong); + if (fieldID == NULL) { return ckParam; } + jPrivateData = (*env)->GetLongField(env, jParam, fieldID); /* get pPublicData2 and ulPublicDataLen2 */ fieldID = (*env)->GetFieldID(env, jX942Dh2DeriveParamsClass, "pPublicData2", "[B"); - assert(fieldID != 0); - jObject = (*env)->GetObjectField(env, jParam, fieldID); - jByteArrayToCKByteArray(env, jObject, &(ckParam.pPublicData2), &(ckParam.ulPublicDataLen2)); + if (fieldID == NULL) { return ckParam; } + jPublicData2 = (*env)->GetObjectField(env, jParam, fieldID); + + /* populate java values */ + ckParam.kdf = jLongToCKULong(jKdf); + jByteArrayToCKByteArray(env, jOtherInfo, &(ckParam.pOtherInfo), &(ckParam.ulOtherInfoLen)); + if ((*env)->ExceptionCheck(env)) { return ckParam; } + jByteArrayToCKByteArray(env, jPublicData, &(ckParam.pPublicData), &(ckParam.ulPublicDataLen)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pOtherInfo); + return ckParam; + } + ckParam.ulPrivateDataLen = jLongToCKULong(jPrivateDataLen); + ckParam.hPrivateData = jLongToCKULong(jPrivateData); + jByteArrayToCKByteArray(env, jPublicData2, &(ckParam.pPublicData2), &(ckParam.ulPublicDataLen2)); + if ((*env)->ExceptionCheck(env)) { + free(ckParam.pOtherInfo); + free(ckParam.pPublicData); + return ckParam; + } return ckParam ; } diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_crypt.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_crypt.c index bbcbe90e317..63366d43580 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_crypt.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_crypt.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -81,6 +81,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptInit ckSessionHandle = jLongToCKULong(jSessionHandle); ckKeyHandle = jLongToCKULong(jKeyHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return; } rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle, &ckMechanism, ckKeyHandle); @@ -126,14 +127,29 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1Encrypt if (jInLen > MAX_STACK_BUFFER_LEN) { inBufP = (CK_BYTE_PTR)malloc((size_t)jInLen); + if (inBufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } else { inBufP = IBUF; } (*env)->GetByteArrayRegion(env, jIn, jInOfs, jInLen, (jbyte *)inBufP); + if ((*env)->ExceptionCheck(env)) { + if (inBufP != IBUF) { free(inBufP); } + return 0; + } ckEncryptedPartLen = jOutLen; if (jOutLen > MAX_STACK_BUFFER_LEN) { outBufP = (CK_BYTE_PTR)malloc((size_t)jOutLen); + if (outBufP == NULL) { + if (inBufP != IBUF) { + free(inBufP); + } + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } else { outBufP = OBUF; } @@ -193,10 +209,18 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptUpdate } else { if (jInLen > MAX_STACK_BUFFER_LEN) { inBufP = (CK_BYTE_PTR)malloc((size_t)jInLen); + if (inBufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } else { inBufP = IBUF; } (*env)->GetByteArrayRegion(env, jIn, jInOfs, jInLen, (jbyte *)inBufP); + if ((*env)->ExceptionCheck(env)) { + if (directIn == 0 && inBufP != IBUF) { free(inBufP); } + return 0; + } } ckEncryptedPartLen = jOutLen; @@ -205,6 +229,13 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptUpdate } else { if (jOutLen > MAX_STACK_BUFFER_LEN) { outBufP = (CK_BYTE_PTR)malloc((size_t)jOutLen); + if (outBufP == NULL) { + if (directIn == 0 && inBufP != IBUF) { + free(inBufP); + } + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } else { outBufP = OBUF; } @@ -317,6 +348,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptInit ckSessionHandle = jLongToCKULong(jSessionHandle); ckKeyHandle = jLongToCKULong(jKeyHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return; } rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, &ckMechanism, ckKeyHandle); @@ -362,14 +394,29 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1Decrypt if (jInLen > MAX_STACK_BUFFER_LEN) { inBufP = (CK_BYTE_PTR)malloc((size_t)jInLen); + if (inBufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } else { inBufP = IBUF; } (*env)->GetByteArrayRegion(env, jIn, jInOfs, jInLen, (jbyte *)inBufP); + if ((*env)->ExceptionCheck(env)) { + if (inBufP != IBUF) { free(inBufP); } + return 0; + } ckPartLen = jOutLen; if (jOutLen > MAX_STACK_BUFFER_LEN) { outBufP = (CK_BYTE_PTR)malloc((size_t)jOutLen); + if (outBufP == NULL) { + if (inBufP != IBUF) { + free(inBufP); + } + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } else { outBufP = OBUF; } @@ -429,10 +476,18 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptUpdate } else { if (jInLen > MAX_STACK_BUFFER_LEN) { inBufP = (CK_BYTE_PTR)malloc((size_t)jInLen); + if (inBufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } else { inBufP = IBUF; } (*env)->GetByteArrayRegion(env, jIn, jInOfs, jInLen, (jbyte *)inBufP); + if ((*env)->ExceptionCheck(env)) { + if (directIn == 0 && inBufP != IBUF) { free(inBufP); } + return 0; + } } ckDecryptedPartLen = jOutLen; @@ -441,6 +496,13 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptUpdate } else { if (jOutLen > MAX_STACK_BUFFER_LEN) { outBufP = (CK_BYTE_PTR)malloc((size_t)jOutLen); + if (outBufP == NULL) { + if (directIn == 0 && inBufP != IBUF) { + free(inBufP); + } + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } else { outBufP = OBUF; } diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_digest.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_digest.c index 978479bb311..8ff5ecc1b02 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_digest.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_digest.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -75,6 +75,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DigestInit ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return; } rv = (*ckpFunctions->C_DigestInit)(ckSessionHandle, &ckMechanism); @@ -82,7 +83,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DigestInit free(ckMechanism.pParameter); } - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -114,6 +115,7 @@ JNIEXPORT jint JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DigestSingle ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return 0; } rv = (*ckpFunctions->C_DigestInit)(ckSessionHandle, &ckMechanism); @@ -121,29 +123,32 @@ JNIEXPORT jint JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DigestSingle free(ckMechanism.pParameter); } - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0; } if (jInLen <= MAX_STACK_BUFFER_LEN) { bufP = BUF; } else { /* always use single part op, even for large data */ - bufP = (CK_BYTE_PTR)malloc((size_t)jInLen); + bufP = (CK_BYTE_PTR) malloc((size_t)jInLen); + if (bufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } (*env)->GetByteArrayRegion(env, jIn, jInOfs, jInLen, (jbyte *)bufP); - rv = (*ckpFunctions->C_Digest)(ckSessionHandle, bufP, jInLen, DIGESTBUF, &ckDigestLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { - if (bufP != BUF) { - free(bufP); - } + if ((*env)->ExceptionCheck(env)) { + if (bufP != BUF) { free(bufP); } return 0; } - (*env)->SetByteArrayRegion(env, jDigest, jDigestOfs, ckDigestLength, (jbyte *)DIGESTBUF); - - if (bufP != BUF) { - free(bufP); + rv = (*ckpFunctions->C_Digest)(ckSessionHandle, bufP, jInLen, DIGESTBUF, &ckDigestLength); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + (*env)->SetByteArrayRegion(env, jDigest, jDigestOfs, ckDigestLength, (jbyte *)DIGESTBUF); } + + if (bufP != BUF) { free(bufP); } + return ckDigestLength; } #endif @@ -183,17 +188,23 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DigestUpdate bufP = BUF; } else { bufLen = min(MAX_HEAP_BUFFER_LEN, jInLen); - bufP = (CK_BYTE_PTR)malloc((size_t)bufLen); + bufP = (CK_BYTE_PTR) malloc((size_t)bufLen); + if (bufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } } while (jInLen > 0) { jsize chunkLen = min(bufLen, jInLen); (*env)->GetByteArrayRegion(env, jIn, jInOfs, chunkLen, (jbyte *)bufP); + if ((*env)->ExceptionCheck(env)) { + if (bufP != BUF) { free(bufP); } + return; + } rv = (*ckpFunctions->C_DigestUpdate)(ckSessionHandle, bufP, chunkLen); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { - if (bufP != BUF) { - free(bufP); - } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + if (bufP != BUF) { free(bufP); } return; } jInOfs += chunkLen; @@ -229,7 +240,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DigestKey ckKeyHandle = jLongToCKULong(jKeyHandle); rv = (*ckpFunctions->C_DigestKey)(ckSessionHandle, ckKeyHandle); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -257,10 +268,9 @@ JNIEXPORT jint JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DigestFinal ckSessionHandle = jLongToCKULong(jSessionHandle); rv = (*ckpFunctions->C_DigestFinal)(ckSessionHandle, BUF, &ckDigestLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0 ; } - - (*env)->SetByteArrayRegion(env, jDigest, jDigestOfs, ckDigestLength, (jbyte *)BUF); - + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + (*env)->SetByteArrayRegion(env, jDigest, jDigestOfs, ckDigestLength, (jbyte *)BUF); + } return ckDigestLength; } #endif @@ -288,12 +298,13 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SeedRandom ckSessionHandle = jLongToCKULong(jSessionHandle); jByteArrayToCKByteArray(env, jSeed, &ckpSeed, &ckSeedLength); + if ((*env)->ExceptionCheck(env)) { return; } rv = (*ckpFunctions->C_SeedRandom)(ckSessionHandle, ckpSeed, ckSeedLength); free(ckpSeed); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -322,6 +333,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GenerateRandom jRandomBufferLength = (*env)->GetArrayLength(env, jRandomData); jRandomBuffer = (*env)->GetByteArrayElements(env, jRandomData, NULL); + if (jRandomBuffer == NULL) { return; } rv = (*ckpFunctions->C_GenerateRandom)(ckSessionHandle, (CK_BYTE_PTR) jRandomBuffer, @@ -330,6 +342,6 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GenerateRandom /* copy back generated bytes */ (*env)->ReleaseByteArrayElements(env, jRandomData, jRandomBuffer, 0); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_dual.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_dual.c index ead1fe42989..24bae5e1626 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_dual.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_dual.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -73,7 +73,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DigestEn CK_SESSION_HANDLE ckSessionHandle; CK_BYTE_PTR ckpPart = NULL_PTR, ckpEncryptedPart; CK_ULONG ckPartLength, ckEncryptedPartLength = 0; - jbyteArray jEncryptedPart; + jbyteArray jEncryptedPart = NULL; CK_RV rv; CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); @@ -81,20 +81,28 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DigestEn ckSessionHandle = jLongToCKULong(jSessionHandle); jByteArrayToCKByteArray(env, jPart, &ckpPart, &ckPartLength); + if ((*env)->ExceptionCheck(env)) { return NULL; } rv = (*ckpFunctions->C_DigestEncryptUpdate)(ckSessionHandle, ckpPart, ckPartLength, NULL_PTR, &ckEncryptedPartLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + free(ckpPart); + return NULL; + } ckpEncryptedPart = (CK_BYTE_PTR) malloc(ckEncryptedPartLength * sizeof(CK_BYTE)); + if (ckpEncryptedPart == NULL) { + free(ckpPart); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_DigestEncryptUpdate)(ckSessionHandle, ckpPart, ckPartLength, ckpEncryptedPart, &ckEncryptedPartLength); - - jEncryptedPart = ckByteArrayToJByteArray(env, ckpEncryptedPart, ckEncryptedPartLength); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jEncryptedPart = ckByteArrayToJByteArray(env, ckpEncryptedPart, ckEncryptedPartLength); + } free(ckpPart); free(ckpEncryptedPart); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - return jEncryptedPart ; } #endif @@ -117,7 +125,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptD CK_SESSION_HANDLE ckSessionHandle; CK_BYTE_PTR ckpPart, ckpEncryptedPart = NULL_PTR; CK_ULONG ckPartLength = 0, ckEncryptedPartLength; - jbyteArray jPart; + jbyteArray jPart = NULL; CK_RV rv; CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); @@ -125,19 +133,27 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptD ckSessionHandle = jLongToCKULong(jSessionHandle); jByteArrayToCKByteArray(env, jEncryptedPart, &ckpEncryptedPart, &ckEncryptedPartLength); + if ((*env)->ExceptionCheck(env)) { return NULL; } rv = (*ckpFunctions->C_DecryptDigestUpdate)(ckSessionHandle, ckpEncryptedPart, ckEncryptedPartLength, NULL_PTR, &ckPartLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + free(ckpEncryptedPart); + return NULL; + } ckpPart = (CK_BYTE_PTR) malloc(ckPartLength * sizeof(CK_BYTE)); + if (ckpPart == NULL) { + free(ckpEncryptedPart); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_DecryptDigestUpdate)(ckSessionHandle, ckpEncryptedPart, ckEncryptedPartLength, ckpPart, &ckPartLength); - - jPart = ckByteArrayToJByteArray(env, ckpPart, ckPartLength); - free(ckpPart); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jPart = ckByteArrayToJByteArray(env, ckpPart, ckPartLength); + } free(ckpEncryptedPart); - - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } + free(ckpPart); return jPart ; } @@ -161,7 +177,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SignEncr CK_SESSION_HANDLE ckSessionHandle; CK_BYTE_PTR ckpPart = NULL_PTR, ckpEncryptedPart; CK_ULONG ckPartLength, ckEncryptedPartLength = 0; - jbyteArray jEncryptedPart; + jbyteArray jEncryptedPart = NULL; CK_RV rv; CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); @@ -169,20 +185,28 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SignEncr ckSessionHandle = jLongToCKULong(jSessionHandle); jByteArrayToCKByteArray(env, jPart, &ckpPart, &ckPartLength); + if ((*env)->ExceptionCheck(env)) { return NULL; } rv = (*ckpFunctions->C_SignEncryptUpdate)(ckSessionHandle, ckpPart, ckPartLength, NULL_PTR, &ckEncryptedPartLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + free(ckpPart); + return NULL; + } ckpEncryptedPart = (CK_BYTE_PTR) malloc(ckEncryptedPartLength * sizeof(CK_BYTE)); + if (ckpEncryptedPart == NULL) { + free(ckpPart); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_SignEncryptUpdate)(ckSessionHandle, ckpPart, ckPartLength, ckpEncryptedPart, &ckEncryptedPartLength); - - jEncryptedPart = ckByteArrayToJByteArray(env, ckpEncryptedPart, ckEncryptedPartLength); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jEncryptedPart = ckByteArrayToJByteArray(env, ckpEncryptedPart, ckEncryptedPartLength); + } free(ckpPart); free(ckpEncryptedPart); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - return jEncryptedPart ; } #endif @@ -205,7 +229,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptV CK_SESSION_HANDLE ckSessionHandle; CK_BYTE_PTR ckpPart, ckpEncryptedPart = NULL_PTR; CK_ULONG ckPartLength = 0, ckEncryptedPartLength; - jbyteArray jPart; + jbyteArray jPart = NULL; CK_RV rv; CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); @@ -213,19 +237,28 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptV ckSessionHandle = jLongToCKULong(jSessionHandle); jByteArrayToCKByteArray(env, jEncryptedPart, &ckpEncryptedPart, &ckEncryptedPartLength); + if ((*env)->ExceptionCheck(env)) { return NULL; } rv = (*ckpFunctions->C_DecryptVerifyUpdate)(ckSessionHandle, ckpEncryptedPart, ckEncryptedPartLength, NULL_PTR, &ckPartLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + free(ckpEncryptedPart); + return NULL; + } ckpPart = (CK_BYTE_PTR) malloc(ckPartLength * sizeof(CK_BYTE)); + if (ckpPart == NULL) { + free(ckpEncryptedPart); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_DecryptVerifyUpdate)(ckSessionHandle, ckpEncryptedPart, ckEncryptedPartLength, ckpPart, &ckPartLength); - jPart = ckByteArrayToJByteArray(env, ckpPart, ckPartLength); - free(ckpPart); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jPart = ckByteArrayToJByteArray(env, ckpPart, ckPartLength); + } free(ckpEncryptedPart); - - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } + free(ckpPart); return jPart ; } @@ -252,7 +285,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetFunctionSta /* C_GetFunctionStatus should always return CKR_FUNCTION_NOT_PARALLEL */ rv = (*ckpFunctions->C_GetFunctionStatus)(ckSessionHandle); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -277,6 +310,6 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CancelFunction /* C_GetFunctionStatus should always return CKR_FUNCTION_NOT_PARALLEL */ rv = (*ckpFunctions->C_CancelFunction)(ckSessionHandle); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_general.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_general.c index 05821a15d36..e6cbe2b6d91 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_general.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_general.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -102,6 +102,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_initializeLibrary jclass fetchClass(JNIEnv *env, const char *name) { jclass tmpClass = (*env)->FindClass(env, name); + if (tmpClass == NULL) { return NULL; } return (*env)->NewGlobalRef(env, tmpClass); } @@ -110,14 +111,18 @@ void prefetchFields(JNIEnv *env, jclass thisClass) { /* PKCS11 */ pNativeDataID = (*env)->GetFieldID(env, thisClass, "pNativeData", "J"); + if (pNativeDataID == NULL) { return; } /* CK_MECHANISM */ tmpClass = (*env)->FindClass(env, CLASS_MECHANISM); + if (tmpClass == NULL) { return; } mech_mechanismID = (*env)->GetFieldID(env, tmpClass, "mechanism", "J"); + if (mech_mechanismID == NULL) { return; } mech_pParameterID = (*env)->GetFieldID(env, tmpClass, "pParameter", "Ljava/lang/Object;"); - + if (mech_pParameterID == NULL) { return; } jByteArrayClass = fetchClass(env, "[B"); + if (jByteArrayClass == NULL) { return; } jLongClass = fetchClass(env, "java/lang/Long"); } @@ -252,10 +257,9 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetInfo if (ckpFunctions == NULL) { return NULL; } rv = (*ckpFunctions->C_GetInfo)(&ckLibInfo); - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - - jInfoObject = ckInfoPtrToJInfo(env, &ckLibInfo); - + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jInfoObject = ckInfoPtrToJInfo(env, &ckLibInfo); + } return jInfoObject ; } @@ -279,28 +283,31 @@ jobject ckInfoPtrToJInfo(JNIEnv *env, const CK_INFO_PTR ckpInfo) /* load CK_INFO class */ jInfoClass = (*env)->FindClass(env, CLASS_INFO); - assert(jInfoClass != 0); + if (jInfoClass == NULL) { return NULL; }; /* load CK_INFO constructor */ jCtrId = (*env)->GetMethodID (env, jInfoClass, "<init>", "(Lsun/security/pkcs11/wrapper/CK_VERSION;[CJ[CLsun/security/pkcs11/wrapper/CK_VERSION;)V"); - - assert(jCtrId != 0); + if (jCtrId == NULL) { return NULL; } /* prep all fields */ jCryptokiVer = ckVersionPtrToJVersion(env, &(ckpInfo->cryptokiVersion)); + if (jCryptokiVer == NULL) { return NULL; } jVendor = ckUTF8CharArrayToJCharArray(env, &(ckpInfo->manufacturerID[0]), 32); + if (jVendor == NULL) { return NULL; } jFlags = ckULongToJLong(ckpInfo->flags); jLibraryDesc = ckUTF8CharArrayToJCharArray(env, &(ckpInfo->libraryDescription[0]), 32); + if (jLibraryDesc == NULL) { return NULL; } jLibraryVer = ckVersionPtrToJVersion(env, &(ckpInfo->libraryVersion)); + if (jLibraryVer == NULL) { return NULL; } /* create new CK_INFO object */ jInfoObject = (*env)->NewObject(env, jInfoClass, jCtrId, jCryptokiVer, jVendor, jFlags, jLibraryDesc, jLibraryVer); - assert(jInfoObject != 0); + if (jInfoObject == NULL) { return NULL; } /* free local references */ (*env)->DeleteLocalRef(env, jInfoClass); @@ -343,15 +350,18 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetSlotList if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } ckpSlotList = (CK_SLOT_ID_PTR) malloc(ckTokenNumber * sizeof(CK_SLOT_ID)); + if (ckpSlotList == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_GetSlotList)(ckTokenPresent, ckpSlotList, &ckTokenNumber); - - jSlotList = ckULongArrayToJLongArray(env, ckpSlotList, ckTokenNumber); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jSlotList = ckULongArrayToJLongArray(env, ckpSlotList, ckTokenNumber); + } free(ckpSlotList); - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - return jSlotList ; } #endif @@ -380,10 +390,9 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetSlotInfo ckSlotID = jLongToCKULong(jSlotID); rv = (*ckpFunctions->C_GetSlotInfo)(ckSlotID, &ckSlotInfo); - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - - jSlotInfoObject = ckSlotInfoPtrToJSlotInfo(env, &ckSlotInfo); - + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jSlotInfoObject = ckSlotInfoPtrToJSlotInfo(env, &ckSlotInfo); + } return jSlotInfoObject ; } @@ -410,28 +419,32 @@ ckSlotInfoPtrToJSlotInfo /* load CK_SLOT_INFO class */ jSlotInfoClass = (*env)->FindClass(env, CLASS_SLOT_INFO); - assert(jSlotInfoClass != 0); + if (jSlotInfoClass == NULL) { return NULL; }; /* load CK_SLOT_INFO constructor */ jCtrId = (*env)->GetMethodID (env, jSlotInfoClass, "<init>", "([C[CJLsun/security/pkcs11/wrapper/CK_VERSION;Lsun/security/pkcs11/wrapper/CK_VERSION;)V"); - assert(jCtrId != 0); + if (jCtrId == NULL) { return NULL; } /* prep all fields */ jSlotDesc = ckUTF8CharArrayToJCharArray(env, &(ckpSlotInfo->slotDescription[0]), 64); + if (jSlotDesc == NULL) { return NULL; } jVendor = ckUTF8CharArrayToJCharArray(env, &(ckpSlotInfo->manufacturerID[0]), 32); + if (jVendor == NULL) { return NULL; } jFlags = ckULongToJLong(ckpSlotInfo->flags); jHardwareVer = ckVersionPtrToJVersion(env, &(ckpSlotInfo->hardwareVersion)); + if (jHardwareVer == NULL) { return NULL; } jFirmwareVer = ckVersionPtrToJVersion(env, &(ckpSlotInfo->firmwareVersion)); + if (jFirmwareVer == NULL) { return NULL; } /* create new CK_SLOT_INFO object */ jSlotInfoObject = (*env)->NewObject (env, jSlotInfoClass, jCtrId, jSlotDesc, jVendor, jFlags, jHardwareVer, jFirmwareVer); - assert(jSlotInfoObject != 0); + if (jSlotInfoObject == NULL) { return NULL; } /* free local references */ (*env)->DeleteLocalRef(env, jSlotInfoClass); @@ -460,7 +473,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetTokenInfo { CK_SLOT_ID ckSlotID; CK_TOKEN_INFO ckTokenInfo; - jobject jInfoTokenObject; + jobject jInfoTokenObject = NULL; CK_RV rv; CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); @@ -469,10 +482,9 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetTokenInfo ckSlotID = jLongToCKULong(jSlotID); rv = (*ckpFunctions->C_GetTokenInfo)(ckSlotID, &ckTokenInfo); - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - - jInfoTokenObject = ckTokenInfoPtrToJTokenInfo(env, &ckTokenInfo); - + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jInfoTokenObject = ckTokenInfoPtrToJTokenInfo(env, &ckTokenInfo); + } return jInfoTokenObject ; } @@ -512,21 +524,25 @@ ckTokenInfoPtrToJTokenInfo /* load CK_TOKEN_INFO class */ jTokenInfoClass = (*env)->FindClass(env, CLASS_TOKEN_INFO); - assert(jTokenInfoClass != 0); + if (jTokenInfoClass == NULL) { return NULL; }; /* load CK_TOKEN_INFO constructor */ jCtrId = (*env)->GetMethodID (env, jTokenInfoClass, "<init>", "([C[C[C[CJJJJJJJJJJJLsun/security/pkcs11/wrapper/CK_VERSION;Lsun/security/pkcs11/wrapper/CK_VERSION;[C)V"); - assert(jCtrId != 0); + if (jCtrId == NULL) { return NULL; }; /* prep all fields */ jLabel = ckUTF8CharArrayToJCharArray(env, &(ckpTokenInfo->label[0]), 32); + if (jLabel == NULL) { return NULL; }; jVendor = ckUTF8CharArrayToJCharArray(env, &(ckpTokenInfo->manufacturerID[0]), 32); + if (jVendor == NULL) { return NULL; }; jModel = ckUTF8CharArrayToJCharArray(env, &(ckpTokenInfo->model[0]), 16); + if (jModel == NULL) { return NULL; }; jSerialNo = ckUTF8CharArrayToJCharArray(env, &(ckpTokenInfo->serialNumber[0]), 16); + if (jSerialNo == NULL) { return NULL; }; jFlags = ckULongToJLong(ckpTokenInfo->flags); jMaxSnCnt = ckULongSpecialToJLong(ckpTokenInfo->ulMaxSessionCount); jSnCnt = ckULongSpecialToJLong(ckpTokenInfo->ulSessionCount); @@ -540,10 +556,13 @@ ckTokenInfoPtrToJTokenInfo jFreePrivMem = ckULongSpecialToJLong(ckpTokenInfo->ulFreePrivateMemory); jHardwareVer = ckVersionPtrToJVersion(env, &(ckpTokenInfo->hardwareVersion)); + if (jHardwareVer == NULL) { return NULL; } jFirmwareVer = ckVersionPtrToJVersion(env, &(ckpTokenInfo->firmwareVersion)); + if (jFirmwareVer == NULL) { return NULL; } jUtcTime = ckUTF8CharArrayToJCharArray(env, &(ckpTokenInfo->utcTime[0]), 16); + if (jUtcTime == NULL) { return NULL; } /* create new CK_TOKEN_INFO object */ jTokenInfoObject = @@ -553,7 +572,7 @@ ckTokenInfoPtrToJTokenInfo jMaxPinLen, jMinPinLen, jTotalPubMem, jFreePubMem, jTotalPrivMem, jFreePrivMem, jHardwareVer, jFirmwareVer, jUtcTime); - assert(jTokenInfoObject != 0); + if (jTokenInfoObject == NULL) { return NULL; } /* free local references */ (*env)->DeleteLocalRef(env, jTokenInfoClass); @@ -584,7 +603,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1WaitForSlotEvent { CK_FLAGS ckFlags; CK_SLOT_ID ckSlotID; - jlong jSlotID; + jlong jSlotID = 0L; CK_RV rv; CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); @@ -593,9 +612,9 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1WaitForSlotEvent ckFlags = jLongToCKULong(jFlags); rv = (*ckpFunctions->C_WaitForSlotEvent)(ckFlags, &ckSlotID, NULL_PTR); - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L; } - - jSlotID = ckULongToJLong(ckSlotID); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jSlotID = ckULongToJLong(ckSlotID); + } return jSlotID ; } @@ -632,16 +651,19 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetMechanismList ckpMechanismList = (CK_MECHANISM_TYPE_PTR) malloc(ckMechanismNumber * sizeof(CK_MECHANISM_TYPE)); + if (ckpMechanismList == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_GetMechanismList)(ckSlotID, ckpMechanismList, &ckMechanismNumber); - - jMechanismList = ckULongArrayToJLongArray(env, ckpMechanismList, - ckMechanismNumber); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jMechanismList = ckULongArrayToJLongArray(env, ckpMechanismList, + ckMechanismNumber); + } free(ckpMechanismList); - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - return jMechanismList ; } #endif @@ -663,7 +685,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetMechanismInfo CK_SLOT_ID ckSlotID; CK_MECHANISM_TYPE ckMechanismType; CK_MECHANISM_INFO ckMechanismInfo; - jobject jMechanismInfo; + jobject jMechanismInfo = NULL; CK_RV rv; CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); @@ -674,10 +696,9 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetMechanismInfo rv = (*ckpFunctions->C_GetMechanismInfo)(ckSlotID, ckMechanismType, &ckMechanismInfo); - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - - jMechanismInfo = ckMechanismInfoPtrToJMechanismInfo(env, &ckMechanismInfo); - + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jMechanismInfo = ckMechanismInfoPtrToJMechanismInfo(env, &ckMechanismInfo); + } return jMechanismInfo ; } @@ -703,11 +724,11 @@ ckMechanismInfoPtrToJMechanismInfo /* load CK_MECHANISM_INFO class */ jMechanismInfoClass = (*env)->FindClass(env, CLASS_MECHANISM_INFO); - assert(jMechanismInfoClass != 0); + if (jMechanismInfoClass == NULL) { return NULL; }; /* load CK_MECHANISM_INFO constructor */ jCtrId = (*env)->GetMethodID(env, jMechanismInfoClass, "<init>", "(JJJ)V"); - assert(jCtrId != 0); + if (jCtrId == NULL) { return NULL; }; /* prep all fields */ jMinKeySize = ckULongToJLong(ckpMechanismInfo->ulMinKeySize); @@ -717,7 +738,7 @@ ckMechanismInfoPtrToJMechanismInfo /* create new CK_MECHANISM_INFO object */ jMechanismInfoObject = (*env)->NewObject(env, jMechanismInfoClass, jCtrId, jMinKeySize, jMaxKeySize, jFlags); - assert(jMechanismInfoObject != 0); + if (jMechanismInfoObject == NULL) { return NULL; }; /* free local references */ (*env)->DeleteLocalRef(env, jMechanismInfoClass); @@ -753,8 +774,13 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1InitToken ckSlotID = jLongToCKULong(jSlotID); jCharArrayToCKCharArray(env, jPin, &ckpPin, &ckPinLength); - jCharArrayToCKUTF8CharArray(env, jLabel, &ckpLabel, &ckLabelLength); + if ((*env)->ExceptionCheck(env)) { return; } /* ckLabelLength <= 32 !!! */ + jCharArrayToCKUTF8CharArray(env, jLabel, &ckpLabel, &ckLabelLength); + if ((*env)->ExceptionCheck(env)) { + free(ckpPin); + return; + } rv = (*ckpFunctions->C_InitToken)(ckSlotID, ckpPin, ckPinLength, ckpLabel); TRACE1("InitToken return code: %d", rv); @@ -790,6 +816,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1InitPIN ckSessionHandle = jLongToCKULong(jSessionHandle); jCharArrayToCKCharArray(env, jPin, &ckpPin, &ckPinLength); + if ((*env)->ExceptionCheck(env)) { return; } rv = (*ckpFunctions->C_InitPIN)(ckSessionHandle, ckpPin, ckPinLength); @@ -828,7 +855,12 @@ jcharArray jNewPin) ckSessionHandle = jLongToCKULong(jSessionHandle); jCharArrayToCKCharArray(env, jOldPin, &ckpOldPin, &ckOldPinLength); + if ((*env)->ExceptionCheck(env)) { return; } jCharArrayToCKCharArray(env, jNewPin, &ckpNewPin, &ckNewPinLength); + if ((*env)->ExceptionCheck(env)) { + free(ckpOldPin); + return; + } rv = (*ckpFunctions->C_SetPIN)(ckSessionHandle, ckpOldPin, ckOldPinLength, ckpNewPin, ckNewPinLength); diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_keymgmt.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_keymgmt.c index 65fbfd80057..aab0491a30e 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_keymgmt.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_keymgmt.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -74,7 +74,7 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GenerateKey CK_ATTRIBUTE_PTR ckpAttributes = NULL_PTR; CK_ULONG ckAttributesLength; CK_OBJECT_HANDLE ckKeyHandle; - jlong jKeyHandle; + jlong jKeyHandle = 0L; CK_ULONG i; CK_RV rv; @@ -83,21 +83,23 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GenerateKey ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); - if ((*env)->ExceptionOccurred(env)) { return 0L ; } + if ((*env)->ExceptionCheck(env)) { return 0L ; } + jAttributeArrayToCKAttributeArray(env, jTemplate, &ckpAttributes, &ckAttributesLength); + if ((*env)->ExceptionCheck(env)) { + if (ckMechanism.pParameter != NULL_PTR) { + free(ckMechanism.pParameter); + } + return 0L; + } rv = (*ckpFunctions->C_GenerateKey)(ckSessionHandle, &ckMechanism, ckpAttributes, ckAttributesLength, &ckKeyHandle); - jKeyHandle = ckULongToJLong(ckKeyHandle); - for(i=0; i<ckAttributesLength; i++) { - if(ckpAttributes[i].pValue != NULL_PTR) { - free(ckpAttributes[i].pValue); - } - } - free(ckpAttributes); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jKeyHandle = ckULongToJLong(ckKeyHandle); - /* cheack, if we must give a initialization vector back to Java */ - switch (ckMechanism.mechanism) { + /* cheack, if we must give a initialization vector back to Java */ + switch (ckMechanism.mechanism) { case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_PBE_MD5_CAST_CBC: @@ -109,13 +111,13 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GenerateKey /* we must copy back the initialization vector to the jMechanism object */ copyBackPBEInitializationVector(env, &ckMechanism, jMechanism); break; + } } - if(ckMechanism.pParameter != NULL_PTR) { + if (ckMechanism.pParameter != NULL_PTR) { free(ckMechanism.pParameter); } - - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } + freeCKAttributeArray(ckpAttributes, ckAttributesLength); return jKeyHandle ; } @@ -158,40 +160,53 @@ JNIEXPORT jlongArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Generate ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); - jAttributeArrayToCKAttributeArray(env, jPublicKeyTemplate, &ckpPublicKeyAttributes, &ckPublicKeyAttributesLength); - jAttributeArrayToCKAttributeArray(env, jPrivateKeyTemplate, &ckpPrivateKeyAttributes, &ckPrivateKeyAttributesLength); + if ((*env)->ExceptionCheck(env)) { return NULL; } + ckpKeyHandles = (CK_OBJECT_HANDLE_PTR) malloc(2 * sizeof(CK_OBJECT_HANDLE)); + if (ckpKeyHandles == NULL) { + if (ckMechanism.pParameter != NULL_PTR) { + free(ckMechanism.pParameter); + } + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } ckpPublicKeyHandle = ckpKeyHandles; /* first element of array is Public Key */ ckpPrivateKeyHandle = (ckpKeyHandles + 1); /* second element of array is Private Key */ + jAttributeArrayToCKAttributeArray(env, jPublicKeyTemplate, &ckpPublicKeyAttributes, &ckPublicKeyAttributesLength); + if ((*env)->ExceptionCheck(env)) { + if (ckMechanism.pParameter != NULL_PTR) { + free(ckMechanism.pParameter); + } + free(ckpKeyHandles); + return NULL; + } + + jAttributeArrayToCKAttributeArray(env, jPrivateKeyTemplate, &ckpPrivateKeyAttributes, &ckPrivateKeyAttributesLength); + if ((*env)->ExceptionCheck(env)) { + if (ckMechanism.pParameter != NULL_PTR) { + free(ckMechanism.pParameter); + } + free(ckpKeyHandles); + freeCKAttributeArray(ckpPublicKeyAttributes, ckPublicKeyAttributesLength); + return NULL; + } + rv = (*ckpFunctions->C_GenerateKeyPair)(ckSessionHandle, &ckMechanism, ckpPublicKeyAttributes, ckPublicKeyAttributesLength, ckpPrivateKeyAttributes, ckPrivateKeyAttributesLength, ckpPublicKeyHandle, ckpPrivateKeyHandle); - jKeyHandles = ckULongArrayToJLongArray(env, ckpKeyHandles, 2); - - for(i=0; i<ckPublicKeyAttributesLength; i++) { - if(ckpPublicKeyAttributes[i].pValue != NULL_PTR) { - free(ckpPublicKeyAttributes[i].pValue); - } + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jKeyHandles = ckULongArrayToJLongArray(env, ckpKeyHandles, 2); } - free(ckpPublicKeyAttributes); - - for(i=0; i<ckPrivateKeyAttributesLength; i++) { - if(ckpPrivateKeyAttributes[i].pValue != NULL_PTR) { - free(ckpPrivateKeyAttributes[i].pValue); - } - } - free(ckpPrivateKeyAttributes); if(ckMechanism.pParameter != NULL_PTR) { free(ckMechanism.pParameter); } - free(ckpKeyHandles); - - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL; } + freeCKAttributeArray(ckpPublicKeyAttributes, ckPublicKeyAttributesLength); + freeCKAttributeArray(ckpPrivateKeyAttributes, ckPrivateKeyAttributesLength); return jKeyHandles ; } @@ -217,7 +232,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1WrapKey CK_MECHANISM ckMechanism; CK_OBJECT_HANDLE ckWrappingKeyHandle; CK_OBJECT_HANDLE ckKeyHandle; - jbyteArray jWrappedKey; + jbyteArray jWrappedKey = NULL; CK_RV rv; CK_BYTE BUF[MAX_STACK_BUFFER_LEN]; CK_BYTE_PTR ckpWrappedKey = BUF; @@ -228,24 +243,32 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1WrapKey ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return NULL; } + ckWrappingKeyHandle = jLongToCKULong(jWrappingKeyHandle); ckKeyHandle = jLongToCKULong(jKeyHandle); rv = (*ckpFunctions->C_WrapKey)(ckSessionHandle, &ckMechanism, ckWrappingKeyHandle, ckKeyHandle, ckpWrappedKey, &ckWrappedKeyLength); if (rv == CKR_BUFFER_TOO_SMALL) { ckpWrappedKey = (CK_BYTE_PTR) malloc(ckWrappedKeyLength); + if (ckpWrappedKey == NULL) { + if (ckMechanism.pParameter != NULL_PTR) { + free(ckMechanism.pParameter); + } + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } + rv = (*ckpFunctions->C_WrapKey)(ckSessionHandle, &ckMechanism, ckWrappingKeyHandle, ckKeyHandle, ckpWrappedKey, &ckWrappedKeyLength); } if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { jWrappedKey = ckByteArrayToJByteArray(env, ckpWrappedKey, ckWrappedKeyLength); } - if (ckpWrappedKey != BUF) { - free(ckpWrappedKey); - } - if(ckMechanism.pParameter != NULL_PTR) + if (ckpWrappedKey != BUF) { free(ckpWrappedKey); } + if (ckMechanism.pParameter != NULL_PTR) { free(ckMechanism.pParameter); - + } return jWrappedKey ; } #endif @@ -277,7 +300,7 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1UnwrapKey CK_ATTRIBUTE_PTR ckpAttributes = NULL_PTR; CK_ULONG ckAttributesLength; CK_OBJECT_HANDLE ckKeyHandle; - jlong jKeyHandle; + jlong jKeyHandle = 0L; CK_ULONG i; CK_RV rv; @@ -286,37 +309,48 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1UnwrapKey ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return 0L; } + ckUnwrappingKeyHandle = jLongToCKULong(jUnwrappingKeyHandle); jByteArrayToCKByteArray(env, jWrappedKey, &ckpWrappedKey, &ckWrappedKeyLength); + if ((*env)->ExceptionCheck(env)) { + if (ckMechanism.pParameter != NULL_PTR) { + free(ckMechanism.pParameter); + } + return 0L; + } + jAttributeArrayToCKAttributeArray(env, jTemplate, &ckpAttributes, &ckAttributesLength); + if ((*env)->ExceptionCheck(env)) { + if (ckMechanism.pParameter != NULL_PTR) { + free(ckMechanism.pParameter); + } + free(ckpWrappedKey); + return 0L; + } + rv = (*ckpFunctions->C_UnwrapKey)(ckSessionHandle, &ckMechanism, ckUnwrappingKeyHandle, ckpWrappedKey, ckWrappedKeyLength, ckpAttributes, ckAttributesLength, &ckKeyHandle); - jKeyHandle = ckLongToJLong(ckKeyHandle); - - for(i=0; i<ckAttributesLength; i++) { - if(ckpAttributes[i].pValue != NULL_PTR) { - free(ckpAttributes[i].pValue); - } - } - free(ckpAttributes); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jKeyHandle = ckLongToJLong(ckKeyHandle); #if 0 - /* cheack, if we must give a initialization vector back to Java */ - if (ckMechanism.mechanism == CKM_KEY_WRAP_SET_OAEP) { - /* we must copy back the unwrapped key info to the jMechanism object */ - copyBackSetUnwrappedKey(env, &ckMechanism, jMechanism); - } + /* cheack, if we must give a initialization vector back to Java */ + if (ckMechanism.mechanism == CKM_KEY_WRAP_SET_OAEP) { + /* we must copy back the unwrapped key info to the jMechanism object */ + copyBackSetUnwrappedKey(env, &ckMechanism, jMechanism); + } #endif + } - free(ckpWrappedKey); - if(ckMechanism.pParameter != NULL_PTR) { + if (ckMechanism.pParameter != NULL_PTR) { free(ckMechanism.pParameter); } - - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } + freeCKAttributeArray(ckpAttributes, ckAttributesLength); + free(ckpWrappedKey); return jKeyHandle ; } @@ -360,8 +394,7 @@ void freeEcdh1DeriveParams(CK_MECHANISM_PTR ckMechanism) { */ void copyBackTLSPrfParams(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMechanism) { - jclass jMechanismClass= (*env)->FindClass(env, CLASS_MECHANISM); - jclass jTLSPrfParamsClass = (*env)->FindClass(env, CLASS_TLS_PRF_PARAMS); + jclass jMechanismClass, jTLSPrfParamsClass; CK_TLS_PRF_PARAMS *ckTLSPrfParams; jobject jTLSPrfParams; jfieldID fieldID; @@ -374,8 +407,10 @@ void copyBackTLSPrfParams(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMecha int i; /* get mechanism */ + jMechanismClass = (*env)->FindClass(env, CLASS_MECHANISM); + if (jMechanismClass == NULL) { return; } fieldID = (*env)->GetFieldID(env, jMechanismClass, "mechanism", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jMechanismType = (*env)->GetLongField(env, jMechanism, fieldID); ckMechanismType = jLongToCKULong(jMechanismType); if (ckMechanismType != ckMechanism->mechanism) { @@ -388,12 +423,14 @@ void copyBackTLSPrfParams(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMecha if (ckTLSPrfParams != NULL_PTR) { /* get the Java CK_TLS_PRF_PARAMS object (pParameter) */ fieldID = (*env)->GetFieldID(env, jMechanismClass, "pParameter", "Ljava/lang/Object;"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jTLSPrfParams = (*env)->GetObjectField(env, jMechanism, fieldID); /* copy back the client IV */ + jTLSPrfParamsClass = (*env)->FindClass(env, CLASS_TLS_PRF_PARAMS); + if (jTLSPrfParamsClass == NULL) { return; } fieldID = (*env)->GetFieldID(env, jTLSPrfParamsClass, "pOutput", "[B"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jOutput = (*env)->GetObjectField(env, jTLSPrfParams, fieldID); output = ckTLSPrfParams->pOutput; @@ -402,26 +439,21 @@ void copyBackTLSPrfParams(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMecha if (jOutput != NULL) { jLength = (*env)->GetArrayLength(env, jOutput); jBytes = (*env)->GetByteArrayElements(env, jOutput, NULL); + if (jBytes == NULL) { return; } + /* copy the bytes to the Java buffer */ for (i=0; i < jLength; i++) { jBytes[i] = ckByteToJByte(output[i]); } /* copy back the Java buffer to the object */ (*env)->ReleaseByteArrayElements(env, jOutput, jBytes, 0); - // free malloc'd data - free(output); } // free malloc'd data - if (ckTLSPrfParams->pSeed != NULL) { - free(ckTLSPrfParams->pSeed); - } - if (ckTLSPrfParams->pLabel != NULL) { - free(ckTLSPrfParams->pLabel); - } - if (ckTLSPrfParams->pulOutputLen != NULL) { - free(ckTLSPrfParams->pulOutputLen); - } + free(ckTLSPrfParams->pSeed); + free(ckTLSPrfParams->pLabel); + free(ckTLSPrfParams->pulOutputLen); + free(ckTLSPrfParams->pOutput); } } @@ -456,8 +488,16 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DeriveKey ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return 0L; } + ckBaseKeyHandle = jLongToCKULong(jBaseKeyHandle); jAttributeArrayToCKAttributeArray(env, jTemplate, &ckpAttributes, &ckAttributesLength); + if ((*env)->ExceptionCheck(env)) { + if (ckMechanism.pParameter != NULL_PTR) { + free(ckMechanism.pParameter); + } + return 0L; + } switch (ckMechanism.mechanism) { case CKM_SSL3_KEY_AND_MAC_DERIVE: @@ -476,14 +516,8 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DeriveKey ckpAttributes, ckAttributesLength, phKey); jKeyHandle = ckLongToJLong(ckKeyHandle); - for(i=0; i<ckAttributesLength; i++) { - if(ckpAttributes[i].pValue != NULL_PTR) { - free(ckpAttributes[i].pValue); - } - } - if (ckpAttributes != NULL) { - free(ckpAttributes); - } + + freeCKAttributeArray(ckpAttributes, ckAttributesLength); switch (ckMechanism.mechanism) { case CKM_SSL3_MASTER_KEY_DERIVE: @@ -512,11 +546,10 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DeriveKey break; } - if(ckMechanism.pParameter != NULL_PTR) { + if (ckMechanism.pParameter != NULL_PTR) { free(ckMechanism.pParameter); } - - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } return jKeyHandle ; } @@ -529,9 +562,7 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DeriveKey */ void copyBackClientVersion(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMechanism) { - jclass jMechanismClass= (*env)->FindClass(env, CLASS_MECHANISM); - jclass jSSL3MasterKeyDeriveParamsClass = (*env)->FindClass(env, CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS); - jclass jVersionClass = (*env)->FindClass(env, CLASS_VERSION); + jclass jMechanismClass, jSSL3MasterKeyDeriveParamsClass, jVersionClass; CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ckSSL3MasterKeyDeriveParams; CK_VERSION *ckVersion; jfieldID fieldID; @@ -541,8 +572,10 @@ void copyBackClientVersion(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMech jobject jVersion; /* get mechanism */ + jMechanismClass = (*env)->FindClass(env, CLASS_MECHANISM); + if (jMechanismClass == NULL) { return; } fieldID = (*env)->GetFieldID(env, jMechanismClass, "mechanism", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jMechanismType = (*env)->GetLongField(env, jMechanism, fieldID); ckMechanismType = jLongToCKULong(jMechanismType); if (ckMechanismType != ckMechanism->mechanism) { @@ -558,27 +591,31 @@ void copyBackClientVersion(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMech if (ckVersion != NULL_PTR) { /* get the Java CK_SSL3_MASTER_KEY_DERIVE_PARAMS (pParameter) */ fieldID = (*env)->GetFieldID(env, jMechanismClass, "pParameter", "Ljava/lang/Object;"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } + jSSL3MasterKeyDeriveParams = (*env)->GetObjectField(env, jMechanism, fieldID); /* get the Java CK_VERSION */ + jSSL3MasterKeyDeriveParamsClass = (*env)->FindClass(env, CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS); + if (jSSL3MasterKeyDeriveParamsClass == NULL) { return; } fieldID = (*env)->GetFieldID(env, jSSL3MasterKeyDeriveParamsClass, "pVersion", "L"CLASS_VERSION";"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jVersion = (*env)->GetObjectField(env, jSSL3MasterKeyDeriveParams, fieldID); /* now copy back the version from the native structure to the Java structure */ /* copy back the major version */ + jVersionClass = (*env)->FindClass(env, CLASS_VERSION); + if (jVersionClass == NULL) { return; } fieldID = (*env)->GetFieldID(env, jVersionClass, "major", "B"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } (*env)->SetByteField(env, jVersion, fieldID, ckByteToJByte(ckVersion->major)); /* copy back the minor version */ fieldID = (*env)->GetFieldID(env, jVersionClass, "minor", "B"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } (*env)->SetByteField(env, jVersion, fieldID, ckByteToJByte(ckVersion->minor)); } - } } @@ -591,9 +628,7 @@ void copyBackClientVersion(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMech */ void copyBackSSLKeyMatParams(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMechanism) { - jclass jMechanismClass= (*env)->FindClass(env, CLASS_MECHANISM); - jclass jSSL3KeyMatParamsClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_PARAMS); - jclass jSSL3KeyMatOutClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_OUT); + jclass jMechanismClass, jSSL3KeyMatParamsClass, jSSL3KeyMatOutClass; CK_SSL3_KEY_MAT_PARAMS *ckSSL3KeyMatParam; CK_SSL3_KEY_MAT_OUT *ckSSL3KeyMatOut; jfieldID fieldID; @@ -608,8 +643,10 @@ void copyBackSSLKeyMatParams(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMe int i; /* get mechanism */ + jMechanismClass= (*env)->FindClass(env, CLASS_MECHANISM); + if (jMechanismClass == NULL) { return; } fieldID = (*env)->GetFieldID(env, jMechanismClass, "mechanism", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jMechanismType = (*env)->GetLongField(env, jMechanism, fieldID); ckMechanismType = jLongToCKULong(jMechanismType); if (ckMechanismType != ckMechanism->mechanism) { @@ -633,74 +670,78 @@ void copyBackSSLKeyMatParams(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMe if (ckSSL3KeyMatOut != NULL_PTR) { /* get the Java CK_SSL3_KEY_MAT_PARAMS (pParameter) */ fieldID = (*env)->GetFieldID(env, jMechanismClass, "pParameter", "Ljava/lang/Object;"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jSSL3KeyMatParam = (*env)->GetObjectField(env, jMechanism, fieldID); /* get the Java CK_SSL3_KEY_MAT_OUT */ + jSSL3KeyMatParamsClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_PARAMS); + if (jSSL3KeyMatParamsClass == NULL) { return; } fieldID = (*env)->GetFieldID(env, jSSL3KeyMatParamsClass, "pReturnedKeyMaterial", "L"CLASS_SSL3_KEY_MAT_OUT";"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jSSL3KeyMatOut = (*env)->GetObjectField(env, jSSL3KeyMatParam, fieldID); /* now copy back all the key handles and the initialization vectors */ /* copy back client MAC secret handle */ + jSSL3KeyMatOutClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_OUT); + if (jSSL3KeyMatOutClass == NULL) { return; } fieldID = (*env)->GetFieldID(env, jSSL3KeyMatOutClass, "hClientMacSecret", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } (*env)->SetLongField(env, jSSL3KeyMatOut, fieldID, ckULongToJLong(ckSSL3KeyMatOut->hClientMacSecret)); /* copy back server MAC secret handle */ fieldID = (*env)->GetFieldID(env, jSSL3KeyMatOutClass, "hServerMacSecret", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } (*env)->SetLongField(env, jSSL3KeyMatOut, fieldID, ckULongToJLong(ckSSL3KeyMatOut->hServerMacSecret)); /* copy back client secret key handle */ fieldID = (*env)->GetFieldID(env, jSSL3KeyMatOutClass, "hClientKey", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } (*env)->SetLongField(env, jSSL3KeyMatOut, fieldID, ckULongToJLong(ckSSL3KeyMatOut->hClientKey)); /* copy back server secret key handle */ fieldID = (*env)->GetFieldID(env, jSSL3KeyMatOutClass, "hServerKey", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } (*env)->SetLongField(env, jSSL3KeyMatOut, fieldID, ckULongToJLong(ckSSL3KeyMatOut->hServerKey)); /* copy back the client IV */ fieldID = (*env)->GetFieldID(env, jSSL3KeyMatOutClass, "pIVClient", "[B"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jIV = (*env)->GetObjectField(env, jSSL3KeyMatOut, fieldID); iv = ckSSL3KeyMatOut->pIVClient; if (jIV != NULL) { jLength = (*env)->GetArrayLength(env, jIV); jBytes = (*env)->GetByteArrayElements(env, jIV, NULL); + if (jBytes == NULL) { return; } /* copy the bytes to the Java buffer */ for (i=0; i < jLength; i++) { jBytes[i] = ckByteToJByte(iv[i]); } /* copy back the Java buffer to the object */ (*env)->ReleaseByteArrayElements(env, jIV, jBytes, 0); - // free malloc'd data - free(iv); } + // free malloc'd data + free(ckSSL3KeyMatOut->pIVClient); /* copy back the server IV */ fieldID = (*env)->GetFieldID(env, jSSL3KeyMatOutClass, "pIVServer", "[B"); - assert(fieldID != 0); + if (fieldID == NULL) { return; } jIV = (*env)->GetObjectField(env, jSSL3KeyMatOut, fieldID); iv = ckSSL3KeyMatOut->pIVServer; if (jIV != NULL) { jLength = (*env)->GetArrayLength(env, jIV); jBytes = (*env)->GetByteArrayElements(env, jIV, NULL); + if (jBytes == NULL) { return; } /* copy the bytes to the Java buffer */ for (i=0; i < jLength; i++) { jBytes[i] = ckByteToJByte(iv[i]); } /* copy back the Java buffer to the object */ (*env)->ReleaseByteArrayElements(env, jIV, jBytes, 0); - // free malloc'd data - free(iv); } - // free malloc'd data + free(ckSSL3KeyMatOut->pIVServer); free(ckSSL3KeyMatOut); } } diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_mutex.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_mutex.c index 31674f4ef9c..cb04af5a373 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_mutex.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_mutex.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -76,7 +76,7 @@ CK_C_INITIALIZE_ARGS_PTR ckpGlobalInitArgs; CK_C_INITIALIZE_ARGS_PTR makeCKInitArgsAdapter(JNIEnv *env, jobject jInitArgs) { CK_C_INITIALIZE_ARGS_PTR ckpInitArgs; - jclass jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS); + jclass jInitArgsClass; jfieldID fieldID; jlong jFlags; jobject jReserved; @@ -91,10 +91,20 @@ CK_C_INITIALIZE_ARGS_PTR makeCKInitArgsAdapter(JNIEnv *env, jobject jInitArgs) /* convert the Java InitArgs object to a pointer to a CK_C_INITIALIZE_ARGS structure */ ckpInitArgs = (CK_C_INITIALIZE_ARGS_PTR) malloc(sizeof(CK_C_INITIALIZE_ARGS)); + if (ckpInitArgs == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL_PTR; + } /* Set the mutex functions that will call the Java mutex functions, but * only set it, if the field is not null. */ + jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS); + if (jInitArgsClass == NULL) { + free(ckpInitArgs); + return NULL; + } + #ifdef NO_CALLBACKS ckpInitArgs->CreateMutex = NULL_PTR; ckpInitArgs->DestroyMutex = NULL_PTR; @@ -102,22 +112,22 @@ CK_C_INITIALIZE_ARGS_PTR makeCKInitArgsAdapter(JNIEnv *env, jobject jInitArgs) ckpInitArgs->UnlockMutex = NULL_PTR; #else fieldID = (*env)->GetFieldID(env, jInitArgsClass, "CreateMutex", "Lsun/security/pkcs11/wrapper/CK_CREATEMUTEX;"); - assert(fieldID != 0); + if (fieldID == NULL) { return NULL; } jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID); ckpInitArgs->CreateMutex = (jMutexHandler != NULL) ? &callJCreateMutex : NULL_PTR; fieldID = (*env)->GetFieldID(env, jInitArgsClass, "DestroyMutex", "Lsun/security/pkcs11/wrapper/CK_DESTROYMUTEX;"); - assert(fieldID != 0); + if (fieldID == NULL) { return NULL; } jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID); ckpInitArgs->DestroyMutex = (jMutexHandler != NULL) ? &callJDestroyMutex : NULL_PTR; fieldID = (*env)->GetFieldID(env, jInitArgsClass, "LockMutex", "Lsun/security/pkcs11/wrapper/CK_LOCKMUTEX;"); - assert(fieldID != 0); + if (fieldID == NULL) { return NULL; } jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID); ckpInitArgs->LockMutex = (jMutexHandler != NULL) ? &callJLockMutex : NULL_PTR; fieldID = (*env)->GetFieldID(env, jInitArgsClass, "UnlockMutex", "Lsun/security/pkcs11/wrapper/CK_UNLOCKMUTEX;"); - assert(fieldID != 0); + if (fieldID == NULL) { return NULL; } jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID); ckpInitArgs->UnlockMutex = (jMutexHandler != NULL) ? &callJUnlockMutex : NULL_PTR; @@ -129,19 +139,25 @@ CK_C_INITIALIZE_ARGS_PTR makeCKInitArgsAdapter(JNIEnv *env, jobject jInitArgs) /* set the global object jInitArgs so that the right Java mutex functions will be called */ jInitArgsObject = (*env)->NewGlobalRef(env, jInitArgs); ckpGlobalInitArgs = (CK_C_INITIALIZE_ARGS_PTR) malloc(sizeof(CK_C_INITIALIZE_ARGS)); + if (ckpGlobalInitArgs == NULL) { + free(ckpInitArgs); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL_PTR; + } + memcpy(ckpGlobalInitArgs, ckpInitArgs, sizeof(CK_C_INITIALIZE_ARGS)); } #endif /* NO_CALLBACKS */ /* convert and set the flags field */ fieldID = (*env)->GetFieldID(env, jInitArgsClass, "flags", "J"); - assert(fieldID != 0); + if (fieldID == NULL) { return NULL; } jFlags = (*env)->GetLongField(env, jInitArgs, fieldID); ckpInitArgs->flags = jLongToCKULong(jFlags); /* pReserved should be NULL_PTR in this version */ fieldID = (*env)->GetFieldID(env, jInitArgsClass, "pReserved", "Ljava/lang/Object;"); - assert(fieldID != 0); + if (fieldID == NULL) { return NULL; } jReserved = (*env)->GetObjectField(env, jInitArgs, fieldID); /* we try to convert the reserved parameter also */ @@ -201,20 +217,21 @@ CK_RV callJCreateMutex(CK_VOID_PTR_PTR ppMutex) wasAttached = 1; } - jCreateMutexClass = (*env)->FindClass(env, CLASS_CREATEMUTEX); + if (jCreateMutexClass == NULL) { return rv; } jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS); + if (jInitArgsClass == NULL) { return rv; } /* get the CreateMutex object out of the jInitArgs object */ fieldID = (*env)->GetFieldID(env, jInitArgsClass, "CreateMutex", "Lsun/security/pkcs11/wrapper/CK_CREATEMUTEX;"); - assert(fieldID != 0); + if (fieldID == NULL) { return rv; } jCreateMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID); assert(jCreateMutex != 0); /* call the CK_CREATEMUTEX function of the CreateMutex object */ /* and get the new Java mutex object */ methodID = (*env)->GetMethodID(env, jCreateMutexClass, "CK_CREATEMUTEX", "()Ljava/lang/Object;"); - assert(methodID != 0); + if (methodID == NULL) { return rv; } jMutex = (*env)->CallObjectMethod(env, jCreateMutex, methodID); /* set a global reference on the Java mutex */ @@ -227,10 +244,13 @@ CK_RV callJCreateMutex(CK_VOID_PTR_PTR ppMutex) pkcs11Exception = (*env)->ExceptionOccurred(env); if (pkcs11Exception != NULL) { + /* TBD: clear the pending exception with ExceptionClear? */ /* The was an exception thrown, now we get the error-code from it */ pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION); + if (pkcs11ExceptionClass == NULL) { return rv; } methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J"); - assert(methodID != 0); + if (methodID == NULL) { return rv; } + errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID); rv = jLongToCKULong(errorCode); } @@ -292,22 +312,23 @@ CK_RV callJDestroyMutex(CK_VOID_PTR pMutex) wasAttached = 1; } - jDestroyMutexClass = (*env)->FindClass(env, CLASS_DESTROYMUTEX); + if (jDestroyMutexClass == NULL) { return rv; } jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS); + if (jInitArgsClass == NULL) { return rv; } /* convert the CK mutex to a Java mutex */ jMutex = ckVoidPtrToJObject(pMutex); /* get the DestroyMutex object out of the jInitArgs object */ fieldID = (*env)->GetFieldID(env, jInitArgsClass, "DestroyMutex", "Lsun/security/pkcs11/wrapper/CK_DESTROYMUTEX;"); - assert(fieldID != 0); + if (fieldID == NULL) { return rv; } jDestroyMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID); assert(jDestroyMutex != 0); /* call the CK_DESTROYMUTEX method of the DestroyMutex object */ methodID = (*env)->GetMethodID(env, jDestroyMutexClass, "CK_DESTROYMUTEX", "(Ljava/lang/Object;)V"); - assert(methodID != 0); + if (methodID == NULL) { return rv; } (*env)->CallVoidMethod(env, jDestroyMutex, methodID, jMutex); /* delete the global reference on the Java mutex */ @@ -318,10 +339,12 @@ CK_RV callJDestroyMutex(CK_VOID_PTR pMutex) pkcs11Exception = (*env)->ExceptionOccurred(env); if (pkcs11Exception != NULL) { + /* TBD: clear the pending exception with ExceptionClear? */ /* The was an exception thrown, now we get the error-code from it */ pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION); + if (pkcs11ExceptionClass == NULL) { return rv; } methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J"); - assert(methodID != 0); + if (methodID == NULL) { return rv; } errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID); rv = jLongToCKULong(errorCode); } @@ -383,33 +406,35 @@ CK_RV callJLockMutex(CK_VOID_PTR pMutex) wasAttached = 1; } - jLockMutexClass = (*env)->FindClass(env, CLASS_LOCKMUTEX); + if (jLockMutexClass == NULL) { return rv; } jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS); + if (jInitArgsClass == NULL) { return rv; } /* convert the CK mutex to a Java mutex */ jMutex = ckVoidPtrToJObject(pMutex); /* get the LockMutex object out of the jInitArgs object */ fieldID = (*env)->GetFieldID(env, jInitArgsClass, "LockMutex", "Lsun/security/pkcs11/wrapper/CK_LOCKMUTEX;"); - assert(fieldID != 0); + if (fieldID == NULL) { return rv; } jLockMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID); assert(jLockMutex != 0); /* call the CK_LOCKMUTEX method of the LockMutex object */ methodID = (*env)->GetMethodID(env, jLockMutexClass, "CK_LOCKMUTEX", "(Ljava/lang/Object;)V"); - assert(methodID != 0); + if (methodID == NULL) { return rv; } (*env)->CallVoidMethod(env, jLockMutex, methodID, jMutex); - /* check, if callback threw an exception */ pkcs11Exception = (*env)->ExceptionOccurred(env); if (pkcs11Exception != NULL) { + /* TBD: clear the pending exception with ExceptionClear? */ /* The was an exception thrown, now we get the error-code from it */ pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION); + if (pkcs11ExceptionClass == NULL) { return rv; } methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J"); - assert(methodID != 0); + if (methodID == NULL) { return rv; } errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID); rv = jLongToCKULong(errorCode); } @@ -471,33 +496,35 @@ CK_RV callJUnlockMutex(CK_VOID_PTR pMutex) wasAttached = 1; } - jUnlockMutexClass = (*env)->FindClass(env, CLASS_UNLOCKMUTEX); + if (jUnlockMutexClass == NULL) { return rv; } jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS); + if (jInitArgsClass == NULL) { return rv; } /* convert the CK-type mutex to a Java mutex */ jMutex = ckVoidPtrToJObject(pMutex); /* get the UnlockMutex object out of the jInitArgs object */ fieldID = (*env)->GetFieldID(env, jInitArgsClass, "UnlockMutex", "Lsun/security/pkcs11/wrapper/CK_UNLOCKMUTEX;"); - assert(fieldID != 0); + if (fieldID == NULL) { return rv; } jUnlockMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID); assert(jUnlockMutex != 0); /* call the CK_UNLOCKMUTEX method of the UnLockMutex object */ methodID = (*env)->GetMethodID(env, jUnlockMutexClass, "CK_UNLOCKMUTEX", "(Ljava/lang/Object;)V"); - assert(methodID != 0); + if (methodID == NULL) { return rv; } (*env)->CallVoidMethod(env, jUnlockMutex, methodID, jMutex); - /* check, if callback threw an exception */ pkcs11Exception = (*env)->ExceptionOccurred(env); if (pkcs11Exception != NULL) { + /* TBD: clear the pending exception with ExceptionClear? */ /* The was an exception thrown, now we get the error-code from it */ pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION); + if (pkcs11ExceptionClass == NULL) { return rv; } methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J"); - assert(methodID != 0); + if (methodID == NULL) { return rv; } errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID); rv = jLongToCKULong(errorCode); } diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_objmgmt.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_objmgmt.c index 0fb10f151a0..a72f20d2719 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_objmgmt.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_objmgmt.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -81,16 +81,14 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CreateObject ckSessionHandle = jLongToCKULong(jSessionHandle); jAttributeArrayToCKAttributeArray(env, jTemplate, &ckpAttributes, &ckAttributesLength); + if ((*env)->ExceptionCheck(env)) { return 0L; } rv = (*ckpFunctions->C_CreateObject)(ckSessionHandle, ckpAttributes, ckAttributesLength, &ckObjectHandle); jObjectHandle = ckULongToJLong(ckObjectHandle); - for(i=0; i<ckAttributesLength; i++) - if(ckpAttributes[i].pValue != NULL_PTR) - free(ckpAttributes[i].pValue); - free(ckpAttributes); + freeCKAttributeArray(ckpAttributes, ckAttributesLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } return jObjectHandle ; } @@ -126,14 +124,12 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CopyObject ckSessionHandle = jLongToCKULong(jSessionHandle); ckObjectHandle = jLongToCKULong(jObjectHandle); jAttributeArrayToCKAttributeArray(env, jTemplate, &ckpAttributes, &ckAttributesLength); + if ((*env)->ExceptionCheck(env)) { return 0L; } rv = (*ckpFunctions->C_CopyObject)(ckSessionHandle, ckObjectHandle, ckpAttributes, ckAttributesLength, &ckNewObjectHandle); jNewObjectHandle = ckULongToJLong(ckNewObjectHandle); - for(i=0; i<ckAttributesLength; i++) - if(ckpAttributes[i].pValue != NULL_PTR) - free(ckpAttributes[i].pValue); - free(ckpAttributes); + freeCKAttributeArray(ckpAttributes, ckAttributesLength); if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } @@ -164,7 +160,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DestroyObject ckObjectHandle = jLongToCKULong(jObjectHandle); rv = (*ckpFunctions->C_DestroyObject)(ckSessionHandle, ckObjectHandle); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -194,7 +190,7 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetObjectSize ckObjectHandle = jLongToCKULong(jObjectHandle); rv = (*ckpFunctions->C_GetObjectSize)(ckSessionHandle, ckObjectHandle, &ckObjectSize); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } jObjectSize = ckULongToJLong(ckObjectSize); @@ -221,7 +217,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetAttributeVa CK_ATTRIBUTE_PTR ckpAttributes = NULL_PTR; CK_ULONG ckAttributesLength; CK_ULONG ckBufferLength; - CK_ULONG i; + CK_ULONG i, j; jobject jAttribute; CK_RV rv; @@ -238,19 +234,20 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetAttributeVa ckObjectHandle = jLongToCKULong(jObjectHandle); TRACE1("jAttributeArrayToCKAttributeArray now with jTemplate = %d", jTemplate); jAttributeArrayToCKAttributeArray(env, jTemplate, &ckpAttributes, &ckAttributesLength); + if ((*env)->ExceptionCheck(env)) { return; } + TRACE2("DEBUG: jAttributeArrayToCKAttributeArray finished with ckpAttribute = %d, Length = %d\n", ckpAttributes, ckAttributesLength); /* first set all pValue to NULL, to get the needed buffer length */ for(i = 0; i < ckAttributesLength; i++) { - if(ckpAttributes[i].pValue != NULL_PTR) { + if (ckpAttributes[i].pValue != NULL_PTR) { free(ckpAttributes[i].pValue); + ckpAttributes[i].pValue = NULL_PTR; } } - for (i = 0; i < ckAttributesLength; i++) { - ckpAttributes[i].pValue = NULL_PTR; - } + rv = (*ckpFunctions->C_GetAttributeValue)(ckSessionHandle, ckObjectHandle, ckpAttributes, ckAttributesLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { free(ckpAttributes); return ; } @@ -261,27 +258,34 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetAttributeVa for (i = 0; i < ckAttributesLength; i++) { ckBufferLength = sizeof(CK_BYTE) * ckpAttributes[i].ulValueLen; ckpAttributes[i].pValue = (void *) malloc(ckBufferLength); + if (ckpAttributes[i].pValue == NULL) { + freeCKAttributeArray(ckpAttributes, i); + JNU_ThrowOutOfMemoryError(env, 0); + return; + } ckpAttributes[i].ulValueLen = ckBufferLength; } /* now get the attributes with all values */ rv = (*ckpFunctions->C_GetAttributeValue)(ckSessionHandle, ckObjectHandle, ckpAttributes, ckAttributesLength); - /* copy back the values to the Java attributes */ - for (i = 0; i < ckAttributesLength; i++) { - jAttribute = ckAttributePtrToJAttribute(env, &(ckpAttributes[i])); - (*env)->SetObjectArrayElement(env, jTemplate, i, jAttribute); - } - - for(i=0; i<ckAttributesLength; i++) { - if(ckpAttributes[i].pValue != NULL_PTR) { - free(ckpAttributes[i].pValue); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + /* copy back the values to the Java attributes */ + for (i = 0; i < ckAttributesLength; i++) { + jAttribute = ckAttributePtrToJAttribute(env, &(ckpAttributes[i])); + if (jAttribute == NULL) { + freeCKAttributeArray(ckpAttributes, ckAttributesLength); + return; + } + (*env)->SetObjectArrayElement(env, jTemplate, i, jAttribute); + if ((*env)->ExceptionCheck(env)) { + freeCKAttributeArray(ckpAttributes, ckAttributesLength); + return; + } } } - free(ckpAttributes); + freeCKAttributeArray(ckpAttributes, ckAttributesLength); TRACE0("FINISHED\n"); - - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return ; } } #endif @@ -312,15 +316,11 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SetAttributeVa ckSessionHandle = jLongToCKULong(jSessionHandle); ckObjectHandle = jLongToCKULong(jObjectHandle); jAttributeArrayToCKAttributeArray(env, jTemplate, &ckpAttributes, &ckAttributesLength); + if ((*env)->ExceptionCheck(env)) { return; } rv = (*ckpFunctions->C_SetAttributeValue)(ckSessionHandle, ckObjectHandle, ckpAttributes, ckAttributesLength); - for(i=0; i<ckAttributesLength; i++) { - if(ckpAttributes[i].pValue != NULL_PTR) { - free(ckpAttributes[i].pValue); - } - } - free(ckpAttributes); + freeCKAttributeArray(ckpAttributes, ckAttributesLength); if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } @@ -355,15 +355,11 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1FindObjectsIni ckSessionHandle = jLongToCKULong(jSessionHandle); jAttributeArrayToCKAttributeArray(env, jTemplate, &ckpAttributes, &ckAttributesLength); + if ((*env)->ExceptionCheck(env)) { return; } rv = (*ckpFunctions->C_FindObjectsInit)(ckSessionHandle, ckpAttributes, ckAttributesLength); - for(i=0; i<ckAttributesLength; i++) { - if(ckpAttributes[i].pValue != NULL_PTR) { - free(ckpAttributes[i].pValue); - } - } - free(ckpAttributes); + freeCKAttributeArray(ckpAttributes, ckAttributesLength); TRACE0("FINISHED\n"); if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } @@ -397,14 +393,18 @@ JNIEXPORT jlongArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1FindObje ckSessionHandle = jLongToCKULong(jSessionHandle); ckMaxObjectLength = jLongToCKULong(jMaxObjectCount); ckpObjectHandleArray = (CK_OBJECT_HANDLE_PTR) malloc(sizeof(CK_OBJECT_HANDLE) * ckMaxObjectLength); + if (ckpObjectHandleArray == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_FindObjects)(ckSessionHandle, ckpObjectHandleArray, ckMaxObjectLength, &ckActualObjectCount); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jObjectHandleArray = ckULongArrayToJLongArray(env, ckpObjectHandleArray, ckActualObjectCount); + } - jObjectHandleArray = ckULongArrayToJLongArray(env, ckpObjectHandleArray, ckActualObjectCount); free(ckpObjectHandleArray); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - return jObjectHandleArray ; } #endif diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sessmgmt.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sessmgmt.c index cc2364cd7d9..950b9064170 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sessmgmt.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sessmgmt.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -97,6 +97,10 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1OpenSession #ifndef NO_CALLBACKS if (jNotify != NULL) { notifyEncapsulation = (NotifyEncapsulation *) malloc(sizeof(NotifyEncapsulation)); + if (notifyEncapsulation == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return 0L; + } notifyEncapsulation->jApplicationData = (jApplication != NULL) ? (*env)->NewGlobalRef(env, jApplication) : NULL; @@ -118,7 +122,18 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1OpenSession TRACE0(" ... "); rv = (*ckpFunctions->C_OpenSession)(ckSlotID, ckFlags, ckpApplication, ckNotify, &ckSessionHandle); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return 0L ; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { +#ifndef NO_CALLBACKS + if (notifyEncapsulation != NULL) { + if (notifyEncapsulation->jApplicationData != NULL) { + (*env)->DeleteGlobalRef(env, jApplication); + } + (*env)->DeleteGlobalRef(env, jNotify); + free(notifyEncapsulation); + } +#endif /* NO_CALLBACKS */ + return 0L; + } TRACE0("got session"); TRACE1(", SessionHandle=%u", ckSessionHandle); @@ -163,7 +178,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseSession ckSessionHandle = jLongToCKULong(jSessionHandle); rv = (*ckpFunctions->C_CloseSession)(ckSessionHandle); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } #ifndef NO_CALLBACKS notifyEncapsulation = removeNotifyEntry(env, ckSessionHandle); @@ -208,7 +223,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseAllSessio ckSlotID = jLongToCKULong(jSlotID); rv = (*ckpFunctions->C_CloseAllSessions)(ckSlotID); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } #ifndef NO_CALLBACKS /* Remove all notify callback helper objects. */ @@ -250,10 +265,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetSessionI ckSessionHandle = jLongToCKULong(jSessionHandle); rv = (*ckpFunctions->C_GetSessionInfo)(ckSessionHandle, &ckSessionInfo); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - - jSessionInfo = ckSessionInfoPtrToJSessionInfo(env, &ckSessionInfo); - + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jSessionInfo = ckSessionInfoPtrToJSessionInfo(env, &ckSessionInfo); + } return jSessionInfo ; } #endif @@ -274,7 +288,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetOpera CK_SESSION_HANDLE ckSessionHandle; CK_BYTE_PTR ckpState; CK_ULONG ckStateLength; - jbyteArray jState; + jbyteArray jState = NULL; CK_RV rv; CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); @@ -283,17 +297,20 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetOpera ckSessionHandle = jLongToCKULong(jSessionHandle); rv = (*ckpFunctions->C_GetOperationState)(ckSessionHandle, NULL_PTR, &ckStateLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } ckpState = (CK_BYTE_PTR) malloc(ckStateLength); + if (ckpState == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_GetOperationState)(ckSessionHandle, ckpState, &ckStateLength); - - jState = ckByteArrayToJByteArray(env, ckpState, ckStateLength); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jState = ckByteArrayToJByteArray(env, ckpState, ckStateLength); + } free(ckpState); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - return jState ; } #endif @@ -325,6 +342,8 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SetOperationSt ckSessionHandle = jLongToCKULong(jSessionHandle); jByteArrayToCKByteArray(env, jOperationState, &ckpState, &ckStateLength); + if ((*env)->ExceptionCheck(env)) { return; } + ckEncryptionKeyHandle = jLongToCKULong(jEncryptionKeyHandle); ckAuthenticationKeyHandle = jLongToCKULong(jAuthenticationKeyHandle); @@ -332,7 +351,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SetOperationSt free(ckpState); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -362,12 +381,13 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Login ckSessionHandle = jLongToCKULong(jSessionHandle); ckUserType = jLongToCKULong(jUserType); jCharArrayToCKCharArray(env, jPin, &ckpPinArray, &ckPinLength); + if ((*env)->ExceptionCheck(env)) { return; } rv = (*ckpFunctions->C_Login)(ckSessionHandle, ckUserType, ckpPinArray, ckPinLength); free(ckpPinArray); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -391,7 +411,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Logout ckSessionHandle = jLongToCKULong(jSessionHandle); rv = (*ckpFunctions->C_Logout)(ckSessionHandle); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -410,10 +430,14 @@ void putNotifyEntry(JNIEnv *env, CK_SESSION_HANDLE hSession, NotifyEncapsulation NotifyListNode *currentNode, *newNode; if (notifyEncapsulation == NULL) { - return ; + return; } newNode = (NotifyListNode *) malloc(sizeof(NotifyListNode)); + if (newNode == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } newNode->hSession = hSession; newNode->notifyEncapsulation = notifyEncapsulation; newNode->next = NULL; @@ -578,9 +602,10 @@ CK_RV notifyCallback( jEvent = ckULongToJLong(event); ckNotifyClass = (*env)->FindClass(env, CLASS_NOTIFY); - assert(ckNotifyClass != 0); + if (ckNotifyClass == NULL) { return rv; } jmethod = (*env)->GetMethodID(env, ckNotifyClass, "CK_NOTIFY", "(JJLjava/lang/Object;)V"); - assert(jmethod != 0); + if (jmethod == NULL) { return rv; } + (*env)->CallVoidMethod(env, notifyEncapsulation->jNotifyObject, jmethod, jSessionHandle, jEvent, notifyEncapsulation->jApplicationData); @@ -588,10 +613,14 @@ CK_RV notifyCallback( pkcs11Exception = (*env)->ExceptionOccurred(env); if (pkcs11Exception != NULL) { + /* TBD: clear the pending exception with ExceptionClear? */ /* The was an exception thrown, now we get the error-code from it */ pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION); + if (pkcs11ExceptionClass == NULL) { return rv; } + jmethod = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J"); - assert(jmethod != 0); + if (jmethod == NULL) { return rv; } + errorCode = (*env)->CallLongMethod(env, pkcs11Exception, jmethod); rv = jLongToCKULong(errorCode); } diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sign.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sign.c index 0ac75784c83..e55755d1cf0 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sign.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sign.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -77,15 +77,16 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SignInit ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return; } ckKeyHandle = jLongToCKULong(jKeyHandle); rv = (*ckpFunctions->C_SignInit)(ckSessionHandle, &ckMechanism, ckKeyHandle); - if(ckMechanism.pParameter != NULL_PTR) { + if (ckMechanism.pParameter != NULL_PTR) { free(ckMechanism.pParameter); } - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -117,14 +118,23 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Sign ckSessionHandle = jLongToCKULong(jSessionHandle); jByteArrayToCKByteArray(env, jData, &ckpData, &ckDataLength); + if ((*env)->ExceptionCheck(env)) { return NULL; } /* START standard code */ /* first determine the length of the signature */ rv = (*ckpFunctions->C_Sign)(ckSessionHandle, ckpData, ckDataLength, NULL_PTR, &ckSignatureLength); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + free(ckpData); + return NULL; + } ckpSignature = (CK_BYTE_PTR) malloc(ckSignatureLength * sizeof(CK_BYTE)); + if (ckpSignature == NULL) { + free(ckpData); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } /* now get the signature */ rv = (*ckpFunctions->C_Sign)(ckSessionHandle, ckpData, ckDataLength, ckpSignature, &ckSignatureLength); @@ -134,22 +144,31 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Sign /* START workaround code for operation abort bug in pkcs#11 of Datakey and iButton */ /* ckpSignature = (CK_BYTE_PTR) malloc(256 * sizeof(CK_BYTE)); + if (ckpSignature == NULL) { + free(ckpData); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_Sign)(ckSessionHandle, ckpData, ckDataLength, ckpSignature, &ckSignatureLength); if (rv == CKR_BUFFER_TOO_SMALL) { free(ckpSignature); ckpSignature = (CK_BYTE_PTR) malloc(ckSignatureLength * sizeof(CK_BYTE)); + if (ckpSignature == NULL) { + free(ckpData); + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_Sign)(ckSessionHandle, ckpData, ckDataLength, ckpSignature, &ckSignatureLength); } */ /* END workaround code */ - - jSignature = ckByteArrayToJByteArray(env, ckpSignature, ckSignatureLength); + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { + jSignature = ckByteArrayToJByteArray(env, ckpSignature, ckSignatureLength); + } free(ckpData); free(ckpSignature); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; } - return jSignature ; } #endif @@ -189,14 +208,22 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SignUpdate bufP = BUF; } else { bufLen = min(MAX_HEAP_BUFFER_LEN, jInLen); - bufP = (CK_BYTE_PTR)malloc((size_t)bufLen); + bufP = (CK_BYTE_PTR) malloc((size_t)bufLen); + if (bufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } } while (jInLen > 0) { jsize chunkLen = min(bufLen, jInLen); (*env)->GetByteArrayRegion(env, jIn, jInOfs, chunkLen, (jbyte *)bufP); + if ((*env)->ExceptionCheck(env)) { + if (bufP != BUF) { free(bufP); } + return; + } rv = (*ckpFunctions->C_SignUpdate)(ckSessionHandle, bufP, chunkLen); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { if (bufP != BUF) { free(bufP); } @@ -206,9 +233,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SignUpdate jInLen -= chunkLen; } - if (bufP != BUF) { - free(bufP); - } + if (bufP != BUF) { free(bufP); } } #endif @@ -244,15 +269,18 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SignFina rv = (*ckpFunctions->C_SignFinal)(ckSessionHandle, bufP, &ckSignatureLength); if (rv == CKR_BUFFER_TOO_SMALL) { bufP = (CK_BYTE_PTR) malloc(ckSignatureLength); + if (bufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } rv = (*ckpFunctions->C_SignFinal)(ckSessionHandle, bufP, &ckSignatureLength); } if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { jSignature = ckByteArrayToJByteArray(env, bufP, ckSignatureLength); } - if (bufP != BUF) { - free(bufP); - } + if (bufP != BUF) { free(bufP); } + return jSignature; } #endif @@ -280,11 +308,13 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SignRecoverIni ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return; } + ckKeyHandle = jLongToCKULong(jKeyHandle); rv = (*ckpFunctions->C_SignRecoverInit)(ckSessionHandle, &ckMechanism, ckKeyHandle); - if(ckMechanism.pParameter != NULL_PTR) { + if (ckMechanism.pParameter != NULL_PTR) { free(ckMechanism.pParameter); } @@ -323,26 +353,38 @@ JNIEXPORT jint JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SignRecover if (jInLen <= MAX_STACK_BUFFER_LEN) { inBufP = INBUF; } else { - inBufP = (CK_BYTE_PTR)malloc((size_t)jInLen); + inBufP = (CK_BYTE_PTR) malloc((size_t)jInLen); + if (inBufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } (*env)->GetByteArrayRegion(env, jIn, jInOfs, jInLen, (jbyte *)inBufP); + if ((*env)->ExceptionCheck(env)) { + if (inBufP != INBUF) { free(inBufP); } + return 0; + } rv = (*ckpFunctions->C_SignRecover)(ckSessionHandle, inBufP, jInLen, outBufP, &ckSignatureLength); /* re-alloc larger buffer if it fits into our Java buffer */ if ((rv == CKR_BUFFER_TOO_SMALL) && (ckSignatureLength <= jIntToCKULong(jOutLen))) { outBufP = (CK_BYTE_PTR) malloc(ckSignatureLength); + if (outBufP == NULL) { + if (inBufP != INBUF) { + free(inBufP); + } + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } rv = (*ckpFunctions->C_SignRecover)(ckSessionHandle, inBufP, jInLen, outBufP, &ckSignatureLength); } if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { (*env)->SetByteArrayRegion(env, jOut, jOutOfs, ckSignatureLength, (jbyte *)outBufP); } - if (inBufP != INBUF) { - free(inBufP); - } - if (outBufP != OUTBUF) { - free(outBufP); - } + if (inBufP != INBUF) { free(inBufP); } + if (outBufP != OUTBUF) { free(outBufP); } + return ckSignatureLength; } #endif @@ -370,6 +412,8 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1VerifyInit ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return; } + ckKeyHandle = jLongToCKULong(jKeyHandle); rv = (*ckpFunctions->C_VerifyInit)(ckSessionHandle, &ckMechanism, ckKeyHandle); @@ -378,7 +422,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1VerifyInit free(ckMechanism.pParameter); } - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -409,7 +453,13 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Verify ckSessionHandle = jLongToCKULong(jSessionHandle); jByteArrayToCKByteArray(env, jData, &ckpData, &ckDataLength); + if ((*env)->ExceptionCheck(env)) { return; } + jByteArrayToCKByteArray(env, jSignature, &ckpSignature, &ckSignatureLength); + if ((*env)->ExceptionCheck(env)) { + free(ckpData); + return; + } /* verify the signature */ rv = (*ckpFunctions->C_Verify)(ckSessionHandle, ckpData, ckDataLength, ckpSignature, ckSignatureLength); @@ -417,7 +467,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Verify free(ckpData); free(ckpSignature); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -456,26 +506,31 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1VerifyUpdate bufP = BUF; } else { bufLen = min(MAX_HEAP_BUFFER_LEN, jInLen); - bufP = (CK_BYTE_PTR)malloc((size_t)bufLen); + bufP = (CK_BYTE_PTR) malloc((size_t)bufLen); + if (bufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } } while (jInLen > 0) { jsize chunkLen = min(bufLen, jInLen); (*env)->GetByteArrayRegion(env, jIn, jInOfs, chunkLen, (jbyte *)bufP); + if ((*env)->ExceptionCheck(env)) { + if (bufP != BUF) { free(bufP); } + return; + } + rv = (*ckpFunctions->C_VerifyUpdate)(ckSessionHandle, bufP, chunkLen); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { - if (bufP != BUF) { - free(bufP); - } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + if (bufP != BUF) { free(bufP); } return; } jInOfs += chunkLen; jInLen -= chunkLen; } - if (bufP != BUF) { - free(bufP); - } + if (bufP != BUF) { free(bufP); } } #endif @@ -502,13 +557,14 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1VerifyFinal ckSessionHandle = jLongToCKULong(jSessionHandle); jByteArrayToCKByteArray(env, jSignature, &ckpSignature, &ckSignatureLength); + if ((*env)->ExceptionCheck(env)) { return; } /* verify the signature */ rv = (*ckpFunctions->C_VerifyFinal)(ckSessionHandle, ckpSignature, ckSignatureLength); free(ckpSignature); - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -535,15 +591,17 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1VerifyRecoverI ckSessionHandle = jLongToCKULong(jSessionHandle); jMechanismToCKMechanism(env, jMechanism, &ckMechanism); + if ((*env)->ExceptionCheck(env)) { return; } + ckKeyHandle = jLongToCKULong(jKeyHandle); rv = (*ckpFunctions->C_VerifyRecoverInit)(ckSessionHandle, &ckMechanism, ckKeyHandle); - if(ckMechanism.pParameter != NULL_PTR) { + if (ckMechanism.pParameter != NULL_PTR) { free(ckMechanism.pParameter); } - if(ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; } } #endif @@ -578,26 +636,38 @@ JNIEXPORT jint JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1VerifyRecover if (jInLen <= MAX_STACK_BUFFER_LEN) { inBufP = INBUF; } else { - inBufP = (CK_BYTE_PTR)malloc((size_t)jInLen); + inBufP = (CK_BYTE_PTR) malloc((size_t)jInLen); + if (inBufP == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } } (*env)->GetByteArrayRegion(env, jIn, jInOfs, jInLen, (jbyte *)inBufP); + if ((*env)->ExceptionCheck(env)) { + if (inBufP != INBUF) { free(inBufP); } + return 0; + } + rv = (*ckpFunctions->C_VerifyRecover)(ckSessionHandle, inBufP, jInLen, outBufP, &ckDataLength); + /* re-alloc larger buffer if it fits into our Java buffer */ if ((rv == CKR_BUFFER_TOO_SMALL) && (ckDataLength <= jIntToCKULong(jOutLen))) { outBufP = (CK_BYTE_PTR) malloc(ckDataLength); + if (outBufP == NULL) { + if (inBufP != INBUF) { free(inBufP); } + JNU_ThrowOutOfMemoryError(env, 0); + return 0; + } rv = (*ckpFunctions->C_VerifyRecover)(ckSessionHandle, inBufP, jInLen, outBufP, &ckDataLength); } if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { (*env)->SetByteArrayRegion(env, jOut, jOutOfs, ckDataLength, (jbyte *)outBufP); } - if (inBufP != INBUF) { - free(inBufP); - } - if (outBufP != OUTBUF) { - free(outBufP); - } + if (inBufP != INBUF) { free(inBufP); } + if (outBufP != OUTBUF) { free(outBufP); } + return ckDataLength; } #endif diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c index 2276cb101c5..d4c12a06baa 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -73,11 +73,11 @@ jobject createLockObject(JNIEnv *env) { jmethodID jConstructor; jObjectClass = (*env)->FindClass(env, "java/lang/Object"); - assert(jObjectClass != 0); + if (jObjectClass == NULL) { return NULL; } jConstructor = (*env)->GetMethodID(env, jObjectClass, "<init>", "()V"); - assert(jConstructor != 0); + if (jConstructor == NULL) { return NULL; } jLockObject = (*env)->NewObject(env, jObjectClass, jConstructor); - assert(jLockObject != 0); + if (jLockObject == NULL) { return NULL; } jLockObject = (*env)->NewGlobalRef(env, jLockObject); return jLockObject ; @@ -200,84 +200,30 @@ jlong ckAssertReturnValueOK(JNIEnv *env, CK_RV returnValue) return 0L ; } else { jPKCS11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION); - assert(jPKCS11ExceptionClass != 0); - jConstructor = (*env)->GetMethodID(env, jPKCS11ExceptionClass, "<init>", "(J)V"); - assert(jConstructor != 0); - jErrorCode = ckULongToJLong(returnValue); - jPKCS11Exception = (jthrowable) (*env)->NewObject(env, jPKCS11ExceptionClass, jConstructor, jErrorCode); - (*env)->Throw(env, jPKCS11Exception); + if (jPKCS11ExceptionClass != NULL) { + jConstructor = (*env)->GetMethodID(env, jPKCS11ExceptionClass, "<init>", "(J)V"); + if (jConstructor != NULL) { + jErrorCode = ckULongToJLong(returnValue); + jPKCS11Exception = (jthrowable) (*env)->NewObject(env, jPKCS11ExceptionClass, jConstructor, jErrorCode); + if (jPKCS11Exception != NULL) { + (*env)->Throw(env, jPKCS11Exception); + } + } + } + (*env)->DeleteLocalRef(env, jPKCS11ExceptionClass); return jErrorCode ; } } /* - * this function simply throws a FileNotFoundException - * - * @param env Used to call JNI funktions and to get the Exception class. - * @param jmessage The message string of the Exception object. - */ -void throwFileNotFoundException(JNIEnv *env, jstring jmessage) -{ - jclass jFileNotFoundExceptionClass; - jmethodID jConstructor; - jthrowable jFileNotFoundException; - - jFileNotFoundExceptionClass = (*env)->FindClass(env, CLASS_FILE_NOT_FOUND_EXCEPTION); - assert(jFileNotFoundExceptionClass != 0); - - jConstructor = (*env)->GetMethodID(env, jFileNotFoundExceptionClass, "<init>", "(Ljava/lang/String;)V"); - assert(jConstructor != 0); - jFileNotFoundException = (jthrowable) (*env)->NewObject(env, jFileNotFoundExceptionClass, jConstructor, jmessage); - (*env)->Throw(env, jFileNotFoundException); -} - -/* - * this function simply throws an IOException + * This function simply throws an IOException * * @param env Used to call JNI funktions and to get the Exception class. * @param message The message string of the Exception object. */ -void throwIOException(JNIEnv *env, const char * message) +void throwIOException(JNIEnv *env, const char *message) { - jclass jIOExceptionClass; - - jIOExceptionClass = (*env)->FindClass(env, CLASS_IO_EXCEPTION); - assert(jIOExceptionClass != 0); - - (*env)->ThrowNew(env, jIOExceptionClass, message); -} - -/* - * this function simply throws an IOException and takes a unicode - * messge. - * - * @param env Used to call JNI funktions and to get the Exception class. - * @param message The unicode message string of the Exception object. - */ -void throwIOExceptionUnicodeMessage(JNIEnv *env, const short *message) -{ - jclass jIOExceptionClass; - jmethodID jConstructor; - jthrowable jIOException; - jstring jmessage; - jsize length; - short *currentCharacter; - - jIOExceptionClass = (*env)->FindClass(env, CLASS_IO_EXCEPTION); - assert(jIOExceptionClass != 0); - - length = 0; - if (message != NULL) { - currentCharacter = (short *) message; - while (*(currentCharacter++) != 0) length++; - } - - jmessage = (*env)->NewString(env, (const jchar *)message, length); - - jConstructor = (*env)->GetMethodID(env, jIOExceptionClass, "<init>", "(Ljava/lang/String;)V"); - assert(jConstructor != 0); - jIOException = (jthrowable) (*env)->NewObject(env, jIOExceptionClass, jConstructor, jmessage); - (*env)->Throw(env, jIOException); + JNU_ThrowByName(env, CLASS_IO_EXCEPTION, message); } /* @@ -288,26 +234,9 @@ void throwIOExceptionUnicodeMessage(JNIEnv *env, const short *message) * @param env Used to call JNI funktions and to get the Exception class. * @param jmessage The message string of the Exception object. */ -void throwPKCS11RuntimeException(JNIEnv *env, jstring jmessage) +void throwPKCS11RuntimeException(JNIEnv *env, const char *message) { - jclass jPKCS11RuntimeExceptionClass; - jmethodID jConstructor; - jthrowable jPKCS11RuntimeException; - - jPKCS11RuntimeExceptionClass = (*env)->FindClass(env, CLASS_PKCS11RUNTIMEEXCEPTION); - assert(jPKCS11RuntimeExceptionClass != 0); - - if (jmessage == NULL) { - jConstructor = (*env)->GetMethodID(env, jPKCS11RuntimeExceptionClass, "<init>", "()V"); - assert(jConstructor != 0); - jPKCS11RuntimeException = (jthrowable) (*env)->NewObject(env, jPKCS11RuntimeExceptionClass, jConstructor); - (*env)->Throw(env, jPKCS11RuntimeException); - } else { - jConstructor = (*env)->GetMethodID(env, jPKCS11RuntimeExceptionClass, "<init>", "(Ljava/lang/String;)V"); - assert(jConstructor != 0); - jPKCS11RuntimeException = (jthrowable) (*env)->NewObject(env, jPKCS11RuntimeExceptionClass, jConstructor, jmessage); - (*env)->Throw(env, jPKCS11RuntimeException); - } + JNU_ThrowByName(env, CLASS_PKCS11RUNTIMEEXCEPTION, message); } /* @@ -318,9 +247,24 @@ void throwPKCS11RuntimeException(JNIEnv *env, jstring jmessage) */ void throwDisconnectedRuntimeException(JNIEnv *env) { - jstring jExceptionMessage = (*env)->NewStringUTF(env, "This object is not connected to a module."); + throwPKCS11RuntimeException(env, "This object is not connected to a module."); +} - throwPKCS11RuntimeException(env, jExceptionMessage); +/* This function frees the specified CK_ATTRIBUTE array. + * + * @param attrPtr pointer to the to-be-freed CK_ATTRIBUTE array. + * @param len the length of the array + */ +void freeCKAttributeArray(CK_ATTRIBUTE_PTR attrPtr, int len) +{ + int i; + + for (i=0; i<len; i++) { + if (attrPtr[i].pValue != NULL_PTR) { + free(attrPtr[i].pValue); + } + } + free(attrPtr); } /* @@ -375,8 +319,22 @@ void jBooleanArrayToCKBBoolArray(JNIEnv *env, const jbooleanArray jArray, CK_BBO } *ckpLength = (*env)->GetArrayLength(env, jArray); jpTemp = (jboolean*) malloc((*ckpLength) * sizeof(jboolean)); + if (jpTemp == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } (*env)->GetBooleanArrayRegion(env, jArray, 0, *ckpLength, jpTemp); + if ((*env)->ExceptionCheck(env)) { + free(jpTemp); + return; + } + *ckpArray = (CK_BBOOL*) malloc ((*ckpLength) * sizeof(CK_BBOOL)); + if (*ckpArray == NULL) { + free(jpTemp); + JNU_ThrowOutOfMemoryError(env, 0); + return; + } for (i=0; i<(*ckpLength); i++) { (*ckpArray)[i] = jBooleanToCKBBool(jpTemp[i]); } @@ -403,13 +361,26 @@ void jByteArrayToCKByteArray(JNIEnv *env, const jbyteArray jArray, CK_BYTE_PTR * } *ckpLength = (*env)->GetArrayLength(env, jArray); jpTemp = (jbyte*) malloc((*ckpLength) * sizeof(jbyte)); + if (jpTemp == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } (*env)->GetByteArrayRegion(env, jArray, 0, *ckpLength, jpTemp); + if ((*env)->ExceptionCheck(env)) { + free(jpTemp); + return; + } /* if CK_BYTE is the same size as jbyte, we save an additional copy */ if (sizeof(CK_BYTE) == sizeof(jbyte)) { *ckpArray = (CK_BYTE_PTR) jpTemp; } else { *ckpArray = (CK_BYTE_PTR) malloc ((*ckpLength) * sizeof(CK_BYTE)); + if (*ckpArray == NULL) { + free(jpTemp); + JNU_ThrowOutOfMemoryError(env, 0); + return; + } for (i=0; i<(*ckpLength); i++) { (*ckpArray)[i] = jByteToCKByte(jpTemp[i]); } @@ -437,8 +408,22 @@ void jLongArrayToCKULongArray(JNIEnv *env, const jlongArray jArray, CK_ULONG_PTR } *ckpLength = (*env)->GetArrayLength(env, jArray); jTemp = (jlong*) malloc((*ckpLength) * sizeof(jlong)); + if (jTemp == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } (*env)->GetLongArrayRegion(env, jArray, 0, *ckpLength, jTemp); + if ((*env)->ExceptionCheck(env)) { + free(jTemp); + return; + } + *ckpArray = (CK_ULONG_PTR) malloc (*ckpLength * sizeof(CK_ULONG)); + if (*ckpArray == NULL) { + free(jTemp); + JNU_ThrowOutOfMemoryError(env, 0); + return; + } for (i=0; i<(*ckpLength); i++) { (*ckpArray)[i] = jLongToCKULong(jTemp[i]); } @@ -465,8 +450,22 @@ void jCharArrayToCKCharArray(JNIEnv *env, const jcharArray jArray, CK_CHAR_PTR * } *ckpLength = (*env)->GetArrayLength(env, jArray); jpTemp = (jchar*) malloc((*ckpLength) * sizeof(jchar)); + if (jpTemp == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } (*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jpTemp); + if ((*env)->ExceptionCheck(env)) { + free(jpTemp); + return; + } + *ckpArray = (CK_CHAR_PTR) malloc (*ckpLength * sizeof(CK_CHAR)); + if (*ckpArray == NULL) { + free(jpTemp); + JNU_ThrowOutOfMemoryError(env, 0); + return; + } for (i=0; i<(*ckpLength); i++) { (*ckpArray)[i] = jCharToCKChar(jpTemp[i]); } @@ -493,8 +492,22 @@ void jCharArrayToCKUTF8CharArray(JNIEnv *env, const jcharArray jArray, CK_UTF8CH } *ckpLength = (*env)->GetArrayLength(env, jArray); jTemp = (jchar*) malloc((*ckpLength) * sizeof(jchar)); + if (jTemp == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } (*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jTemp); + if ((*env)->ExceptionCheck(env)) { + free(jTemp); + return; + } + *ckpArray = (CK_UTF8CHAR_PTR) malloc (*ckpLength * sizeof(CK_UTF8CHAR)); + if (*ckpArray == NULL) { + free(jTemp); + JNU_ThrowOutOfMemoryError(env, 0); + return; + } for (i=0; i<(*ckpLength); i++) { (*ckpArray)[i] = jCharToCKUTF8Char(jTemp[i]); } @@ -521,8 +534,15 @@ void jStringToCKUTF8CharArray(JNIEnv *env, const jstring jArray, CK_UTF8CHAR_PTR } pCharArray = (*env)->GetStringUTFChars(env, jArray, &isCopy); + if (pCharArray == NULL) { return; } + *ckpLength = strlen(pCharArray); *ckpArray = (CK_UTF8CHAR_PTR) malloc((*ckpLength + 1) * sizeof(CK_UTF8CHAR)); + if (*ckpArray == NULL) { + (*env)->ReleaseStringUTFChars(env, (jstring) jArray, pCharArray); + JNU_ThrowOutOfMemoryError(env, 0); + return; + } strcpy((char*)*ckpArray, pCharArray); (*env)->ReleaseStringUTFChars(env, (jstring) jArray, pCharArray); } @@ -552,55 +572,36 @@ void jAttributeArrayToCKAttributeArray(JNIEnv *env, jobjectArray jArray, CK_ATTR jLength = (*env)->GetArrayLength(env, jArray); *ckpLength = jLongToCKULong(jLength); *ckpArray = (CK_ATTRIBUTE_PTR) malloc(*ckpLength * sizeof(CK_ATTRIBUTE)); + if (*ckpArray == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return; + } TRACE1(", converting %d attibutes", jLength); for (i=0; i<(*ckpLength); i++) { TRACE1(", getting %d. attibute", i); jAttribute = (*env)->GetObjectArrayElement(env, jArray, i); + if ((*env)->ExceptionCheck(env)) { + freeCKAttributeArray(*ckpArray, i); + return; + } TRACE1(", jAttribute = %d", jAttribute); TRACE1(", converting %d. attibute", i); (*ckpArray)[i] = jAttributeToCKAttribute(env, jAttribute); + if ((*env)->ExceptionCheck(env)) { + freeCKAttributeArray(*ckpArray, i); + return; + } } TRACE0("FINISHED\n"); } -/* - * converts a jobjectArray to a CK_VOID_PTR array. The allocated memory has to be freed after - * use! - * NOTE: this function does not work and is not used yet - * - * @param env - used to call JNI funktions to get the array informtaion - * @param jArray - the Java object array to convert - * @param ckpArray - the reference, where the pointer to the new CK_VOID_PTR array will be stored - * @param ckpLength - the reference, where the array length will be stored - */ -/* -void jObjectArrayToCKVoidPtrArray(JNIEnv *env, const jobjectArray jArray, CK_VOID_PTR_PTR *ckpArray, CK_ULONG_PTR ckpLength) -{ - jobject jTemp; - CK_ULONG i; - - if(jArray == NULL) { - *ckpArray = NULL_PTR; - *ckpLength = 0L; - return; - } - *ckpLength = (*env)->GetArrayLength(env, jArray); - *ckpArray = (CK_VOID_PTR_PTR) malloc (*ckpLength * sizeof(CK_VOID_PTR)); - for (i=0; i<(*ckpLength); i++) { - jTemp = (*env)->GetObjectArrayElement(env, jArray, i); - (*ckpArray)[i] = jObjectToCKVoidPtr(jTemp); - } - free(jTemp); -} -*/ - /* * converts a CK_BYTE array and its length to a jbyteArray. * * @param env - used to call JNI funktions to create the new Java array * @param ckpArray - the pointer to the CK_BYTE array to convert * @param ckpLength - the length of the array to convert - * @return - the new Java byte array + * @return - the new Java byte array or NULL if error occurred */ jbyteArray ckByteArrayToJByteArray(JNIEnv *env, const CK_BYTE_PTR ckpArray, CK_ULONG ckLength) { @@ -613,18 +614,22 @@ jbyteArray ckByteArrayToJByteArray(JNIEnv *env, const CK_BYTE_PTR ckpArray, CK_U jpTemp = (jbyte*) ckpArray; } else { jpTemp = (jbyte*) malloc((ckLength) * sizeof(jbyte)); + if (jpTemp == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } for (i=0; i<ckLength; i++) { jpTemp[i] = ckByteToJByte(ckpArray[i]); } } jArray = (*env)->NewByteArray(env, ckULongToJSize(ckLength)); - (*env)->SetByteArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); - - if (sizeof(CK_BYTE) != sizeof(jbyte)) { - free(jpTemp); + if (jArray != NULL) { + (*env)->SetByteArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); } + if (sizeof(CK_BYTE) != sizeof(jbyte)) { free(jpTemp); } + return jArray ; } @@ -643,11 +648,17 @@ jlongArray ckULongArrayToJLongArray(JNIEnv *env, const CK_ULONG_PTR ckpArray, CK jlongArray jArray; jpTemp = (jlong*) malloc((ckLength) * sizeof(jlong)); + if (jpTemp == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } for (i=0; i<ckLength; i++) { jpTemp[i] = ckLongToJLong(ckpArray[i]); } jArray = (*env)->NewLongArray(env, ckULongToJSize(ckLength)); - (*env)->SetLongArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + if (jArray != NULL) { + (*env)->SetLongArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + } free(jpTemp); return jArray ; @@ -668,11 +679,17 @@ jcharArray ckCharArrayToJCharArray(JNIEnv *env, const CK_CHAR_PTR ckpArray, CK_U jcharArray jArray; jpTemp = (jchar*) malloc(ckLength * sizeof(jchar)); + if (jpTemp == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } for (i=0; i<ckLength; i++) { jpTemp[i] = ckCharToJChar(ckpArray[i]); } jArray = (*env)->NewCharArray(env, ckULongToJSize(ckLength)); - (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + if (jArray != NULL) { + (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + } free(jpTemp); return jArray ; @@ -693,11 +710,17 @@ jcharArray ckUTF8CharArrayToJCharArray(JNIEnv *env, const CK_UTF8CHAR_PTR ckpArr jcharArray jArray; jpTemp = (jchar*) malloc(ckLength * sizeof(jchar)); + if (jpTemp == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } for (i=0; i<ckLength; i++) { jpTemp[i] = ckUTF8CharToJChar(ckpArray[i]); } jArray = (*env)->NewCharArray(env, ckULongToJSize(ckLength)); - (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + if (jArray != NULL) { + (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + } free(jpTemp); return jArray ; @@ -736,12 +759,11 @@ jobject ckBBoolPtrToJBooleanObject(JNIEnv *env, const CK_BBOOL *ckpValue) jboolean jValue; jValueObjectClass = (*env)->FindClass(env, "java/lang/Boolean"); - assert(jValueObjectClass != 0); + if (jValueObjectClass == NULL) { return NULL; } jConstructor = (*env)->GetMethodID(env, jValueObjectClass, "<init>", "(Z)V"); - assert(jConstructor != 0); + if (jConstructor == NULL) { return NULL; } jValue = ckBBoolToJBoolean(*ckpValue); jValueObject = (*env)->NewObject(env, jValueObjectClass, jConstructor, jValue); - assert(jValueObject != 0); return jValueObject ; } @@ -761,12 +783,11 @@ jobject ckULongPtrToJLongObject(JNIEnv *env, const CK_ULONG_PTR ckpValue) jlong jValue; jValueObjectClass = (*env)->FindClass(env, "java/lang/Long"); - assert(jValueObjectClass != 0); + if (jValueObjectClass == NULL) { return NULL; } jConstructor = (*env)->GetMethodID(env, jValueObjectClass, "<init>", "(J)V"); - assert(jConstructor != 0); + if (jConstructor == NULL) { return NULL; } jValue = ckULongToJLong(*ckpValue); jValueObject = (*env)->NewObject(env, jValueObjectClass, jConstructor, jValue); - assert(jValueObject != 0); return jValueObject ; } @@ -787,11 +808,15 @@ CK_BBOOL* jBooleanObjectToCKBBoolPtr(JNIEnv *env, jobject jObject) CK_BBOOL *ckpValue; jObjectClass = (*env)->FindClass(env, "java/lang/Boolean"); - assert(jObjectClass != 0); + if (jObjectClass == NULL) { return NULL; } jValueMethod = (*env)->GetMethodID(env, jObjectClass, "booleanValue", "()Z"); - assert(jValueMethod != 0); + if (jValueMethod == NULL) { return NULL; } jValue = (*env)->CallBooleanMethod(env, jObject, jValueMethod); ckpValue = (CK_BBOOL *) malloc(sizeof(CK_BBOOL)); + if (ckpValue == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } *ckpValue = jBooleanToCKBBool(jValue); return ckpValue ; @@ -813,13 +838,16 @@ CK_BYTE_PTR jByteObjectToCKBytePtr(JNIEnv *env, jobject jObject) CK_BYTE_PTR ckpValue; jObjectClass = (*env)->FindClass(env, "java/lang/Byte"); - assert(jObjectClass != 0); + if (jObjectClass == NULL) { return NULL; } jValueMethod = (*env)->GetMethodID(env, jObjectClass, "byteValue", "()B"); - assert(jValueMethod != 0); + if (jValueMethod == NULL) { return NULL; } jValue = (*env)->CallByteMethod(env, jObject, jValueMethod); ckpValue = (CK_BYTE_PTR) malloc(sizeof(CK_BYTE)); + if (ckpValue == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } *ckpValue = jByteToCKByte(jValue); - return ckpValue ; } @@ -839,13 +867,16 @@ CK_ULONG* jIntegerObjectToCKULongPtr(JNIEnv *env, jobject jObject) CK_ULONG *ckpValue; jObjectClass = (*env)->FindClass(env, "java/lang/Integer"); - assert(jObjectClass != 0); + if (jObjectClass == NULL) { return NULL; } jValueMethod = (*env)->GetMethodID(env, jObjectClass, "intValue", "()I"); - assert(jValueMethod != 0); + if (jValueMethod == NULL) { return NULL; } jValue = (*env)->CallIntMethod(env, jObject, jValueMethod); ckpValue = (CK_ULONG *) malloc(sizeof(CK_ULONG)); + if (ckpValue == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } *ckpValue = jLongToCKLong(jValue); - return ckpValue ; } @@ -865,11 +896,15 @@ CK_ULONG* jLongObjectToCKULongPtr(JNIEnv *env, jobject jObject) CK_ULONG *ckpValue; jObjectClass = (*env)->FindClass(env, "java/lang/Long"); - assert(jObjectClass != 0); + if (jObjectClass == NULL) { return NULL; } jValueMethod = (*env)->GetMethodID(env, jObjectClass, "longValue", "()J"); - assert(jValueMethod != 0); + if (jValueMethod == NULL) { return NULL; } jValue = (*env)->CallLongMethod(env, jObject, jValueMethod); ckpValue = (CK_ULONG *) malloc(sizeof(CK_ULONG)); + if (ckpValue == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } *ckpValue = jLongToCKULong(jValue); return ckpValue ; @@ -891,11 +926,15 @@ CK_CHAR_PTR jCharObjectToCKCharPtr(JNIEnv *env, jobject jObject) CK_CHAR_PTR ckpValue; jObjectClass = (*env)->FindClass(env, "java/lang/Char"); - assert(jObjectClass != 0); + if (jObjectClass == NULL) { return NULL; } jValueMethod = (*env)->GetMethodID(env, jObjectClass, "charValue", "()C"); - assert(jValueMethod != 0); + if (jValueMethod == NULL) { return NULL; } jValue = (*env)->CallCharMethod(env, jObject, jValueMethod); ckpValue = (CK_CHAR_PTR) malloc(sizeof(CK_CHAR)); + if (ckpValue == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return NULL; + } *ckpValue = jCharToCKChar(jValue); return ckpValue ; @@ -913,124 +952,172 @@ CK_CHAR_PTR jCharObjectToCKCharPtr(JNIEnv *env, jobject jObject) */ void jObjectToPrimitiveCKObjectPtrPtr(JNIEnv *env, jobject jObject, CK_VOID_PTR *ckpObjectPtr, CK_ULONG *ckpLength) { - jclass jBooleanClass = (*env)->FindClass(env, "java/lang/Boolean"); - jclass jByteClass = (*env)->FindClass(env, "java/lang/Byte"); - jclass jCharacterClass = (*env)->FindClass(env, "java/lang/Character"); - jclass jClassClass = (*env)->FindClass(env, "java/lang/Class"); - /* jclass jShortClass = (*env)->FindClass(env, "java/lang/Short"); */ - jclass jIntegerClass = (*env)->FindClass(env, "java/lang/Integer"); - jclass jLongClass = (*env)->FindClass(env, "java/lang/Long"); - /* jclass jFloatClass = (*env)->FindClass(env, "java/lang/Float"); */ - /* jclass jDoubleClass = (*env)->FindClass(env, "java/lang/Double"); */ - jclass jDateClass = (*env)->FindClass(env, CLASS_DATE); - jclass jStringClass = (*env)->FindClass(env, "java/lang/String"); - jclass jStringBufferClass = (*env)->FindClass(env, "java/lang/StringBuffer"); - jclass jBooleanArrayClass = (*env)->FindClass(env, "[Z"); - jclass jByteArrayClass = (*env)->FindClass(env, "[B"); - jclass jCharArrayClass = (*env)->FindClass(env, "[C"); - /* jclass jShortArrayClass = (*env)->FindClass(env, "[S"); */ - jclass jIntArrayClass = (*env)->FindClass(env, "[I"); - jclass jLongArrayClass = (*env)->FindClass(env, "[J"); - /* jclass jFloatArrayClass = (*env)->FindClass(env, "[F"); */ - /* jclass jDoubleArrayClass = (*env)->FindClass(env, "[D"); */ - jclass jObjectClass = (*env)->FindClass(env, "java/lang/Object"); - /* jclass jObjectArrayClass = (*env)->FindClass(env, "[java/lang/Object"); */ - /* ATTENTION: jObjectArrayClass is always NULL !! */ - /* CK_ULONG ckArrayLength; */ - /* CK_VOID_PTR *ckpElementObject; */ - /* CK_ULONG ckElementLength; */ - /* CK_ULONG i; */ + jclass jLongClass, jBooleanClass, jByteArrayClass, jCharArrayClass; + jclass jByteClass, jDateClass, jCharacterClass, jIntegerClass; + jclass jBooleanArrayClass, jIntArrayClass, jLongArrayClass; + jclass jStringClass; + jclass jObjectClass, jClassClass; CK_VOID_PTR ckpVoid = *ckpObjectPtr; jmethodID jMethod; jobject jClassObject; jstring jClassNameString; - jstring jExceptionMessagePrefix; - jobject jExceptionMessageStringBuffer; - jstring jExceptionMessage; + char *classNameString, *exceptionMsgPrefix, *exceptionMsg; TRACE0("\nDEBUG: jObjectToPrimitiveCKObjectPtrPtr"); if (jObject == NULL) { *ckpObjectPtr = NULL; *ckpLength = 0; - } else if ((*env)->IsInstanceOf(env, jObject, jLongClass)) { + return; + } + + jLongClass = (*env)->FindClass(env, "java/lang/Long"); + if (jLongClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jLongClass)) { *ckpObjectPtr = jLongObjectToCKULongPtr(env, jObject); *ckpLength = sizeof(CK_ULONG); TRACE1("<converted long value %X>", *((CK_ULONG *) *ckpObjectPtr)); - } else if ((*env)->IsInstanceOf(env, jObject, jBooleanClass)) { + return; + } + + jBooleanClass = (*env)->FindClass(env, "java/lang/Boolean"); + if (jBooleanClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jBooleanClass)) { *ckpObjectPtr = jBooleanObjectToCKBBoolPtr(env, jObject); *ckpLength = sizeof(CK_BBOOL); TRACE0(" <converted boolean value "); TRACE0((*((CK_BBOOL *) *ckpObjectPtr) == TRUE) ? "TRUE>" : "FALSE>"); - } else if ((*env)->IsInstanceOf(env, jObject, jByteArrayClass)) { + return; + } + + jByteArrayClass = (*env)->FindClass(env, "[B"); + if (jByteArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jByteArrayClass)) { jByteArrayToCKByteArray(env, jObject, (CK_BYTE_PTR*)ckpObjectPtr, ckpLength); - } else if ((*env)->IsInstanceOf(env, jObject, jCharArrayClass)) { + return; + } + + jCharArrayClass = (*env)->FindClass(env, "[C"); + if (jCharArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jCharArrayClass)) { jCharArrayToCKUTF8CharArray(env, jObject, (CK_UTF8CHAR_PTR*)ckpObjectPtr, ckpLength); - } else if ((*env)->IsInstanceOf(env, jObject, jByteClass)) { + return; + } + + jByteClass = (*env)->FindClass(env, "java/lang/Byte"); + if (jByteClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jByteClass)) { *ckpObjectPtr = jByteObjectToCKBytePtr(env, jObject); *ckpLength = sizeof(CK_BYTE); TRACE1("<converted byte value %X>", *((CK_BYTE *) *ckpObjectPtr)); - } else if ((*env)->IsInstanceOf(env, jObject, jDateClass)) { + return; + } + + jDateClass = (*env)->FindClass(env, CLASS_DATE); + if (jDateClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jDateClass)) { *ckpObjectPtr = jDateObjectPtrToCKDatePtr(env, jObject); *ckpLength = sizeof(CK_DATE); - TRACE3("<converted date value %.4s-%.2s-%.2s>", (*((CK_DATE *) *ckpObjectPtr)).year, - (*((CK_DATE *) *ckpObjectPtr)).month, - (*((CK_DATE *) *ckpObjectPtr)).day); - } else if ((*env)->IsInstanceOf(env, jObject, jCharacterClass)) { + TRACE3("<converted date value %.4s-%.2s-%.2s>", (*((CK_DATE *) *ckpObjectPtr)).year, (*((CK_DATE *) *ckpObjectPtr)).month, (*((CK_DATE *) *ckpObjectPtr)).day); + return; + } + + jCharacterClass = (*env)->FindClass(env, "java/lang/Character"); + if (jCharacterClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jCharacterClass)) { *ckpObjectPtr = jCharObjectToCKCharPtr(env, jObject); *ckpLength = sizeof(CK_UTF8CHAR); TRACE1("<converted char value %c>", *((CK_CHAR *) *ckpObjectPtr)); - } else if ((*env)->IsInstanceOf(env, jObject, jIntegerClass)) { + return; + } + + jIntegerClass = (*env)->FindClass(env, "java/lang/Integer"); + if (jIntegerClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jIntegerClass)) { *ckpObjectPtr = jIntegerObjectToCKULongPtr(env, jObject); *ckpLength = sizeof(CK_ULONG); TRACE1("<converted integer value %X>", *((CK_ULONG *) *ckpObjectPtr)); - } else if ((*env)->IsInstanceOf(env, jObject, jBooleanArrayClass)) { - jBooleanArrayToCKBBoolArray(env, jObject, (CK_BBOOL**)ckpObjectPtr, ckpLength); - } else if ((*env)->IsInstanceOf(env, jObject, jIntArrayClass)) { - jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*)ckpObjectPtr, ckpLength); - } else if ((*env)->IsInstanceOf(env, jObject, jLongArrayClass)) { - jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*)ckpObjectPtr, ckpLength); - } else if ((*env)->IsInstanceOf(env, jObject, jStringClass)) { - jStringToCKUTF8CharArray(env, jObject, (CK_UTF8CHAR_PTR*)ckpObjectPtr, ckpLength); - - /* a Java object array is not used by CK_ATTRIBUTE by now... */ -/* } else if ((*env)->IsInstanceOf(env, jObject, jObjectArrayClass)) { - ckArrayLength = (*env)->GetArrayLength(env, (jarray) jObject); - ckpObjectPtr = (CK_VOID_PTR_PTR) malloc(sizeof(CK_VOID_PTR) * ckArrayLength); - *ckpLength = 0; - for (i = 0; i < ckArrayLength; i++) { - jObjectToPrimitiveCKObjectPtrPtr(env, (*env)->GetObjectArrayElement(env, (jarray) jObject, i), - ckpElementObject, &ckElementLength); - (*ckpObjectPtr)[i] = *ckpElementObject; - *ckpLength += ckElementLength; - } -*/ - } else { - /* type of jObject unknown, throw PKCS11RuntimeException */ - jMethod = (*env)->GetMethodID(env, jObjectClass, "getClass", "()Ljava/lang/Class;"); - assert(jMethod != 0); - jClassObject = (*env)->CallObjectMethod(env, jObject, jMethod); - assert(jClassObject != 0); - jMethod = (*env)->GetMethodID(env, jClassClass, "getName", "()Ljava/lang/String;"); - assert(jMethod != 0); - jClassNameString = (jstring) - (*env)->CallObjectMethod(env, jClassObject, jMethod); - assert(jClassNameString != 0); - jExceptionMessagePrefix = (*env)->NewStringUTF(env, "Java object of this class cannot be converted to native PKCS#11 type: "); - jMethod = (*env)->GetMethodID(env, jStringBufferClass, "<init>", "(Ljava/lang/String;)V"); - assert(jMethod != 0); - jExceptionMessageStringBuffer = (*env)->NewObject(env, jStringBufferClass, jMethod, jExceptionMessagePrefix); - assert(jClassNameString != 0); - jMethod = (*env)->GetMethodID(env, jStringBufferClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); - assert(jMethod != 0); - jExceptionMessage = (jstring) - (*env)->CallObjectMethod(env, jExceptionMessageStringBuffer, jMethod, jClassNameString); - assert(jExceptionMessage != 0); - - throwPKCS11RuntimeException(env, jExceptionMessage); - - *ckpObjectPtr = NULL; - *ckpLength = 0; + return; } + jBooleanArrayClass = (*env)->FindClass(env, "[Z"); + if (jBooleanArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jBooleanArrayClass)) { + jBooleanArrayToCKBBoolArray(env, jObject, (CK_BBOOL**)ckpObjectPtr, ckpLength); + return; + } + + jIntArrayClass = (*env)->FindClass(env, "[I"); + if (jIntArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jIntArrayClass)) { + jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*)ckpObjectPtr, ckpLength); + return; + } + + jLongArrayClass = (*env)->FindClass(env, "[J"); + if (jLongArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jLongArrayClass)) { + jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*)ckpObjectPtr, ckpLength); + return; + } + + jStringClass = (*env)->FindClass(env, "java/lang/String"); + if (jStringClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jStringClass)) { + jStringToCKUTF8CharArray(env, jObject, (CK_UTF8CHAR_PTR*)ckpObjectPtr, ckpLength); + return; + } + + /* type of jObject unknown, throw PKCS11RuntimeException */ + jObjectClass = (*env)->FindClass(env, "java/lang/Object"); + if (jObjectClass == NULL) { return; } + jMethod = (*env)->GetMethodID(env, jObjectClass, "getClass", "()Ljava/lang/Class;"); + if (jMethod == NULL) { return; } + jClassObject = (*env)->CallObjectMethod(env, jObject, jMethod); + assert(jClassObject != 0); + jClassClass = (*env)->FindClass(env, "java/lang/Class"); + if (jClassClass == NULL) { return; } + jMethod = (*env)->GetMethodID(env, jClassClass, "getName", "()Ljava/lang/String;"); + if (jMethod == NULL) { return; } + jClassNameString = (jstring) + (*env)->CallObjectMethod(env, jClassObject, jMethod); + assert(jClassNameString != 0); + classNameString = (char*) + (*env)->GetStringUTFChars(env, jClassNameString, NULL); + if (classNameString == NULL) { return; } + exceptionMsgPrefix = "Java object of this class cannot be converted to native PKCS#11 type: "; + exceptionMsg = (char *) + malloc((strlen(exceptionMsgPrefix) + strlen(classNameString) + 1)); + if (exceptionMsg == NULL) { + (*env)->ReleaseStringUTFChars(env, jClassNameString, classNameString); + JNU_ThrowOutOfMemoryError(env, 0); + return; + } + strcpy(exceptionMsg, exceptionMsgPrefix); + strcat(exceptionMsg, classNameString); + (*env)->ReleaseStringUTFChars(env, jClassNameString, classNameString); + throwPKCS11RuntimeException(env, exceptionMsg); + free(exceptionMsg); + *ckpObjectPtr = NULL; + *ckpLength = 0; + TRACE0("FINISHED\n"); } + +#ifdef P11_MEMORYDEBUG + +#undef malloc +#undef free + +void *p11malloc(size_t c, char *file, int line) { + void *p = malloc(c); + printf("malloc\t%08x\t%d\t%s:%d\n", p, c, file, line); fflush(stdout); + return p; +} + +void p11free(void *p, char *file, int line) { + printf("free\t%08x\t\t%s:%d\n", p, file, line); fflush(stdout); + free(p); +} + +#endif + diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11wrapper.h b/jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11wrapper.h index 2b67e2b3df7..9dd90c30466 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11wrapper.h +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11wrapper.h @@ -1,5 +1,5 @@ /* - * Portions Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -154,6 +154,7 @@ #include "pkcs11.h" #include <jni.h> +#include <jni_util.h> #define MAX_STACK_BUFFER_LEN (4 * 1024) #define MAX_HEAP_BUFFER_LEN (64 * 1024) @@ -277,12 +278,14 @@ */ jlong ckAssertReturnValueOK(JNIEnv *env, CK_RV returnValue); -void throwPKCS11RuntimeException(JNIEnv *env, jstring jmessage); -void throwFileNotFoundException(JNIEnv *env, jstring jmessage); void throwIOException(JNIEnv *env, const char *message); -void throwIOExceptionUnicodeMessage(JNIEnv *env, const short *message); +void throwPKCS11RuntimeException(JNIEnv *env, const char *message); void throwDisconnectedRuntimeException(JNIEnv *env); +/* function to free CK_ATTRIBUTE array + */ +void freeCKAttributeArray(CK_ATTRIBUTE_PTR attrPtr, int len); + /* funktions to convert Java arrays to a CK-type array and the array length */ void jBooleanArrayToCKBBoolArray(JNIEnv *env, const jbooleanArray jArray, CK_BBOOL **ckpArray, CK_ULONG_PTR ckLength); @@ -438,3 +441,15 @@ extern jobject notifyListLock; extern jobject jInitArgsObject; extern CK_C_INITIALIZE_ARGS_PTR ckpGlobalInitArgs; #endif /* NO_CALLBACKS */ + +#ifdef P11_MEMORYDEBUG +#include <stdlib.h> + +/* Simple malloc/free dumper */ +void *p11malloc(size_t c, char *file, int line); +void p11free(void *p, char *file, int line); + +#define malloc(c) (p11malloc((c), __FILE__, __LINE__)) +#define free(c) (p11free((c), __FILE__, __LINE__)) + +#endif diff --git a/jdk/src/share/sample/nio/file/AclEdit.java b/jdk/src/share/sample/nio/file/AclEdit.java new file mode 100644 index 00000000000..55ed9c00bee --- /dev/null +++ b/jdk/src/share/sample/nio/file/AclEdit.java @@ -0,0 +1,296 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; +import java.util.regex.Pattern; + +/** + * Sample utility for editing a file's ACL. + */ + +public class AclEdit { + + // parse string as list of ACE permissions separated by / + static Set<AclEntryPermission> parsePermissions(String permsString) { + Set<AclEntryPermission> perms = new HashSet<AclEntryPermission>(); + String[] result = permsString.split("/"); + for (String s : result) { + if (s.equals("")) + continue; + try { + perms.add(AclEntryPermission.valueOf(s.toUpperCase())); + } catch (IllegalArgumentException x) { + System.err.format("Invalid permission '%s'\n", s); + System.exit(-1); + } + } + return perms; + } + + // parse string as list of ACE flags separated by / + static Set<AclEntryFlag> parseFlags(String flagsString) { + Set<AclEntryFlag> flags = new HashSet<AclEntryFlag>(); + String[] result = flagsString.split("/"); + for (String s : result) { + if (s.equals("")) + continue; + try { + flags.add(AclEntryFlag.valueOf(s.toUpperCase())); + } catch (IllegalArgumentException x) { + System.err.format("Invalid flag '%s'\n", s); + System.exit(-1); + } + } + return flags; + } + + // parse ACE type + static AclEntryType parseType(String typeString) { + // FIXME: support audit and alarm types in the future + if (typeString.equalsIgnoreCase("allow")) + return AclEntryType.ALLOW; + if (typeString.equalsIgnoreCase("deny")) + return AclEntryType.DENY; + System.err.format("Invalid type '%s'\n", typeString); + System.exit(-1); + return null; // keep compiler happy + } + + /** + * Parse string of the form: + * [user|group:]<username|groupname>:<perms>[:flags]:<allow|deny> + */ + static AclEntry parseAceString(String s, + UserPrincipalLookupService lookupService) + { + String[] result = s.split(":"); + + // must have at least 3 components (username:perms:type) + if (result.length < 3) + usage(); + + int index = 0; + int remaining = result.length; + + // optional first component can indicate user or group type + boolean isGroup = false; + if (result[index].equalsIgnoreCase("user") || + result[index].equalsIgnoreCase("group")) + { + if (--remaining < 3) + usage(); + isGroup = result[index++].equalsIgnoreCase("group"); + } + + // user and permissions required + String userString = result[index++]; remaining--; + String permsString = result[index++]; remaining--; + + // flags are optional + String flagsString = ""; + String typeString = null; + if (remaining == 1) { + typeString = result[index++]; + } else { + if (remaining == 2) { + flagsString = result[index++]; + typeString = result[index++]; + } else { + usage(); + } + } + + // lookup UserPrincipal + UserPrincipal user = null; + try { + user = (isGroup) ? + lookupService.lookupPrincipalByGroupName(userString) : + lookupService.lookupPrincipalByName(userString); + } catch (UserPrincipalNotFoundException x) { + System.err.format("Invalid %s '%s'\n", + ((isGroup) ? "group" : "user"), + userString); + System.exit(-1); + } catch (IOException x) { + System.err.format("Lookup of '%s' failed: %s\n", userString, x); + System.exit(-1); + } + + // map string representation of permissions, flags, and type + Set<AclEntryPermission> perms = parsePermissions(permsString); + Set<AclEntryFlag> flags = parseFlags(flagsString); + AclEntryType type = parseType(typeString); + + // build the ACL entry + return AclEntry.newBuilder() + .setType(type) + .setPrincipal(user) + .setPermissions(perms).setFlags(flags).build(); + } + + static void usage() { + System.err.println("usage: java AclEdit [ACL-operation] file"); + System.err.println(""); + System.err.println("Example 1: Prepends access control entry to the begining of the myfile's ACL"); + System.err.println(" java AclEdit A+alice:read_data/read_attributes:allow myfile"); + System.err.println(""); + System.err.println("Example 2: Remove the entry at index 6 of myfile's ACL"); + System.err.println(" java AclEdit A6- myfile"); + System.err.println(""); + System.err.println("Example 3: Replace the entry at index 2 of myfile's ACL"); + System.err.println(" java AclEdit A2=bob:write_data/append_data:deny myfile"); + System.exit(-1); + } + + static enum Action { + PRINT, + ADD, + REMOVE, + REPLACE; + } + + /** + * Main class: parses arguments and prints or edits ACL + */ + public static void main(String[] args) throws IOException { + Action action = null; + int index = -1; + String entryString = null; + + // parse arguments + if (args.length < 1 || args[0].equals("-help") || args[0].equals("-?")) + usage(); + + if (args.length == 1) { + action = Action.PRINT; + } else { + String s = args[0]; + + // A[index]+entry + if (Pattern.matches("^A[0-9]*\\+.*", s)) { + String[] result = s.split("\\+", 2); + if (result.length == 2) { + if (result[0].length() < 2) { + index = 0; + } else { + index = Integer.parseInt(result[0].substring(1)); + } + entryString = result[1]; + action = Action.ADD; + } + } + + // Aindex- + if (Pattern.matches("^A[0-9]+\\-", s)) { + String[] result = s.split("\\-", 2); + if (result.length == 2) { + index = Integer.parseInt(result[0].substring(1)); + entryString = result[1]; + action = Action.REMOVE; + } + } + + // Aindex=entry + if (Pattern.matches("^A[0-9]+=.*", s)) { + String[] result = s.split("=", 2); + if (result.length == 2) { + index = Integer.parseInt(result[0].substring(1)); + entryString = result[1]; + action = Action.REPLACE; + } + } + } + if (action == null) + usage(); + + int fileArg = (action == Action.PRINT) ? 0 : 1; + Path file = Paths.get(args[fileArg]); + + // read file's ACL + AclFileAttributeView view = + file.getFileAttributeView(AclFileAttributeView.class); + if (view == null) { + System.err.println("ACLs not supported on this platform"); + System.exit(-1); + } + List<AclEntry> acl = view.getAcl(); + + switch (action) { + // print ACL + case PRINT : { + for (int i=0; i<acl.size(); i++) { + System.out.format("%5d: %s\n", i, acl.get(i)); + } + break; + } + + // add ACE to existing ACL + case ADD: { + AclEntry entry = parseAceString(entryString, file + .getFileSystem().getUserPrincipalLookupService()); + if (index >= acl.size()) { + acl.add(entry); + } else { + acl.add(index, entry); + } + view.setAcl(acl); + break; + } + + // remove ACE + case REMOVE: { + if (index >= acl.size()) { + System.err.format("Index '%d' is invalid", index); + System.exit(-1); + } + acl.remove(index); + view.setAcl(acl); + break; + } + + // replace ACE + case REPLACE: { + if (index >= acl.size()) { + System.err.format("Index '%d' is invalid", index); + System.exit(-1); + } + AclEntry entry = parseAceString(entryString, file + .getFileSystem().getUserPrincipalLookupService()); + acl.set(index, entry); + view.setAcl(acl); + break; + } + } + } +} diff --git a/jdk/src/share/sample/nio/file/Chmod.java b/jdk/src/share/sample/nio/file/Chmod.java new file mode 100644 index 00000000000..eeb54ad6cd5 --- /dev/null +++ b/jdk/src/share/sample/nio/file/Chmod.java @@ -0,0 +1,347 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import static java.nio.file.attribute.PosixFilePermission.*; +import static java.nio.file.FileVisitResult.*; +import java.io.IOException; +import java.util.*; + +/** + * Sample code that changes the permissions of files in a similar manner to the + * chmod(1) program. + */ + +public class Chmod { + + /** + * Compiles a list of one or more <em>symbolic mode expressions</em> that + * may be used to change a set of file permissions. This method is + * intended for use where file permissions are required to be changed in + * a manner similar to the UNIX <i>chmod</i> program. + * + * <p> The {@code exprs} parameter is a comma separated list of expressions + * where each takes the form: + * <blockquote> + * <i>who operator</i> [<i>permissions</i>] + * </blockquote> + * where <i>who</i> is one or more of the characters {@code 'u'}, {@code 'g'}, + * {@code 'o'}, or {@code 'a'} meaning the owner (user), group, others, or + * all (owner, group, and others) respectively. + * + * <p> <i>operator</i> is the character {@code '+'}, {@code '-'}, or {@code + * '='} signifying how permissions are to be changed. {@code '+'} means the + * permissions are added, {@code '-'} means the permissions are removed, and + * {@code '='} means the permissions are assigned absolutely. + * + * <p> <i>permissions</i> is a sequence of zero or more of the following: + * {@code 'r'} for read permission, {@code 'w'} for write permission, and + * {@code 'x'} for execute permission. If <i>permissions</i> is omitted + * when assigned absolutely, then the permissions are cleared for + * the owner, group, or others as identified by <i>who</i>. When omitted + * when adding or removing then the expression is ignored. + * + * <p> The following examples demonstrate possible values for the {@code + * exprs} parameter: + * + * <table border="0"> + * <tr> + * <td> {@code u=rw} </td> + * <td> Sets the owner permissions to be read and write. </td> + * </tr> + * <tr> + * <td> {@code ug+w} </td> + * <td> Sets the owner write and group write permissions. </td> + * </tr> + * <tr> + * <td> {@code u+w,o-rwx} </td> + * <td> Sets the owner write, and removes the others read, others write + * and others execute permissions. </td> + * </tr> + * <tr> + * <td> {@code o=} </td> + * <td> Sets the others permission to none (others read, others write and + * others execute permissions are removed if set) </td> + * </tr> + * </table> + * + * @param exprs + * List of one or more <em>symbolic mode expressions</em> + * + * @return A {@code Changer} that may be used to changer a set of + * file permissions + * + * @throws IllegalArgumentException + * If the value of the {@code exprs} parameter is invalid + */ + public static Changer compile(String exprs) { + // minimum is who and operator (u= for example) + if (exprs.length() < 2) + throw new IllegalArgumentException("Invalid mode"); + + // permissions that the changer will add or remove + final Set<PosixFilePermission> toAdd = new HashSet<PosixFilePermission>(); + final Set<PosixFilePermission> toRemove = new HashSet<PosixFilePermission>(); + + // iterate over each of expression modes + for (String expr: exprs.split(",")) { + // minimum of who and operator + if (expr.length() < 2) + throw new IllegalArgumentException("Invalid mode"); + + int pos = 0; + + // who + boolean u = false; + boolean g = false; + boolean o = false; + boolean done = false; + for (;;) { + switch (expr.charAt(pos)) { + case 'u' : u = true; break; + case 'g' : g = true; break; + case 'o' : o = true; break; + case 'a' : u = true; g = true; o = true; break; + default : done = true; + } + if (done) + break; + pos++; + } + if (!u && !g && !o) + throw new IllegalArgumentException("Invalid mode"); + + // get operator and permissions + char op = expr.charAt(pos++); + String mask = (expr.length() == pos) ? "" : expr.substring(pos); + + // operator + boolean add = (op == '+'); + boolean remove = (op == '-'); + boolean assign = (op == '='); + if (!add && !remove && !assign) + throw new IllegalArgumentException("Invalid mode"); + + // who= means remove all + if (assign && mask.length() == 0) { + assign = false; + remove = true; + mask = "rwx"; + } + + // permissions + boolean r = false; + boolean w = false; + boolean x = false; + for (int i=0; i<mask.length(); i++) { + switch (mask.charAt(i)) { + case 'r' : r = true; break; + case 'w' : w = true; break; + case 'x' : x = true; break; + default: + throw new IllegalArgumentException("Invalid mode"); + } + } + + // update permissions set + if (add) { + if (u) { + if (r) toAdd.add(OWNER_READ); + if (w) toAdd.add(OWNER_WRITE); + if (x) toAdd.add(OWNER_EXECUTE); + } + if (g) { + if (r) toAdd.add(GROUP_READ); + if (w) toAdd.add(GROUP_WRITE); + if (x) toAdd.add(GROUP_EXECUTE); + } + if (o) { + if (r) toAdd.add(OTHERS_READ); + if (w) toAdd.add(OTHERS_WRITE); + if (x) toAdd.add(OTHERS_EXECUTE); + } + } + if (remove) { + if (u) { + if (r) toRemove.add(OWNER_READ); + if (w) toRemove.add(OWNER_WRITE); + if (x) toRemove.add(OWNER_EXECUTE); + } + if (g) { + if (r) toRemove.add(GROUP_READ); + if (w) toRemove.add(GROUP_WRITE); + if (x) toRemove.add(GROUP_EXECUTE); + } + if (o) { + if (r) toRemove.add(OTHERS_READ); + if (w) toRemove.add(OTHERS_WRITE); + if (x) toRemove.add(OTHERS_EXECUTE); + } + } + if (assign) { + if (u) { + if (r) toAdd.add(OWNER_READ); + else toRemove.add(OWNER_READ); + if (w) toAdd.add(OWNER_WRITE); + else toRemove.add(OWNER_WRITE); + if (x) toAdd.add(OWNER_EXECUTE); + else toRemove.add(OWNER_EXECUTE); + } + if (g) { + if (r) toAdd.add(GROUP_READ); + else toRemove.add(GROUP_READ); + if (w) toAdd.add(GROUP_WRITE); + else toRemove.add(GROUP_WRITE); + if (x) toAdd.add(GROUP_EXECUTE); + else toRemove.add(GROUP_EXECUTE); + } + if (o) { + if (r) toAdd.add(OTHERS_READ); + else toRemove.add(OTHERS_READ); + if (w) toAdd.add(OTHERS_WRITE); + else toRemove.add(OTHERS_WRITE); + if (x) toAdd.add(OTHERS_EXECUTE); + else toRemove.add(OTHERS_EXECUTE); + } + } + } + + // return changer + return new Changer() { + @Override + public Set<PosixFilePermission> change(Set<PosixFilePermission> perms) { + perms.addAll(toAdd); + perms.removeAll(toRemove); + return perms; + } + }; + } + + /** + * A task that <i>changes</i> a set of {@link PosixFilePermission} elements. + */ + public interface Changer { + /** + * Applies the changes to the given set of permissions. + * + * @param perms + * The set of permissions to change + * + * @return The {@code perms} parameter + */ + Set<PosixFilePermission> change(Set<PosixFilePermission> perms); + } + + /** + * Changes the permissions of the file using the given Changer. + */ + static void chmod(FileRef file, Changer changer) { + try { + Set<PosixFilePermission> perms = Attributes + .readPosixFileAttributes(file).permissions(); + Attributes.setPosixFilePermissions(file, changer.change(perms)); + } catch (IOException x) { + System.err.println(x); + } + } + + /** + * Changes the permission of each file and directory visited + */ + static class TreeVisitor implements FileVisitor<FileRef> { + private final Changer changer; + + TreeVisitor(Changer changer) { + this.changer = changer; + } + + @Override + public FileVisitResult preVisitDirectory(FileRef dir) { + chmod(dir, changer); + return CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectoryFailed(FileRef dir, IOException exc) { + System.err.println("WARNING: " + exc); + return CONTINUE; + } + + @Override + public FileVisitResult visitFile(FileRef file, BasicFileAttributes attrs) { + chmod(file, changer); + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(FileRef dir, IOException exc) { + if (exc != null) + System.err.println("WARNING: " + exc); + return CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(FileRef file, IOException exc) { + System.err.println("WARNING: " + exc); + return CONTINUE; + } + } + + static void usage() { + System.err.println("java Chmod [-R] symbolic-mode-list file..."); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + if (args.length < 2) + usage(); + int argi = 0; + int maxDepth = 0; + if (args[argi].equals("-R")) { + if (args.length < 3) + usage(); + argi++; + maxDepth = Integer.MAX_VALUE; + } + + // compile the symbolic mode expressions + Changer changer = compile(args[argi++]); + TreeVisitor visitor = new TreeVisitor(changer); + + Set<FileVisitOption> opts = Collections.emptySet(); + while (argi < args.length) { + Path file = Paths.get(args[argi]); + Files.walkFileTree(file, opts, maxDepth, visitor); + argi++; + } + } +} diff --git a/jdk/src/share/sample/nio/file/Copy.java b/jdk/src/share/sample/nio/file/Copy.java new file mode 100644 index 00000000000..e1d5d044ef5 --- /dev/null +++ b/jdk/src/share/sample/nio/file/Copy.java @@ -0,0 +1,217 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.file.*; +import static java.nio.file.StandardCopyOption.*; +import java.nio.file.attribute.*; +import static java.nio.file.FileVisitResult.*; +import java.io.IOException; +import java.util.*; + +/** + * Sample code that copies files in a similar manner to the cp(1) program. + */ + +public class Copy { + + /** + * Returns {@code true} if okay to overwrite a file ("cp -i") + */ + static boolean okayToOverwrite(FileRef file) { + String answer = System.console().readLine("overwrite %s (yes/no)? ", file); + return (answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes")); + } + + /** + * Copy source file to target location. If {@code prompt} is true then + * prompted user to overwrite target if it exists. The {@code preserve} + * parameter determines if file attributes should be copied/preserved. + */ + static void copyFile(Path source, Path target, boolean prompt, boolean preserve) { + CopyOption[] options = (preserve) ? + new CopyOption[] { COPY_ATTRIBUTES, REPLACE_EXISTING } : + new CopyOption[] { REPLACE_EXISTING }; + if (!prompt || target.notExists() || okayToOverwrite(target)) { + try { + source.copyTo(target, options); + } catch (IOException x) { + System.err.format("Unable to create: %s: %s%n", target, x); + } + } + } + + /** + * A {@code FileVisitor} that copies a file-tree ("cp -r") + */ + static class TreeCopier implements FileVisitor<Path> { + private final Path source; + private final Path target; + private final boolean prompt; + private final boolean preserve; + + TreeCopier(Path source, Path target, boolean prompt, boolean preserve) { + this.source = source; + this.target = target; + this.prompt = prompt; + this.preserve = preserve; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir) { + // before visiting entries in a directory we copy the directory + // (okay if directory already exists). + CopyOption[] options = (preserve) ? + new CopyOption[] { COPY_ATTRIBUTES } : new CopyOption[0]; + + Path newdir = target.resolve(source.relativize(dir)); + try { + dir.copyTo(newdir, options); + } catch (FileAlreadyExistsException x) { + // ignore + } catch (IOException x) { + System.err.format("Unable to create: %s: %s%n", newdir, x); + return SKIP_SUBTREE; + } + return CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) { + System.err.format("Unable to copy: %s: %s%n", dir, exc); + return CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (attrs.isDirectory()) { + System.err.println("cycle detected: " + file); + } else { + copyFile(file, target.resolve(source.relativize(file)), + prompt, preserve); + } + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) { + // fix up modification time of directory when done + if (exc == null && preserve) { + try { + BasicFileAttributes attrs = Attributes.readBasicFileAttributes(dir); + Path newdir = target.resolve(source.relativize(dir)); + Attributes.setLastModifiedTime(newdir, + attrs.lastModifiedTime(), attrs.resolution()); + } catch (IOException x) { + // ignore + } + } + return CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) { + System.err.format("Unable to copy: %s: %s%n", file, exc); + return CONTINUE; + } + } + + static void usage() { + System.err.println("java Copy [-ip] source... target"); + System.err.println("java Copy -r [-ip] source-dir... target"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + boolean recursive = false; + boolean prompt = false; + boolean preserve = false; + + // process options + int argi = 0; + while (argi < args.length) { + String arg = args[argi]; + if (!arg.startsWith("-")) + break; + if (arg.length() < 2) + usage(); + for (int i=1; i<arg.length(); i++) { + char c = arg.charAt(i); + switch (c) { + case 'r' : recursive = true; break; + case 'i' : prompt = true; break; + case 'p' : preserve = true; break; + default : usage(); + } + } + argi++; + } + + // remaining arguments are the source files(s) and the target location + int remaining = args.length - argi; + if (remaining < 2) + usage(); + Path[] source = new Path[remaining-1]; + int i=0; + while (remaining > 1) { + source[i++] = Paths.get(args[argi++]); + remaining--; + } + Path target = Paths.get(args[argi]); + + // check if target is a directory + boolean isDir = false; + try { + isDir = Attributes.readBasicFileAttributes(target).isDirectory(); + } catch (IOException x) { + } + + // copy each source file/directory to target + for (i=0; i<source.length; i++) { + Path dest = (isDir) ? target.resolve(source[i].getName()) : target; + + if (recursive) { + // follow links when copying files + EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); + TreeCopier tc = new TreeCopier(source[i], dest, prompt, preserve); + Files.walkFileTree(source[i], opts, -1, tc); + } else { + // not recursive so source must not be a directory + try { + if (Attributes.readBasicFileAttributes(source[i]).isDirectory()) { + System.err.format("%s: is a directory%n", source[i]); + continue; + } + } catch (IOException x) { } + copyFile(source[i], dest, prompt, preserve); + } + } + } +} diff --git a/jdk/src/share/sample/nio/file/DiskUsage.java b/jdk/src/share/sample/nio/file/DiskUsage.java new file mode 100644 index 00000000000..ff16d888490 --- /dev/null +++ b/jdk/src/share/sample/nio/file/DiskUsage.java @@ -0,0 +1,74 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; + +/** + * Example utility that works like the df(1M) program to print out disk space + * information + */ + +public class DiskUsage { + + static final long K = 1024; + + static void printFileStore(FileStore store) throws IOException { + FileStoreSpaceAttributes attrs = Attributes.readFileStoreSpaceAttributes(store); + + long total = attrs.totalSpace() / K; + long used = (attrs.totalSpace() - attrs.unallocatedSpace()) / K; + long avail = attrs.usableSpace() / K; + + String s = store.toString(); + if (s.length() > 20) { + System.out.println(s); + s = ""; + } + System.out.format("%-20s %12d %12d %12d\n", s, total, used, avail); + } + + public static void main(String[] args) throws IOException { + System.out.format("%-20s %12s %12s %12s\n", "Filesystem", "kbytes", "used", "avail"); + if (args.length == 0) { + FileSystem fs = FileSystems.getDefault(); + for (FileStore store: fs.getFileStores()) { + printFileStore(store); + } + } else { + for (String file: args) { + FileStore store = Paths.get(file).getFileStore(); + printFileStore(store); + } + } + } +} diff --git a/jdk/src/share/sample/nio/file/FileType.java b/jdk/src/share/sample/nio/file/FileType.java new file mode 100644 index 00000000000..31fb45299a2 --- /dev/null +++ b/jdk/src/share/sample/nio/file/FileType.java @@ -0,0 +1,57 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; + +public class FileType { + public static void main(String[] args) throws IOException { + if (args.length == 0) { + System.err.println("usage: java FileType file..."); + System.exit(-1); + } + for (String arg: args) { + Path file = Paths.get(arg); + BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file); + + String type; + if (attrs.isDirectory()) { + type = "directory"; + } else { + type = Files.probeContentType(file); + if (type == null) + type = "<not recognized>"; + } + System.out.format("%s\t%s%n", file, type); + } + } +} diff --git a/jdk/src/share/sample/nio/file/WatchDir.java b/jdk/src/share/sample/nio/file/WatchDir.java new file mode 100644 index 00000000000..b8b6474dc6f --- /dev/null +++ b/jdk/src/share/sample/nio/file/WatchDir.java @@ -0,0 +1,196 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.file.*; +import static java.nio.file.StandardWatchEventKind.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; +import java.io.*; +import java.util.*; + +/** + * Example to watch a directory (or tree) for changes to files. + */ + +public class WatchDir { + + private final WatchService watcher; + private final Map<WatchKey,Path> keys; + private final boolean recursive; + private boolean trace = false; + + @SuppressWarnings("unchecked") + static <T> WatchEvent<T> cast(WatchEvent<?> event) { + return (WatchEvent<T>)event; + } + + /** + * Register the given directory with the WatchService + */ + private void register(Path dir) throws IOException { + WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + if (trace) { + FileRef prev = keys.get(key); + if (prev == null) { + System.out.format("register: %s\n", dir); + } else { + if (!dir.equals(prev)) { + System.out.format("update: %s -> %s\n", prev, dir); + } + } + } + keys.put(key, dir); + } + + /** + * Register the given directory, and all its sub-directories, with the + * WatchService. + */ + private void registerAll(final Path start) throws IOException { + // register directory and sub-directories + Files.walkFileTree(start, new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult preVisitDirectory(Path dir) { + try { + register(dir); + } catch (IOException x) { + throw new IOError(x); + } + return FileVisitResult.CONTINUE; + } + }); + } + + /** + * Creates a WatchService and registers the given directory + */ + WatchDir(Path dir, boolean recursive) throws IOException { + this.watcher = FileSystems.getDefault().newWatchService(); + this.keys = new HashMap<WatchKey,Path>(); + this.recursive = recursive; + + if (recursive) { + System.out.format("Scanning %s ...\n", dir); + registerAll(dir); + System.out.println("Done."); + } else { + register(dir); + } + + // enable trace after initial registration + this.trace = true; + } + + /** + * Process all events for keys queued to the watcher + */ + void processEvents() { + for (;;) { + + // wait for key to be signalled + WatchKey key; + try { + key = watcher.take(); + } catch (InterruptedException x) { + return; + } + + Path dir = keys.get(key); + if (dir == null) { + System.err.println("WatchKey not recognized!!"); + continue; + } + + for (WatchEvent<?> event: key.pollEvents()) { + WatchEvent.Kind kind = event.kind(); + + // TBD - provide example of how OVERFLOW event is handled + if (kind == OVERFLOW) { + continue; + } + + // Context for directory entry event is the file name of entry + WatchEvent<Path> ev = cast(event); + Path name = ev.context(); + Path child = dir.resolve(name); + + // print out event + System.out.format("%s: %s\n", event.kind().name(), child); + + // if directory is created, and watching recursively, then + // register it and its sub-directories + if (recursive && (kind == ENTRY_CREATE)) { + try { + if (Attributes.readBasicFileAttributes(child, NOFOLLOW_LINKS).isDirectory()) { + registerAll(child); + } + } catch (IOException x) { + // ignore to keep sample readbale + } + } + } + + // reset key and remove from set if directory no longer accessible + boolean valid = key.reset(); + if (!valid) { + keys.remove(key); + + // all directories are inaccessible + if (keys.isEmpty()) { + break; + } + } + } + } + + static void usage() { + System.err.println("usage: java WatchDir [-r] dir"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + // parse arguments + if (args.length == 0 || args.length > 2) + usage(); + boolean recursive = false; + int dirArg = 0; + if (args[0].equals("-r")) { + if (args.length < 2) + usage(); + recursive = true; + dirArg++; + } + + // register directory and process its events + Path dir = Paths.get(args[dirArg]); + new WatchDir(dir, recursive).processEvents(); + } +} diff --git a/jdk/src/share/sample/nio/file/Xdd.java b/jdk/src/share/sample/nio/file/Xdd.java new file mode 100644 index 00000000000..f66597eddd4 --- /dev/null +++ b/jdk/src/share/sample/nio/file/Xdd.java @@ -0,0 +1,112 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; + +/** + * Example code to list/set/get/delete the user-defined attributes of a file. + */ + +public class Xdd { + + static void usage() { + System.out.println("Usage: java Xdd <file>"); + System.out.println(" java Xdd -set <name>=<value> <file>"); + System.out.println(" java Xdd -get <name> <file>"); + System.out.println(" java Xdd -del <name> <file>"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + // one or three parameters + if (args.length != 1 && args.length != 3) + usage(); + + Path file = (args.length == 1) ? + Paths.get(args[0]) : Paths.get(args[2]); + + // check that user defined attributes are supported by the file system + FileStore store = file.getFileStore(); + if (!store.supportsFileAttributeView("xattr")) { + System.err.format("UserDefinedFileAttributeView not supported on %s\n", store); + System.exit(-1); + + } + UserDefinedFileAttributeView view = file. + getFileAttributeView(UserDefinedFileAttributeView.class); + + // list user defined attributes + if (args.length == 1) { + System.out.println(" Size Name"); + System.out.println("-------- --------------------------------------"); + for (String name: view.list()) { + System.out.format("%8d %s\n", view.size(name), name); + } + return; + } + + // Add/replace a file's user defined attribute + if (args[0].equals("-set")) { + // name=value + String[] s = args[1].split("="); + if (s.length != 2) + usage(); + String name = s[0]; + String value = s[1]; + view.write(name, Charset.defaultCharset().encode(value)); + return; + } + + // Print out the value of a file's user defined attribute + if (args[0].equals("-get")) { + String name = args[1]; + int size = view.size(name); + ByteBuffer buf = ByteBuffer.allocateDirect(size); + view.read(name, buf); + buf.flip(); + System.out.println(Charset.defaultCharset().decode(buf).toString()); + return; + } + + // Delete a file's user defined attribute + if (args[0].equals("-del")) { + view.delete(args[1]); + return; + } + + // option not recognized + usage(); + } + } diff --git a/jdk/src/solaris/classes/sun/awt/X11/XFontPeer.java b/jdk/src/solaris/classes/sun/awt/X11/XFontPeer.java index 62044ace53e..3d03a2503aa 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XFontPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XFontPeer.java @@ -27,9 +27,6 @@ package sun.awt.X11; import sun.awt.PlatformFont; import java.awt.GraphicsEnvironment; -/* FIX ME */ -import sun.awt.motif.MFontConfiguration; - public class XFontPeer extends PlatformFont { /* @@ -51,10 +48,6 @@ public class XFontPeer extends PlatformFont { public XFontPeer(String name, int style){ super(name, style); - - if (fontConfig != null){ - xfsname = ((MFontConfiguration) fontConfig).getMotifFontSet(familyName, style); - } } protected char getMissingGlyphCharacter() { diff --git a/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java b/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java index fe2e5dbf836..a34fed02e15 100644 --- a/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java +++ b/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java @@ -15,7 +15,7 @@ * accompanied this code). * * You should have received a copy of the GNU General Public License version - * along with this work; if not, write to the Free Software Foundation, + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, @@ -87,6 +87,7 @@ public class FcFontConfiguration extends FontConfiguration { return true; } + setFontConfiguration(); readFcInfo(); if (fcCompFonts == null) { fcCompFonts = FontManager.loadFontConfig(); @@ -172,7 +173,7 @@ public class FcFontConfiguration extends FontConfiguration { @Override public FontDescriptor[] getFontDescriptors(String fontName, int style) { - throw new InternalError("Not implemented"); + return new FontDescriptor[0]; } @Override diff --git a/jdk/src/solaris/classes/sun/net/NetHooks.java b/jdk/src/solaris/classes/sun/net/NetHooks.java new file mode 100644 index 00000000000..f847934190c --- /dev/null +++ b/jdk/src/solaris/classes/sun/net/NetHooks.java @@ -0,0 +1,122 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.net; + +import java.net.InetAddress; +import java.io.FileDescriptor; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.security.action.GetPropertyAction; + +/** + * Defines static methods to be invoked prior to binding or connecting TCP sockets. + */ + +public final class NetHooks { + + /** + * A provider with hooks to allow sockets be converted prior to binding or + * connecting a TCP socket. + * + * <p> Concrete implementations of this class should define a zero-argument + * constructor and implement the abstract methods specified below. + */ + public static abstract class Provider { + /** + * Initializes a new instance of this class. + */ + protected Provider() {} + + /** + * Invoked prior to binding a TCP socket. + */ + public abstract void implBeforeTcpBind(FileDescriptor fdObj, + InetAddress address, + int port) + throws IOException; + + /** + * Invoked prior to connecting an unbound TCP socket. + */ + public abstract void implBeforeTcpConnect(FileDescriptor fdObj, + InetAddress address, + int port) + throws IOException; + } + + /** + * For now, we load the SDP provider on Solaris. In the future this may + * be changed to use the ServiceLoader facility to allow the deployment of + * other providers. + */ + private static Provider loadProvider(final String cn) { + return AccessController + .doPrivileged(new PrivilegedAction<Provider>() { + @Override public Provider run() { + Class<Provider> c; + try { + c = (Class<Provider>)Class.forName(cn, true, null); + } catch (ClassNotFoundException x) { + throw new AssertionError(x); + } + try { + return c.newInstance(); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InstantiationException x) { + throw new AssertionError(x); + } + }}); + } + private static final Provider provider = AccessController + .doPrivileged(new GetPropertyAction("os.name")).equals("SunOS") ? + loadProvider("sun.net.spi.SdpProvider") : null; + + /** + * Invoke prior to binding a TCP socket. + */ + public static void beforeTcpBind(FileDescriptor fdObj, + InetAddress address, + int port) + throws IOException + { + if (provider != null) + provider.implBeforeTcpBind(fdObj, address, port); + } + + /** + * Invoke prior to connecting an unbound TCP socket. + */ + public static void beforeTcpConnect(FileDescriptor fdObj, + InetAddress address, + int port) + throws IOException + { + if (provider != null) + provider.implBeforeTcpConnect(fdObj, address, port); + } +} diff --git a/jdk/src/solaris/classes/sun/net/spi/SdpProvider.java b/jdk/src/solaris/classes/sun/net/spi/SdpProvider.java new file mode 100644 index 00000000000..4ae7d9fa58c --- /dev/null +++ b/jdk/src/solaris/classes/sun/net/spi/SdpProvider.java @@ -0,0 +1,339 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.net.spi; + +import sun.net.NetHooks; +import java.net.InetAddress; +import java.net.Inet4Address; +import java.net.UnknownHostException; +import java.util.*; +import java.io.File; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintStream; + +import sun.misc.SharedSecrets; +import sun.misc.JavaIOFileDescriptorAccess; + +/** + * A NetHooks provider that converts sockets from the TCP to SDP protocol prior + * to binding or connecting. + */ + +public class SdpProvider extends NetHooks.Provider { + private static final JavaIOFileDescriptorAccess fdAccess = + SharedSecrets.getJavaIOFileDescriptorAccess(); + + // maximum port + private static final int MAX_PORT = 65535; + + // indicates if SDP is enabled and the rules for when the protocol is used + private final boolean enabled; + private final List<Rule> rules; + + // logging for debug purposes + private PrintStream log; + + public SdpProvider() { + // if this property is not defined then there is nothing to do. + String file = System.getProperty("com.sun.sdp.conf"); + if (file == null) { + this.enabled = false; + this.rules = null; + return; + } + + // load configuration file + List<Rule> list = null; + if (file != null) { + try { + list = loadRulesFromFile(file); + } catch (IOException e) { + fail("Error reading %s: %s", file, e.getMessage()); + } + } + + // check if debugging is enabled + PrintStream out = null; + String logfile = System.getProperty("com.sun.sdp.debug"); + if (logfile != null) { + out = System.out; + if (logfile.length() > 0) { + try { + out = new PrintStream(logfile); + } catch (IOException ignore) { } + } + } + + this.enabled = !list.isEmpty(); + this.rules = list; + this.log = out; + } + + // supported actions + private static enum Action { + BIND, + CONNECT; + } + + // a rule for matching a bind or connect request + private static interface Rule { + boolean match(Action action, InetAddress address, int port); + } + + // rule to match port[-end] + private static class PortRangeRule implements Rule { + private final Action action; + private final int portStart; + private final int portEnd; + PortRangeRule(Action action, int portStart, int portEnd) { + this.action = action; + this.portStart = portStart; + this.portEnd = portEnd; + } + Action action() { + return action; + } + @Override + public boolean match(Action action, InetAddress address, int port) { + return (action == this.action && + port >= this.portStart && + port <= this.portEnd); + } + } + + // rule to match address[/prefix] port[-end] + private static class AddressPortRangeRule extends PortRangeRule { + private final byte[] addressAsBytes; + private final int prefixByteCount; + private final byte mask; + AddressPortRangeRule(Action action, InetAddress address, + int prefix, int port, int end) + { + super(action, port, end); + this.addressAsBytes = address.getAddress(); + this.prefixByteCount = prefix >> 3; + this.mask = (byte)(0xff << (8 - (prefix % 8))); + } + @Override + public boolean match(Action action, InetAddress address, int port) { + if (action != action()) + return false; + byte[] candidate = address.getAddress(); + // same address type? + if (candidate.length != addressAsBytes.length) + return false; + // check bytes + for (int i=0; i<prefixByteCount; i++) { + if (candidate[i] != addressAsBytes[i]) + return false; + } + // check remaining bits + if ((prefixByteCount < addressAsBytes.length) && + ((candidate[prefixByteCount] & mask) != + (addressAsBytes[prefixByteCount] & mask))) + return false; + return super.match(action, address, port); + } + } + + // parses port:[-end] + private static int[] parsePortRange(String s) { + int pos = s.indexOf('-'); + try { + int[] result = new int[2]; + if (pos < 0) { + boolean all = s.equals("*"); + result[0] = all ? 0 : Integer.parseInt(s); + result[1] = all ? MAX_PORT : result[0]; + } else { + String low = s.substring(0, pos); + if (low.length() == 0) low = "*"; + String high = s.substring(pos+1); + if (high.length() == 0) high = "*"; + result[0] = low.equals("*") ? 0 : Integer.parseInt(low); + result[1] = high.equals("*") ? MAX_PORT : Integer.parseInt(high); + } + return result; + } catch (NumberFormatException e) { + return new int[0]; + } + } + + private static void fail(String msg, Object... args) { + Formatter f = new Formatter(); + f.format(msg, args); + throw new RuntimeException(f.out().toString()); + } + + // loads rules from the given file + // Each non-blank/non-comment line must have the format: + // ("bind" | "connect") 1*LWSP-char (hostname | ipaddress["/" prefix]) + // 1*LWSP-char ("*" | port) [ "-" ("*" | port) ] + private static List<Rule> loadRulesFromFile(String file) + throws IOException + { + Scanner scanner = new Scanner(new File(file)); + try { + List<Rule> result = new ArrayList<Rule>(); + while (scanner.hasNextLine()) { + String line = scanner.nextLine().trim(); + + // skip blank lines and comments + if (line.length() == 0 || line.charAt(0) == '#') + continue; + + // must have 3 fields + String[] s = line.split("\\s+"); + if (s.length != 3) { + fail("Malformed line '%s'", line); + continue; + } + + // first field is the action ("bind" or "connect") + Action action = null; + for (Action a: Action.values()) { + if (s[0].equalsIgnoreCase(a.name())) { + action = a; + break; + } + } + if (action == null) { + fail("Action '%s' not recognized", s[0]); + continue; + } + + // * port[-end] + int[] ports = parsePortRange(s[2]); + if (ports.length == 0) { + fail("Malformed port range '%s'", s[2]); + continue; + } + + // match all addresses + if (s[1].equals("*")) { + result.add(new PortRangeRule(action, ports[0], ports[1])); + continue; + } + + // hostname | ipaddress[/prefix] + int pos = s[1].indexOf('/'); + try { + if (pos < 0) { + // hostname or ipaddress (no prefix) + InetAddress[] addresses = InetAddress.getAllByName(s[1]); + for (InetAddress address: addresses) { + int prefix = + (address instanceof Inet4Address) ? 32 : 128; + result.add(new AddressPortRangeRule(action, address, + prefix, ports[0], ports[1])); + } + } else { + // ipaddress/prefix + InetAddress address = InetAddress + .getByName(s[1].substring(0, pos)); + int prefix = -1; + try { + prefix = Integer.parseInt(s[1].substring(pos+1)); + if (address instanceof Inet4Address) { + // must be 1-31 + if (prefix < 0 || prefix > 32) prefix = -1; + } else { + // must be 1-128 + if (prefix < 0 || prefix > 128) prefix = -1; + } + } catch (NumberFormatException e) { + } + + if (prefix > 0) { + result.add(new AddressPortRangeRule(action, + address, prefix, ports[0], ports[1])); + } else { + fail("Malformed prefix '%s'", s[1]); + continue; + } + } + } catch (UnknownHostException uhe) { + fail("Unknown host or malformed IP address '%s'", s[1]); + continue; + } + } + return result; + } finally { + scanner.close(); + } + } + + // converts unbound TCP socket to a SDP socket if it matches the rules + private void convertTcpToSdpIfMatch(FileDescriptor fdObj, + Action action, + InetAddress address, + int port) + throws IOException + { + boolean matched = false; + for (Rule rule: rules) { + if (rule.match(action, address, port)) { + int fd = fdAccess.get(fdObj); + convert(fd); + matched = true; + break; + } + } + if (log != null) { + String addr = (address instanceof Inet4Address) ? + address.getHostAddress() : "[" + address.getHostAddress() + "]"; + if (matched) { + log.format("%s to %s:%d (socket converted to SDP protocol)\n", action, addr, port); + } else { + log.format("%s to %s:%d (no match)\n", action, addr, port); + } + } + } + + @Override + public void implBeforeTcpBind(FileDescriptor fdObj, + InetAddress address, + int port) + throws IOException + { + if (enabled) + convertTcpToSdpIfMatch(fdObj, Action.BIND, address, port); + } + + @Override + public void implBeforeTcpConnect(FileDescriptor fdObj, + InetAddress address, + int port) + throws IOException + { + if (enabled) + convertTcpToSdpIfMatch(fdObj, Action.CONNECT, address, port); + } + + // -- native methods -- + private static native void convert(int fd) throws IOException; +} diff --git a/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java b/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java index 8ac3e1e8d4f..9d0a1d1d7d3 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java +++ b/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,11 +56,11 @@ class DatagramDispatcher extends NativeDispatcher } void close(FileDescriptor fd) throws IOException { - FileDispatcher.close0(fd); + FileDispatcherImpl.close0(fd); } void preClose(FileDescriptor fd) throws IOException { - FileDispatcher.preClose0(fd); + FileDispatcherImpl.preClose0(fd); } static native int read0(FileDescriptor fd, long address, int len) diff --git a/jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java new file mode 100644 index 00000000000..949c817ff1e --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java @@ -0,0 +1,56 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; + +/** + * Creates this platform's default asynchronous channel provider + */ + +public class DefaultAsynchronousChannelProvider { + + /** + * Prevent instantiation. + */ + private DefaultAsynchronousChannelProvider() { } + + /** + * Returns the default AsynchronousChannelProvider. + */ + public static AsynchronousChannelProvider create() { + String osname = AccessController + .doPrivileged(new GetPropertyAction("os.name")); + if (osname.equals("SunOS")) + return new SolarisAsynchronousChannelProvider(); + if (osname.equals("Linux")) + return new LinuxAsynchronousChannelProvider(); + throw new InternalError("platform not recognized"); + } + +} diff --git a/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java b/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java index 7317a8eab1c..53693383eed 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java +++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,20 +76,19 @@ class DevPollArrayWrapper { // Base address of the native pollArray private long pollArrayAddress; + // Array of pollfd structs used for driver updates + private AllocatedNativeObject updatePollArray; + // Maximum number of POLL_FD structs to update at once - private int MAX_UPDATE_SIZE = 10000; + private int MAX_UPDATE_SIZE = Math.min(OPEN_MAX, 10000); DevPollArrayWrapper() { int allocationSize = NUM_POLLFDS * SIZE_POLLFD; pollArray = new AllocatedNativeObject(allocationSize, true); pollArrayAddress = pollArray.address(); + allocationSize = MAX_UPDATE_SIZE * SIZE_POLLFD; + updatePollArray = new AllocatedNativeObject(allocationSize, true); wfd = init(); - - for (int i=0; i<NUM_POLLFDS; i++) { - putDescriptor(i, 0); - putEventOps(i, 0); - putReventOps(i, 0); - } } // Machinery for remembering fd registration changes @@ -129,21 +128,11 @@ class DevPollArrayWrapper { register(wfd, fd0, POLLIN); } - void putEventOps(int i, int event) { - int offset = SIZE_POLLFD * i + EVENT_OFFSET; - pollArray.putShort(offset, (short)event); - } - void putReventOps(int i, int revent) { int offset = SIZE_POLLFD * i + REVENT_OFFSET; pollArray.putShort(offset, (short)revent); } - void putDescriptor(int i, int fd) { - int offset = SIZE_POLLFD * i + FD_OFFSET; - pollArray.putInt(offset, fd); - } - int getEventOps(int i) { int offset = SIZE_POLLFD * i + EVENT_OFFSET; return pollArray.getShort(offset); @@ -172,11 +161,12 @@ class DevPollArrayWrapper { } void closeDevPollFD() throws IOException { - FileDispatcher.closeIntFD(wfd); + FileDispatcherImpl.closeIntFD(wfd); pollArray.free(); + updatePollArray.free(); } - int poll(long timeout) { + int poll(long timeout) throws IOException { updateRegistrations(); updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd); for (int i=0; i<updated; i++) { @@ -189,60 +179,34 @@ class DevPollArrayWrapper { return updated; } - void updateRegistrations() { - // take snapshot of the updateList size to see if there are - // any registrations to update - int updateSize; + void updateRegistrations() throws IOException { + // Populate pollfd array with updated masks synchronized (updateList) { - updateSize = updateList.size(); - } - if (updateSize > 0) { - // Construct a pollfd array with updated masks; we may overallocate - // by some amount because if the events are already POLLREMOVE - // then the second pollfd of that pair will not be needed. The - // number of entries is limited to a reasonable number to avoid - // allocating a lot of memory. - int maxUpdates = Math.min(updateSize * 2, MAX_UPDATE_SIZE); - int allocationSize = maxUpdates * SIZE_POLLFD; - AllocatedNativeObject updatePollArray = - new AllocatedNativeObject(allocationSize, true); + while (updateList.size() > 0) { + // We have to insert a dummy node in between each + // real update to use POLLREMOVE on the fd first because + // otherwise the changes are simply OR'd together + int index = 0; + Updator u = null; + while ((u = updateList.poll()) != null) { + // First add pollfd struct to clear out this fd + putPollFD(updatePollArray, index, u.fd, POLLREMOVE); + index++; + // Now add pollfd to update this fd, if necessary + if (u.mask != POLLREMOVE) { + putPollFD(updatePollArray, index, u.fd, (short)u.mask); + index++; + } - try { - synchronized (updateList) { - while (updateList.size() > 0) { - // We have to insert a dummy node in between each - // real update to use POLLREMOVE on the fd first because - // otherwise the changes are simply OR'd together - int index = 0; - Updator u = null; - while ((u = updateList.poll()) != null) { - // First add pollfd struct to clear out this fd - putPollFD(updatePollArray, index, u.fd, POLLREMOVE); - index++; - // Now add pollfd to update this fd, if necessary - if (u.mask != POLLREMOVE) { - putPollFD(updatePollArray, index, u.fd, - (short)u.mask); - index++; - } - - // Check against the max allocation size; these are - // all we will process. Valid index ranges from 0 to - // (maxUpdates - 1) and we can use up to 2 per loop - if (index > maxUpdates - 2) - break; - } - // Register the changes with /dev/poll - registerMultiple(wfd, updatePollArray.address(), index); - } + // Check against the max update size; these are + // all we will process. Valid index ranges from 0 to + // (MAX_UPDATE_SIZE - 1) and we can use up to 2 per loop + if (index > MAX_UPDATE_SIZE - 2) + break; } - } finally { - // Free the native array - updatePollArray.free(); - // BUG: If an exception was thrown then the selector now believes - // that the last set of changes was updated but it probably - // was not. This should not be a likely occurrence. - } + // Register the changes with /dev/poll + registerMultiple(wfd, updatePollArray.address(), index); + } } } @@ -275,7 +239,8 @@ class DevPollArrayWrapper { private native int init(); private native void register(int wfd, int fd, int mask); - private native void registerMultiple(int wfd, long address, int len); + private native void registerMultiple(int wfd, long address, int len) + throws IOException; private native int poll0(long pollAddress, int numfds, long timeout, int wfd); private static native void interrupt(int fd); diff --git a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java index cdf19cda207..f3f26e48e7f 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -139,8 +139,8 @@ class DevPollSelectorImpl interruptTriggered = true; } - FileDispatcher.closeIntFD(fd0); - FileDispatcher.closeIntFD(fd1); + FileDispatcherImpl.closeIntFD(fd0); + FileDispatcherImpl.closeIntFD(fd1); pollWrapper.release(fd0); pollWrapper.closeDevPollFD(); diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPoll.java b/jdk/src/solaris/classes/sun/nio/ch/EPoll.java new file mode 100644 index 00000000000..065dced7a8a --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/ch/EPoll.java @@ -0,0 +1,121 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.io.IOException; +import sun.misc.Unsafe; + +/** + * Provides access to the Linux epoll facility. + */ + +class EPoll { + private EPoll() { } + + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + /** + * typedef union epoll_data { + * void *ptr; + * int fd; + * __uint32_t u32; + * __uint64_t u64; + * } epoll_data_t; + * + * struct epoll_event { + * __uint32_t events; + * epoll_data_t data; + * } + */ + private static final int SIZEOF_EPOLLEVENT = eventSize(); + private static final int OFFSETOF_EVENTS = eventsOffset(); + private static final int OFFSETOF_FD = dataOffset(); + + // opcodes + static final int EPOLL_CTL_ADD = 1; + static final int EPOLL_CTL_DEL = 2; + static final int EPOLL_CTL_MOD = 3; + + // flags + static final int EPOLLONESHOT = (1 << 30); + + /** + * Allocates a poll array to handle up to {@code count} events. + */ + static long allocatePollArray(int count) { + return unsafe.allocateMemory(count * SIZEOF_EPOLLEVENT); + } + + /** + * Free a poll array + */ + static void freePollArray(long address) { + unsafe.freeMemory(address); + } + + /** + * Returns event[i]; + */ + static long getEvent(long address, int i) { + return address + (SIZEOF_EPOLLEVENT*i); + } + + /** + * Returns event->data.fd + */ + static int getDescriptor(long eventAddress) { + return unsafe.getInt(eventAddress + OFFSETOF_FD); + } + + /** + * Returns event->events + */ + static int getEvents(long eventAddress) { + return unsafe.getInt(eventAddress + OFFSETOF_EVENTS); + } + + // -- Native methods -- + + private static native void init(); + + private static native int eventSize(); + + private static native int eventsOffset(); + + private static native int dataOffset(); + + static native int epollCreate() throws IOException; + + static native int epollCtl(int epfd, int opcode, int fd, int events); + + static native int epollWait(int epfd, long pollAddress, int numfds) + throws IOException; + + static { + Util.load(); + init(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java index d8542e1b03d..622ff8d4764 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,8 +78,8 @@ class EPollArrayWrapper { // Base address of the native pollArray private final long pollArrayAddress; - // Set of "idle" file descriptors - private final HashSet<Integer> idleSet; + // Set of "idle" channels + private final HashSet<SelChImpl> idleSet; EPollArrayWrapper() { // creates the epoll file descriptor @@ -96,19 +96,22 @@ class EPollArrayWrapper { } // create idle set - idleSet = new HashSet<Integer>(); + idleSet = new HashSet<SelChImpl>(); } // Used to update file description registrations private static class Updator { + SelChImpl channel; int opcode; - int fd; int events; - Updator(int opcode, int fd, int events) { + Updator(SelChImpl channel, int opcode, int events) { + this.channel = channel; this.opcode = opcode; - this.fd = fd; this.events = events; } + Updator(SelChImpl channel, int opcode) { + this(channel, opcode, 0); + } } private LinkedList<Updator> updateList = new LinkedList<Updator>(); @@ -163,60 +166,54 @@ class EPollArrayWrapper { } /** - * Update the events for a given file descriptor. + * Update the events for a given channel. */ - void setInterest(int fd, int mask) { + void setInterest(SelChImpl channel, int mask) { synchronized (updateList) { - - // if the interest events are 0 then add to idle set, and delete - // from epoll if registered (or pending) - if (mask == 0) { - if (idleSet.add(fd)) { - updateList.add(new Updator(EPOLL_CTL_DEL, fd, 0)); - } - return; - } - - // if file descriptor is idle then add to epoll - if (!idleSet.isEmpty() && idleSet.remove(fd)) { - updateList.add(new Updator(EPOLL_CTL_ADD, fd, mask)); - return; - } - // if the previous pending operation is to add this file descriptor // to epoll then update its event set if (updateList.size() > 0) { Updator last = updateList.getLast(); - if (last.fd == fd && last.opcode == EPOLL_CTL_ADD) { + if (last.channel == channel && last.opcode == EPOLL_CTL_ADD) { last.events = mask; return; } } // update existing registration - updateList.add(new Updator(EPOLL_CTL_MOD, fd, mask)); + updateList.add(new Updator(channel, EPOLL_CTL_MOD, mask)); } } /** - * Add a new file descriptor to epoll + * Add a channel's file descriptor to epoll */ - void add(int fd) { + void add(SelChImpl channel) { synchronized (updateList) { - updateList.add(new Updator(EPOLL_CTL_ADD, fd, 0)); + updateList.add(new Updator(channel, EPOLL_CTL_ADD)); } } /** - * Remove a file descriptor from epoll + * Remove a channel's file descriptor from epoll */ - void release(int fd) { + void release(SelChImpl channel) { synchronized (updateList) { - // if file descriptor is idle then remove from idle set, otherwise - // delete from epoll - if (!idleSet.remove(fd)) { - updateList.add(new Updator(EPOLL_CTL_DEL, fd, 0)); + // flush any pending updates + int i = 0; + while (i < updateList.size()) { + if (updateList.get(i).channel == channel) { + updateList.remove(i); + } else { + i++; + } } + + // remove from the idle set (if present) + idleSet.remove(channel); + + // remove from epoll (if registered) + epollCtl(epfd, EPOLL_CTL_DEL, channel.getFDVal(), 0); } } @@ -224,7 +221,7 @@ class EPollArrayWrapper { * Close epoll file descriptor and free poll array */ void closeEPollFD() throws IOException { - FileDispatcher.closeIntFD(epfd); + FileDispatcherImpl.closeIntFD(epfd); pollArray.free(); } @@ -248,7 +245,26 @@ class EPollArrayWrapper { synchronized (updateList) { Updator u = null; while ((u = updateList.poll()) != null) { - epollCtl(epfd, u.opcode, u.fd, u.events); + SelChImpl ch = u.channel; + if (!ch.isOpen()) + continue; + + // if the events are 0 then file descriptor is put into "idle + // set" to prevent it being polled + if (u.events == 0) { + boolean added = idleSet.add(u.channel); + // if added to idle set then remove from epoll if registered + if (added && (u.opcode == EPOLL_CTL_MOD)) + epollCtl(epfd, EPOLL_CTL_DEL, ch.getFDVal(), 0); + } else { + // events are specified. If file descriptor was in idle set + // it must be re-registered (by converting opcode to ADD) + boolean idle = false; + if (!idleSet.isEmpty()) + idle = idleSet.remove(u.channel); + int opcode = (idle) ? EPOLL_CTL_ADD : u.opcode; + epollCtl(epfd, opcode, ch.getFDVal(), u.events); + } } } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java b/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java new file mode 100644 index 00000000000..a79cb731841 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java @@ -0,0 +1,322 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.io.IOException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import static sun.nio.ch.EPoll.*; + +/** + * AsynchronousChannelGroup implementation based on the Linux epoll facility. + */ + +final class EPollPort + extends Port +{ + // maximum number of events to poll at a time + private static final int MAX_EPOLL_EVENTS = 512; + + // errors + private static final int ENOENT = 2; + + // epoll file descriptor + private final int epfd; + + // true if epoll closed + private boolean closed; + + // socket pair used for wakeup + private final int sp[]; + + // number of wakeups pending + private final AtomicInteger wakeupCount = new AtomicInteger(); + + // address of the poll array passed to epoll_wait + private final long address; + + // encapsulates an event for a channel + static class Event { + final PollableChannel channel; + final int events; + + Event(PollableChannel channel, int events) { + this.channel = channel; + this.events = events; + } + + PollableChannel channel() { return channel; } + int events() { return events; } + } + + // queue of events for cases that a polling thread dequeues more than one + // event + private final ArrayBlockingQueue<Event> queue; + private final Event NEED_TO_POLL = new Event(null, 0); + private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0); + + EPollPort(AsynchronousChannelProvider provider, ThreadPool pool) + throws IOException + { + super(provider, pool); + + // open epoll + this.epfd = epollCreate(); + + // create socket pair for wakeup mechanism + int[] sv = new int[2]; + try { + socketpair(sv); + // register one end with epoll + epollCtl(epfd, EPOLL_CTL_ADD, sv[0], POLLIN); + } catch (IOException x) { + close0(epfd); + throw x; + } + this.sp = sv; + + // allocate the poll array + this.address = allocatePollArray(MAX_EPOLL_EVENTS); + + // create the queue and offer the special event to ensure that the first + // threads polls + this.queue = new ArrayBlockingQueue<Event>(MAX_EPOLL_EVENTS); + this.queue.offer(NEED_TO_POLL); + } + + EPollPort start() { + startThreads(new EventHandlerTask()); + return this; + } + + /** + * Release all resources + */ + private void implClose() { + synchronized (this) { + if (closed) + return; + closed = true; + } + freePollArray(address); + close0(sp[0]); + close0(sp[1]); + close0(epfd); + } + + private void wakeup() { + if (wakeupCount.incrementAndGet() == 1) { + // write byte to socketpair to force wakeup + try { + interrupt(sp[1]); + } catch (IOException x) { + throw new AssertionError(x); + } + } + } + + @Override + void executeOnHandlerTask(Runnable task) { + synchronized (this) { + if (closed) + throw new RejectedExecutionException(); + offerTask(task); + wakeup(); + } + } + + @Override + void shutdownHandlerTasks() { + /* + * If no tasks are running then just release resources; otherwise + * write to the one end of the socketpair to wakeup any polling threads. + */ + int nThreads = threadCount(); + if (nThreads == 0) { + implClose(); + } else { + // send interrupt to each thread + while (nThreads-- > 0) { + wakeup(); + } + } + } + + // invoke by clients to register a file descriptor + @Override + void startPoll(int fd, int events) { + // update events (or add to epoll on first usage) + int err = epollCtl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT)); + if (err == ENOENT) + err = epollCtl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT)); + if (err != 0) + throw new AssertionError(); // should not happen + } + + /* + * Task to process events from epoll and dispatch to the channel's + * onEvent handler. + * + * Events are retreived from epoll in batch and offered to a BlockingQueue + * where they are consumed by handler threads. A special "NEED_TO_POLL" + * event is used to signal one consumer to re-poll when all events have + * been consumed. + */ + private class EventHandlerTask implements Runnable { + private Event poll() throws IOException { + try { + for (;;) { + int n = epollWait(epfd, address, MAX_EPOLL_EVENTS); + /* + * 'n' events have been read. Here we map them to their + * corresponding channel in batch and queue n-1 so that + * they can be handled by other handler threads. The last + * event is handled by this thread (and so is not queued). + */ + fdToChannelLock.readLock().lock(); + try { + while (n-- > 0) { + long eventAddress = getEvent(address, n); + int fd = getDescriptor(eventAddress); + + // wakeup + if (fd == sp[0]) { + if (wakeupCount.decrementAndGet() == 0) { + // no more wakeups so drain pipe + drain1(sp[0]); + } + + // queue special event if there are more events + // to handle. + if (n > 0) { + queue.offer(EXECUTE_TASK_OR_SHUTDOWN); + continue; + } + return EXECUTE_TASK_OR_SHUTDOWN; + } + + PollableChannel channel = fdToChannel.get(fd); + if (channel != null) { + int events = getEvents(eventAddress); + Event ev = new Event(channel, events); + + // n-1 events are queued; This thread handles + // the last one except for the wakeup + if (n > 0) { + queue.offer(ev); + } else { + return ev; + } + } + } + } finally { + fdToChannelLock.readLock().unlock(); + } + } + } finally { + // to ensure that some thread will poll when all events have + // been consumed + queue.offer(NEED_TO_POLL); + } + } + + public void run() { + Invoker.GroupAndInvokeCount myGroupAndInvokeCount = + Invoker.getGroupAndInvokeCount(); + boolean replaceMe = false; + Event ev; + try { + for (;;) { + // reset invoke count + if (myGroupAndInvokeCount != null) + myGroupAndInvokeCount.resetInvokeCount(); + + try { + replaceMe = false; + ev = queue.take(); + + // no events and this thread has been "selected" to + // poll for more. + if (ev == NEED_TO_POLL) { + try { + ev = poll(); + } catch (IOException x) { + x.printStackTrace(); + return; + } + } + } catch (InterruptedException x) { + continue; + } + + // handle wakeup to execute task or shutdown + if (ev == EXECUTE_TASK_OR_SHUTDOWN) { + Runnable task = pollTask(); + if (task == null) { + // shutdown request + return; + } + // run task (may throw error/exception) + replaceMe = true; + task.run(); + continue; + } + + // process event + try { + ev.channel().onEvent(ev.events()); + } catch (Error x) { + replaceMe = true; throw x; + } catch (RuntimeException x) { + replaceMe = true; throw x; + } + } + } finally { + // last handler to exit when shutdown releases resources + int remaining = threadExit(this, replaceMe); + if (remaining == 0 && isShutdown()) { + implClose(); + } + } + } + } + + // -- Native methods -- + + private static native void socketpair(int[] sv) throws IOException; + + private static native void interrupt(int fd) throws IOException; + + private static native void drain1(int fd) throws IOException; + + private static native void close0(int fd); + + static { + Util.load(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java index 5dc17bb014c..505d8b7bb4e 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,10 +136,9 @@ class EPollSelectorImpl interruptTriggered = true; } - FileDispatcher.closeIntFD(fd0); - FileDispatcher.closeIntFD(fd1); + FileDispatcherImpl.closeIntFD(fd0); + FileDispatcherImpl.closeIntFD(fd1); - pollWrapper.release(fd0); pollWrapper.closeEPollFD(); // it is possible selectedKeys = null; @@ -162,17 +161,18 @@ class EPollSelectorImpl protected void implRegister(SelectionKeyImpl ski) { if (closed) throw new ClosedSelectorException(); - int fd = IOUtil.fdVal(ski.channel.getFD()); - fdToKey.put(Integer.valueOf(fd), ski); - pollWrapper.add(fd); + SelChImpl ch = ski.channel; + fdToKey.put(Integer.valueOf(ch.getFDVal()), ski); + pollWrapper.add(ch); keys.add(ski); } protected void implDereg(SelectionKeyImpl ski) throws IOException { assert (ski.getIndex() >= 0); - int fd = ski.channel.getFDVal(); + SelChImpl ch = ski.channel; + int fd = ch.getFDVal(); fdToKey.remove(Integer.valueOf(fd)); - pollWrapper.release(fd); + pollWrapper.release(ch); ski.setIndex(-1); keys.remove(ski); selectedKeys.remove(ski); @@ -185,8 +185,7 @@ class EPollSelectorImpl void putEventOps(SelectionKeyImpl sk, int ops) { if (closed) throw new ClosedSelectorException(); - int fd = IOUtil.fdVal(sk.channel.getFD()); - pollWrapper.setInterest(fd, ops); + pollWrapper.setInterest(sk.channel, ops); } public Selector wakeup() { diff --git a/jdk/src/solaris/classes/sun/nio/ch/FileDispatcher.java b/jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java similarity index 72% rename from jdk/src/solaris/classes/sun/nio/ch/FileDispatcher.java rename to jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java index 335ac49b951..34d3451bb20 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/FileDispatcher.java +++ b/jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,12 +27,7 @@ package sun.nio.ch; import java.io.*; -/** - * Allows different platforms to call different native methods - * for read and write operations. - */ - -class FileDispatcher extends NativeDispatcher +class FileDispatcherImpl extends FileDispatcher { static { @@ -69,6 +64,28 @@ class FileDispatcher extends NativeDispatcher return writev0(fd, address, len); } + int force(FileDescriptor fd, boolean metaData) throws IOException { + return force0(fd, metaData); + } + + int truncate(FileDescriptor fd, long size) throws IOException { + return truncate0(fd, size); + } + + long size(FileDescriptor fd) throws IOException { + return size0(fd); + } + + int lock(FileDescriptor fd, boolean blocking, long pos, long size, + boolean shared) throws IOException + { + return lock0(fd, blocking, pos, size, shared); + } + + void release(FileDescriptor fd, long pos, long size) throws IOException { + release0(fd, pos, size); + } + void close(FileDescriptor fd) throws IOException { close0(fd); } @@ -97,6 +114,20 @@ class FileDispatcher extends NativeDispatcher static native long writev0(FileDescriptor fd, long address, int len) throws IOException; + static native int force0(FileDescriptor fd, boolean metaData) + throws IOException; + + static native int truncate0(FileDescriptor fd, long size) + throws IOException; + + static native long size0(FileDescriptor fd) throws IOException; + + static native int lock0(FileDescriptor fd, boolean blocking, long pos, + long size, boolean shared) throws IOException; + + static native void release0(FileDescriptor fd, long pos, long size) + throws IOException; + static native void close0(FileDescriptor fd) throws IOException; static native void preClose0(FileDescriptor fd) throws IOException; diff --git a/jdk/src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java b/jdk/src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java new file mode 100644 index 00000000000..775380e8bc6 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java @@ -0,0 +1,99 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.net.ProtocolFamily; +import java.io.IOException; + +public class LinuxAsynchronousChannelProvider + extends AsynchronousChannelProvider +{ + private static volatile EPollPort defaultPort; + + private EPollPort defaultEventPort() throws IOException { + if (defaultPort == null) { + synchronized (LinuxAsynchronousChannelProvider.class) { + if (defaultPort == null) { + defaultPort = new EPollPort(this, ThreadPool.getDefault()).start(); + } + } + } + return defaultPort; + } + + public LinuxAsynchronousChannelProvider() { + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory) + throws IOException + { + return new EPollPort(this, ThreadPool.create(nThreads, factory)).start(); + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) + throws IOException + { + return new EPollPort(this, ThreadPool.wrap(executor, initialSize)).start(); + } + + private Port toPort(AsynchronousChannelGroup group) throws IOException { + if (group == null) { + return defaultEventPort(); + } else { + if (!(group instanceof EPollPort)) + throw new IllegalChannelGroupException(); + return (Port)group; + } + } + + @Override + public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new UnixAsynchronousServerSocketChannelImpl(toPort(group)); + } + + @Override + public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new UnixAsynchronousSocketChannelImpl(toPort(group)); + } + + @Override + public AsynchronousDatagramChannel openAsynchronousDatagramChannel(ProtocolFamily family, + AsynchronousChannelGroup group) + throws IOException + { + return new SimpleAsynchronousDatagramChannelImpl(family, toPort(group)); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java index ab135c9b105..05fbda57d97 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,8 +93,8 @@ class PollSelectorImpl synchronized (interruptLock) { interruptTriggered = true; } - FileDispatcher.closeIntFD(fd0); - FileDispatcher.closeIntFD(fd1); + FileDispatcherImpl.closeIntFD(fd0); + FileDispatcherImpl.closeIntFD(fd1); fd0 = -1; fd1 = -1; pollWrapper.release(0); diff --git a/jdk/src/solaris/classes/sun/nio/ch/Port.java b/jdk/src/solaris/classes/sun/nio/ch/Port.java new file mode 100644 index 00000000000..8b19637bc2a --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/ch/Port.java @@ -0,0 +1,168 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.nio.channels.*; +import java.io.IOException; +import java.io.Closeable; +import java.io.FileDescriptor; +import java.util.Map; +import java.util.HashMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * Base implementation of AsynchronousChannelGroupImpl for Unix systems. + */ + +abstract class Port extends AsynchronousChannelGroupImpl { + static final short POLLIN = 0x0001; + static final short POLLOUT = 0x0004; + static final short POLLERR = 0x0008; + static final short POLLHUP = 0x0010; + + /** + * Implemented by clients registered with this port. + */ + interface PollableChannel extends Closeable { + void onEvent(int events); + } + + // maps fd to "pollable" channel + protected final ReadWriteLock fdToChannelLock = new ReentrantReadWriteLock(); + protected final Map<Integer,PollableChannel> fdToChannel = + new HashMap<Integer,PollableChannel>(); + + + Port(AsynchronousChannelProvider provider, ThreadPool pool) { + super(provider, pool); + } + + /** + * Register channel identified by its file descriptor + */ + final void register(int fd, PollableChannel ch) { + fdToChannelLock.writeLock().lock(); + try { + if (isShutdown()) + throw new ShutdownChannelGroupException(); + fdToChannel.put(Integer.valueOf(fd), ch); + } finally { + fdToChannelLock.writeLock().unlock(); + } + } + + /** + * Unregister channel identified by its file descriptor + */ + final void unregister(int fd) { + boolean checkForShutdown = false; + + fdToChannelLock.writeLock().lock(); + try { + fdToChannel.remove(Integer.valueOf(fd)); + + // last key to be removed so check if group is shutdown + if (fdToChannel.isEmpty()) + checkForShutdown = true; + + } finally { + fdToChannelLock.writeLock().unlock(); + } + + // continue shutdown + if (checkForShutdown && isShutdown()) { + try { + shutdownNow(); + } catch (IOException ignore) { } + } + } + /** + * Register file descriptor with polling mechanism for given events. + * The implementation should translate the events as required. + */ + abstract void startPoll(int fd, int events); + + @Override + final boolean isEmpty() { + fdToChannelLock.writeLock().lock(); + try { + return fdToChannel.isEmpty(); + } finally { + fdToChannelLock.writeLock().unlock(); + } + } + + @Override + final Object attachForeignChannel(final Channel channel, FileDescriptor fd) { + int fdVal = IOUtil.fdVal(fd); + register(fdVal, new PollableChannel() { + public void onEvent(int events) { } + public void close() throws IOException { + channel.close(); + } + }); + return Integer.valueOf(fdVal); + } + + @Override + final void detachForeignChannel(Object key) { + unregister((Integer)key); + } + + @Override + final void closeAllChannels() { + /** + * Close channels in batches of up to 128 channels. This allows close + * to remove the channel from the map without interference. + */ + final int MAX_BATCH_SIZE = 128; + PollableChannel channels[] = new PollableChannel[MAX_BATCH_SIZE]; + int count; + do { + // grab a batch of up to 128 channels + fdToChannelLock.writeLock().lock(); + count = 0; + try { + for (Integer fd: fdToChannel.keySet()) { + channels[count++] = fdToChannel.get(fd); + if (count >= MAX_BATCH_SIZE) + break; + } + } finally { + fdToChannelLock.writeLock().unlock(); + } + + // close them + for (int i=0; i<count; i++) { + try { + channels[i].close(); + } catch (IOException ignore) { } + } + } while (count > 0); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java index bc58ba9ab3c..ced3b608e77 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,7 +208,7 @@ class SinkChannelImpl static { Util.load(); - nd = new FileDispatcher(); + nd = new FileDispatcherImpl(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java b/jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java index 46c8e135e02..fc884c4c9a0 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,26 +36,26 @@ class SocketDispatcher extends NativeDispatcher { int read(FileDescriptor fd, long address, int len) throws IOException { - return FileDispatcher.read0(fd, address, len); + return FileDispatcherImpl.read0(fd, address, len); } long readv(FileDescriptor fd, long address, int len) throws IOException { - return FileDispatcher.readv0(fd, address, len); + return FileDispatcherImpl.readv0(fd, address, len); } int write(FileDescriptor fd, long address, int len) throws IOException { - return FileDispatcher.write0(fd, address, len); + return FileDispatcherImpl.write0(fd, address, len); } long writev(FileDescriptor fd, long address, int len) throws IOException { - return FileDispatcher.writev0(fd, address, len); + return FileDispatcherImpl.writev0(fd, address, len); } void close(FileDescriptor fd) throws IOException { - FileDispatcher.close0(fd); + FileDispatcherImpl.close0(fd); } void preClose(FileDescriptor fd) throws IOException { - FileDispatcher.preClose0(fd); + FileDispatcherImpl.preClose0(fd); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java b/jdk/src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java new file mode 100644 index 00000000000..0da0935cac7 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java @@ -0,0 +1,102 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.net.ProtocolFamily; +import java.io.IOException; + +public class SolarisAsynchronousChannelProvider + extends AsynchronousChannelProvider +{ + private static volatile SolarisEventPort defaultEventPort; + + private SolarisEventPort defaultEventPort() throws IOException { + if (defaultEventPort == null) { + synchronized (SolarisAsynchronousChannelProvider.class) { + if (defaultEventPort == null) { + defaultEventPort = + new SolarisEventPort(this, ThreadPool.getDefault()).start(); + } + } + } + return defaultEventPort; + } + + public SolarisAsynchronousChannelProvider() { + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory) + throws IOException + { + return new SolarisEventPort(this, ThreadPool.create(nThreads, factory)).start(); + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) + throws IOException + { + return new SolarisEventPort(this, ThreadPool.wrap(executor, initialSize)).start(); + } + + private SolarisEventPort toEventPort(AsynchronousChannelGroup group) + throws IOException + { + if (group == null) { + return defaultEventPort(); + } else { + if (!(group instanceof SolarisEventPort)) + throw new IllegalChannelGroupException(); + return (SolarisEventPort)group; + } + } + + @Override + public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new UnixAsynchronousServerSocketChannelImpl(toEventPort(group)); + } + + @Override + public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new UnixAsynchronousSocketChannelImpl(toEventPort(group)); + } + + @Override + public AsynchronousDatagramChannel openAsynchronousDatagramChannel(ProtocolFamily family, + AsynchronousChannelGroup group) + throws IOException + { + return new SimpleAsynchronousDatagramChannelImpl(family, toEventPort(group)); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java b/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java new file mode 100644 index 00000000000..908eecce024 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java @@ -0,0 +1,244 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.util.concurrent.RejectedExecutionException; +import java.io.IOException; +import sun.misc.Unsafe; + +/** + * AsynchronousChannelGroup implementation based on the Solaris 10 event port + * framework. + */ + +class SolarisEventPort + extends Port +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final int addressSize = unsafe.addressSize(); + + private static int dependsArch(int value32, int value64) { + return (addressSize == 4) ? value32 : value64; + } + + /* + * typedef struct port_event { + * int portev_events; + * ushort_t portev_source; + * ushort_t portev_pad; + * uintptr_t portev_object; + * void *portev_user; + * } port_event_t; + */ + private static final int SIZEOF_PORT_EVENT = dependsArch(16, 24); + private static final int OFFSETOF_EVENTS = 0; + private static final int OFFSETOF_SOURCE = 4; + private static final int OFFSETOF_OBJECT = 8; + + // port sources + private static final short PORT_SOURCE_USER = 3; + private static final short PORT_SOURCE_FD = 4; + + // file descriptor to event port. + private final int port; + + // true when port is closed + private boolean closed; + + SolarisEventPort(AsynchronousChannelProvider provider, ThreadPool pool) + throws IOException + { + super(provider, pool); + + // create event port + this.port = portCreate(); + } + + SolarisEventPort start() { + startThreads(new EventHandlerTask()); + return this; + } + + // releass resources + private void implClose() { + synchronized (this) { + if (closed) + return; + closed = true; + } + portClose(port); + } + + private void wakeup() { + try { + portSend(port, 0); + } catch (IOException x) { + throw new AssertionError(x); + } + } + + @Override + void executeOnHandlerTask(Runnable task) { + synchronized (this) { + if (closed) + throw new RejectedExecutionException(); + offerTask(task); + wakeup(); + } + } + + @Override + void shutdownHandlerTasks() { + /* + * If no tasks are running then just release resources; otherwise + * write to the one end of the socketpair to wakeup any polling threads.. + */ + int nThreads = threadCount(); + if (nThreads == 0) { + implClose(); + } else { + // send user event to wakeup each thread + while (nThreads-- > 0) { + try { + portSend(port, 0); + } catch (IOException x) { + throw new AssertionError(x); + } + } + } + } + + @Override + void startPoll(int fd, int events) { + // (re-)associate file descriptor + // no need to translate events + try { + portAssociate(port, PORT_SOURCE_FD, fd, events); + } catch (IOException x) { + throw new AssertionError(); // should not happen + } + } + + /* + * Task to read a single event from the port and dispatch it to the + * channel's onEvent handler. + */ + private class EventHandlerTask implements Runnable { + public void run() { + Invoker.GroupAndInvokeCount myGroupAndInvokeCount = + Invoker.getGroupAndInvokeCount(); + boolean replaceMe = false; + long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT); + try { + for (;;) { + // reset invoke count + if (myGroupAndInvokeCount != null) + myGroupAndInvokeCount.resetInvokeCount(); + + // wait for I/O completion event + // A error here is fatal (thread will not be replaced) + replaceMe = false; + try { + portGet(port, address); + } catch (IOException x) { + x.printStackTrace(); + return; + } + + // event source + short source = unsafe.getShort(address + OFFSETOF_SOURCE); + if (source != PORT_SOURCE_FD) { + // user event is trigger to invoke task or shutdown + if (source == PORT_SOURCE_USER) { + Runnable task = pollTask(); + if (task == null) { + // shutdown request + return; + } + // run task (may throw error/exception) + replaceMe = true; + task.run(); + } + // ignore + continue; + } + + // pe->portev_object is file descriptor + int fd = (int)unsafe.getAddress(address + OFFSETOF_OBJECT); + // pe->portev_events + int events = unsafe.getInt(address + OFFSETOF_EVENTS); + + // lookup channel + PollableChannel ch; + fdToChannelLock.readLock().lock(); + try { + ch = fdToChannel.get(fd); + } finally { + fdToChannelLock.readLock().unlock(); + } + + // notify channel + if (ch != null) { + replaceMe = true; + // no need to translate events + ch.onEvent(events); + } + } + } finally { + // free per-thread resources + unsafe.freeMemory(address); + // last task to exit when shutdown release resources + int remaining = threadExit(this, replaceMe); + if (remaining == 0 && isShutdown()) + implClose(); + } + } + } + + // -- Native methods -- + + private static native void init(); + + private static native int portCreate() throws IOException; + + private static native void portAssociate(int port, int source, long object, + int events) throws IOException; + + private static native void portGet(int port, long pe) throws IOException; + + private static native int portGetn(int port, long address, int max) + throws IOException; + + private static native void portSend(int port, int events) throws IOException; + + private static native void portClose(int port); + + static { + Util.load(); + init(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java index a55543e923e..e1080c917d1 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,7 +208,7 @@ class SourceChannelImpl static { Util.load(); - nd = new FileDispatcher(); + nd = new FileDispatcherImpl(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java new file mode 100644 index 00000000000..1a8c92352d2 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java @@ -0,0 +1,327 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.util.concurrent.*; +import java.io.IOException; +import java.io.FileDescriptor; +import java.net.InetSocketAddress; +import java.util.concurrent.atomic.AtomicBoolean; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Unix implementation of AsynchronousServerSocketChannel + */ + +class UnixAsynchronousServerSocketChannelImpl + extends AsynchronousServerSocketChannelImpl + implements Port.PollableChannel +{ + private final static NativeDispatcher nd = new SocketDispatcher(); + + private final Port port; + private final int fdVal; + + // flag to indicate an accept is outstanding + private final AtomicBoolean accepting = new AtomicBoolean(); + private void enableAccept() { + accepting.set(false); + } + + // used to ensure that the context for an asynchronous accept is visible + // the pooled thread that handles the I/O event + private final Object updateLock = new Object(); + + // pending accept + private PendingFuture<AsynchronousSocketChannel,Object> pendingAccept; + + // context for permission check when security manager set + private AccessControlContext acc; + + + UnixAsynchronousServerSocketChannelImpl(Port port) + throws IOException + { + super(port); + + try { + IOUtil.configureBlocking(fd, false); + } catch (IOException x) { + nd.close(fd); // prevent leak + throw x; + } + this.port = port; + this.fdVal = IOUtil.fdVal(fd); + + // add mapping from file descriptor to this channel + port.register(fdVal, this); + } + + // returns and clears the result of a pending accept + private PendingFuture<AsynchronousSocketChannel,Object> grabPendingAccept() { + synchronized (updateLock) { + PendingFuture<AsynchronousSocketChannel,Object> result = pendingAccept; + pendingAccept = null; + return result; + } + } + + @Override + void implClose() throws IOException { + // remove the mapping + port.unregister(fdVal); + + // close file descriptor + nd.close(fd); + + // if there is a pending accept then complete it + final PendingFuture<AsynchronousSocketChannel,Object> result = + grabPendingAccept(); + if (result != null) { + // discard the stack trace as otherwise it may appear that implClose + // has thrown the exception. + AsynchronousCloseException x = new AsynchronousCloseException(); + x.setStackTrace(new StackTraceElement[0]); + result.setFailure(x); + + // invoke by submitting task rather than directly + Invoker.invokeIndirectly(result.handler(), result); + } + } + + @Override + public AsynchronousChannelGroupImpl group() { + return port; + } + + /** + * Invoked by event handling thread when listener socket is polled + */ + @Override + public void onEvent(int events) { + PendingFuture<AsynchronousSocketChannel,Object> result = grabPendingAccept(); + if (result == null) + return; // may have been grabbed by asynchronous close + + // attempt to accept connection + FileDescriptor newfd = new FileDescriptor(); + InetSocketAddress[] isaa = new InetSocketAddress[1]; + boolean accepted = false; + try { + begin(); + int n = accept0(this.fd, newfd, isaa); + + // spurious wakeup, is this possible? + if (n == IOStatus.UNAVAILABLE) { + synchronized (updateLock) { + this.pendingAccept = result; + } + port.startPoll(fdVal, Port.POLLIN); + return; + } + + // connection accepted + accepted = true; + + } catch (Throwable x) { + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + enableAccept(); + result.setFailure(x); + } finally { + end(); + } + + // Connection accepted so finish it when not holding locks. + AsynchronousSocketChannel child = null; + if (accepted) { + try { + child = finishAccept(newfd, isaa[0], acc); + enableAccept(); + result.setResult(child); + } catch (Throwable x) { + enableAccept(); + if (!(x instanceof IOException) && !(x instanceof SecurityException)) + x = new IOException(x); + result.setFailure(x); + } + } + + // if an async cancel has already cancelled the operation then + // close the new channel so as to free resources + if (child != null && result.isCancelled()) { + try { + child.close(); + } catch (IOException ignore) { } + } + + // invoke the handler + Invoker.invoke(result.handler(), result); + } + + /** + * Completes the accept by creating the AsynchronousSocketChannel for + * the given file descriptor and remote address. If this method completes + * with an IOException or SecurityException then the channel/file descriptor + * will be closed. + */ + private AsynchronousSocketChannel finishAccept(FileDescriptor newfd, + final InetSocketAddress remote, + AccessControlContext acc) + throws IOException, SecurityException + { + AsynchronousSocketChannel ch = null; + try { + ch = new UnixAsynchronousSocketChannelImpl(port, newfd, remote); + } catch (IOException x) { + nd.close(newfd); + throw x; + } + + // permission check must always be in initiator's context + try { + if (acc != null) { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkAccept(remote.getAddress().getHostAddress(), + remote.getPort()); + } + return null; + } + }, acc); + } else { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkAccept(remote.getAddress().getHostAddress(), + remote.getPort()); + } + } + } catch (SecurityException x) { + try { + ch.close(); + } catch (IOException ignore) { } + throw x; + } + return ch; + } + + @Override + @SuppressWarnings("unchecked") + public <A> Future<AsynchronousSocketChannel> accept(A attachment, + final CompletionHandler<AsynchronousSocketChannel,? super A> handler) + { + // complete immediately if channel is closed + if (!isOpen()) { + CompletedFuture<AsynchronousSocketChannel,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invokeIndirectly(handler, result); + return result; + } + if (localAddress == null) + throw new NotYetBoundException(); + + // cancel was invoked with pending accept so connection may have been + // dropped. + if (isAcceptKilled()) + throw new RuntimeException("Accept not allowed due cancellation"); + + // check and set flag to prevent concurrent accepting + if (!accepting.compareAndSet(false, true)) + throw new AcceptPendingException(); + + // attempt accept + AbstractFuture<AsynchronousSocketChannel,A> result = null; + FileDescriptor newfd = new FileDescriptor(); + InetSocketAddress[] isaa = new InetSocketAddress[1]; + try { + begin(); + + int n = accept0(this.fd, newfd, isaa); + if (n == IOStatus.UNAVAILABLE) { + // no connection to accept + result = new PendingFuture<AsynchronousSocketChannel,A>(this, handler, attachment); + + // need calling context when there is security manager as + // permission check may be done in a different thread without + // any application call frames on the stack + synchronized (this) { + this.acc = (System.getSecurityManager() == null) ? + null : AccessController.getContext(); + this.pendingAccept = + (PendingFuture<AsynchronousSocketChannel,Object>)result; + } + + // register for connections + port.startPoll(fdVal, Port.POLLIN); + return result; + } + } catch (Throwable x) { + // accept failed + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + result = CompletedFuture.withFailure(this, x, attachment); + } finally { + end(); + } + + // connection accepted immediately + if (result == null) { + try { + AsynchronousSocketChannel ch = finishAccept(newfd, isaa[0], null); + result = CompletedFuture.withResult(this, ch, attachment); + } catch (Throwable x) { + result = CompletedFuture.withFailure(this, x, attachment); + } + } + + // re-enable accepting and invoke handler + enableAccept(); + Invoker.invokeIndirectly(handler, result); + return result; + } + + // -- Native methods -- + + private static native void initIDs(); + + // Accepts a new connection, setting the given file descriptor to refer to + // the new socket and setting isaa[0] to the socket's remote address. + // Returns 1 on success, or IOStatus.UNAVAILABLE. + // + private native int accept0(FileDescriptor ssfd, FileDescriptor newfd, + InetSocketAddress[] isaa) + throws IOException; + + static { + Util.load(); + initIDs(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java new file mode 100644 index 00000000000..e80f202bdff --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java @@ -0,0 +1,679 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.nio.ByteBuffer; +import java.net.*; +import java.util.concurrent.*; +import java.io.IOException; +import java.io.FileDescriptor; +import java.security.AccessController; +import sun.net.NetHooks; +import sun.security.action.GetPropertyAction; + +/** + * Unix implementation of AsynchronousSocketChannel + */ + +class UnixAsynchronousSocketChannelImpl + extends AsynchronousSocketChannelImpl implements Port.PollableChannel +{ + private final static NativeDispatcher nd = new SocketDispatcher(); + private static enum OpType { CONNECT, READ, WRITE }; + + private static final boolean disableSynchronousRead; + static { + String propValue = AccessController.doPrivileged( + new GetPropertyAction("sun.nio.ch.disableSynchronousRead", "false")); + disableSynchronousRead = (propValue.length() == 0) ? + true : Boolean.valueOf(propValue); + } + + private final Port port; + private final int fdVal; + + // used to ensure that the context for I/O operations that complete + // ascynrhonously is visible to the pooled threads handling I/O events. + private final Object updateLock = new Object(); + + // pending connect (updateLock) + private PendingFuture<Void,Object> pendingConnect; + + // pending remote address (statLock) + private SocketAddress pendingRemote; + + // pending read (updateLock) + private ByteBuffer[] readBuffers; + private boolean scatteringRead; + private PendingFuture<Number,Object> pendingRead; + + // pending write (updateLock) + private ByteBuffer[] writeBuffers; + private boolean gatheringWrite; + private PendingFuture<Number,Object> pendingWrite; + + + UnixAsynchronousSocketChannelImpl(Port port) + throws IOException + { + super(port); + + // set non-blocking + try { + IOUtil.configureBlocking(fd, false); + } catch (IOException x) { + nd.close(fd); + throw x; + } + + this.port = port; + this.fdVal = IOUtil.fdVal(fd); + + // add mapping from file descriptor to this channel + port.register(fdVal, this); + } + + // Constructor for sockets created by UnixAsynchronousServerSocketChannelImpl + UnixAsynchronousSocketChannelImpl(Port port, + FileDescriptor fd, + InetSocketAddress remote) + throws IOException + { + super(port, fd, remote); + + this.fdVal = IOUtil.fdVal(fd); + IOUtil.configureBlocking(fd, false); + + try { + port.register(fdVal, this); + } catch (ShutdownChannelGroupException x) { + // ShutdownChannelGroupException thrown if we attempt to register a + // new channel after the group is shutdown + throw new IOException(x); + } + + this.port = port; + } + + @Override + public AsynchronousChannelGroupImpl group() { + return port; + } + + // register for events if there are outstanding I/O operations + private void updateEvents() { + assert Thread.holdsLock(updateLock); + int events = 0; + if (pendingRead != null) + events |= Port.POLLIN; + if (pendingConnect != null || pendingWrite != null) + events |= Port.POLLOUT; + if (events != 0) + port.startPoll(fdVal, events); + } + + /** + * Invoked by event handler thread when file descriptor is polled + */ + @Override + public void onEvent(int events) { + boolean readable = (events & Port.POLLIN) > 0; + boolean writable = (events & Port.POLLOUT) > 0; + if ((events & (Port.POLLERR | Port.POLLHUP)) > 0) { + readable = true; + writable = true; + } + + PendingFuture<Void,Object> connectResult = null; + PendingFuture<Number,Object> readResult = null; + PendingFuture<Number,Object> writeResult = null; + + // map event to pending result + synchronized (updateLock) { + if (readable && (pendingRead != null)) { + readResult = pendingRead; + pendingRead = null; + } + if (writable) { + if (pendingWrite != null) { + writeResult = pendingWrite; + pendingWrite = null; + } else if (pendingConnect != null) { + connectResult = pendingConnect; + pendingConnect = null; + } + } + } + + // complete the I/O operation. Special case for when channel is + // ready for both reading and writing. In that case, submit task to + // complete write if write operation has a completion handler. + if (readResult != null) { + if (writeResult != null) + finishWrite(writeResult, false); + finishRead(readResult, true); + return; + } + if (writeResult != null) { + finishWrite(writeResult, true); + } + if (connectResult != null) { + finishConnect(connectResult, true); + } + } + + // returns and clears the result of a pending read + PendingFuture<Number,Object> grabPendingRead() { + synchronized (updateLock) { + PendingFuture<Number,Object> result = pendingRead; + pendingRead = null; + return result; + } + } + + // returns and clears the result of a pending write + PendingFuture<Number,Object> grabPendingWrite() { + synchronized (updateLock) { + PendingFuture<Number,Object> result = pendingWrite; + pendingWrite = null; + return result; + } + } + + @Override + void implClose() throws IOException { + // remove the mapping + port.unregister(fdVal); + + // close file descriptor + nd.close(fd); + + // All outstanding I/O operations are required to fail + final PendingFuture<Void,Object> readyToConnect; + final PendingFuture<Number,Object> readyToRead; + final PendingFuture<Number,Object> readyToWrite; + synchronized (updateLock) { + readyToConnect = pendingConnect; + pendingConnect = null; + readyToRead = pendingRead; + pendingRead = null; + readyToWrite = pendingWrite; + pendingWrite = null; + } + if (readyToConnect != null) { + finishConnect(readyToConnect, false); + } + if (readyToRead != null) { + finishRead(readyToRead, false); + } + if (readyToWrite != null) { + finishWrite(readyToWrite, false); + } + } + + @Override + public void onCancel(PendingFuture<?,?> task) { + if (task.getContext() == OpType.CONNECT) + killConnect(); + if (task.getContext() == OpType.READ) + killConnect(); + if (task.getContext() == OpType.WRITE) + killConnect(); + } + + // -- connect -- + + private void setConnected() throws IOException { + synchronized (stateLock) { + state = ST_CONNECTED; + localAddress = Net.localAddress(fd); + remoteAddress = pendingRemote; + } + } + + private void finishConnect(PendingFuture<Void,Object> result, + boolean invokeDirect) + { + Throwable e = null; + try { + begin(); + checkConnect(fdVal); + setConnected(); + result.setResult(null); + } catch (Throwable x) { + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + e = x; + } finally { + end(); + } + if (e != null) { + // close channel if connection cannot be established + try { + close(); + } catch (IOException ignore) { } + result.setFailure(e); + } + if (invokeDirect) { + Invoker.invoke(result.handler(), result); + } else { + Invoker.invokeIndirectly(result.handler(), result); + } + } + + @Override + @SuppressWarnings("unchecked") + public <A> Future<Void> connect(SocketAddress remote, + A attachment, + CompletionHandler<Void,? super A> handler) + { + if (!isOpen()) { + CompletedFuture<Void,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + InetSocketAddress isa = Net.checkAddress(remote); + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); + + // check and set state + boolean notifyBeforeTcpConnect; + synchronized (stateLock) { + if (state == ST_CONNECTED) + throw new AlreadyConnectedException(); + if (state == ST_PENDING) + throw new ConnectionPendingException(); + state = ST_PENDING; + pendingRemote = remote; + notifyBeforeTcpConnect = (localAddress == null); + } + + AbstractFuture<Void,A> result = null; + Throwable e = null; + try { + begin(); + // notify hook if unbound + if (notifyBeforeTcpConnect) + NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort()); + int n = Net.connect(fd, isa.getAddress(), isa.getPort()); + if (n == IOStatus.UNAVAILABLE) { + // connection could not be established immediately + result = new PendingFuture<Void,A>(this, handler, attachment, OpType.CONNECT); + synchronized (updateLock) { + this.pendingConnect = (PendingFuture<Void,Object>)result; + updateEvents(); + } + return result; + } + setConnected(); + result = CompletedFuture.withResult(this, null, attachment); + } catch (Throwable x) { + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + e = x; + } finally { + end(); + } + + // close channel if connect fails + if (e != null) { + try { + close(); + } catch (IOException ignore) { } + result = CompletedFuture.withFailure(this, e, attachment); + } + + Invoker.invoke(handler, result); + return result; + } + + // -- read -- + + @SuppressWarnings("unchecked") + private void finishRead(PendingFuture<Number,Object> result, + boolean invokeDirect) + { + int n = -1; + PendingFuture<Number,Object> pending = null; + try { + begin(); + + ByteBuffer[] dsts = readBuffers; + if (dsts.length == 1) { + n = IOUtil.read(fd, dsts[0], -1, nd, null); + } else { + n = (int)IOUtil.read(fd, dsts, nd); + } + if (n == IOStatus.UNAVAILABLE) { + // spurious wakeup, is this possible? + pending = result; + return; + } + + // allow buffer(s) to be GC'ed. + readBuffers = null; + + // allow another read to be initiated + boolean wasScatteringRead = scatteringRead; + enableReading(); + + // result is Integer or Long + if (wasScatteringRead) { + result.setResult(Long.valueOf(n)); + } else { + result.setResult(Integer.valueOf(n)); + } + + } catch (Throwable x) { + enableReading(); + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + result.setFailure(x); + } finally { + // restart poll in case of concurrent write + synchronized (updateLock) { + if (pending != null) + this.pendingRead = pending; + updateEvents(); + } + end(); + } + + if (invokeDirect) { + Invoker.invoke(result.handler(), result); + } else { + Invoker.invokeIndirectly(result.handler(), result); + } + } + + private Runnable readTimeoutTask = new Runnable() { + public void run() { + PendingFuture<Number,Object> result = grabPendingRead(); + if (result == null) + return; // already completed + + // kill further reading before releasing waiters + enableReading(true); + + // set completed and invoke handler + result.setFailure(new InterruptedByTimeoutException()); + Invoker.invokeIndirectly(result.handler(), result); + } + }; + + /** + * Initiates a read or scattering read operation + */ + @Override + @SuppressWarnings("unchecked") + <V extends Number,A> Future<V> readImpl(ByteBuffer[] dsts, + boolean isScatteringRead, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<V,? super A> handler) + { + // A synchronous read is not attempted if disallowed by system property + // or, we are using a fixed thread pool and the completion handler may + // not be invoked directly (because the thread is not a pooled thread or + // there are too many handlers on the stack). + Invoker.GroupAndInvokeCount myGroupAndInvokeCount = null; + boolean invokeDirect = false; + boolean attemptRead = false; + if (!disableSynchronousRead) { + myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); + invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port); + attemptRead = (handler == null) || invokeDirect || + !port.isFixedThreadPool(); // okay to attempt read with user thread pool + } + + AbstractFuture<V,A> result; + try { + begin(); + + int n; + if (attemptRead) { + if (isScatteringRead) { + n = (int)IOUtil.read(fd, dsts, nd); + } else { + n = IOUtil.read(fd, dsts[0], -1, nd, null); + } + } else { + n = IOStatus.UNAVAILABLE; + } + + if (n == IOStatus.UNAVAILABLE) { + result = new PendingFuture<V,A>(this, handler, attachment, OpType.READ); + + // update evetns so that read will complete asynchronously + synchronized (updateLock) { + this.readBuffers = dsts; + this.scatteringRead = isScatteringRead; + this.pendingRead = (PendingFuture<Number,Object>)result; + updateEvents(); + } + + // schedule timeout + if (timeout > 0L) { + Future<?> timeoutTask = + port.schedule(readTimeoutTask, timeout, unit); + ((PendingFuture<V,A>)result).setTimeoutTask(timeoutTask); + } + return result; + } + + // data available + enableReading(); + + // result type is Long or Integer + if (isScatteringRead) { + result = (CompletedFuture<V,A>)CompletedFuture + .withResult(this, Long.valueOf(n), attachment); + } else { + result = (CompletedFuture<V,A>)CompletedFuture + .withResult(this, Integer.valueOf(n), attachment); + } + } catch (Throwable x) { + enableReading(); + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + result = CompletedFuture.withFailure(this, x, attachment); + } finally { + end(); + } + + if (invokeDirect) { + Invoker.invokeDirect(myGroupAndInvokeCount, handler, result); + } else { + Invoker.invokeIndirectly(handler, result); + } + return result; + } + + // -- write -- + + private void finishWrite(PendingFuture<Number,Object> result, + boolean invokeDirect) + { + PendingFuture<Number,Object> pending = null; + try { + begin(); + + ByteBuffer[] srcs = writeBuffers; + int n; + if (srcs.length == 1) { + n = IOUtil.write(fd, srcs[0], -1, nd, null); + } else { + n = (int)IOUtil.write(fd, srcs, nd); + } + if (n == IOStatus.UNAVAILABLE) { + // spurious wakeup, is this possible? + pending = result; + return; + } + + // allow buffer(s) to be GC'ed. + writeBuffers = null; + + // allow another write to be initiated + boolean wasGatheringWrite = gatheringWrite; + enableWriting(); + + // result is a Long or Integer + if (wasGatheringWrite) { + result.setResult(Long.valueOf(n)); + } else { + result.setResult(Integer.valueOf(n)); + } + + } catch (Throwable x) { + enableWriting(); + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + result.setFailure(x); + } finally { + // restart poll in case of concurrent read + synchronized (this) { + if (pending != null) + this.pendingWrite = pending; + updateEvents(); + } + end(); + } + if (invokeDirect) { + Invoker.invoke(result.handler(), result); + } else { + Invoker.invokeIndirectly(result.handler(), result); + } + } + + private Runnable writeTimeoutTask = new Runnable() { + public void run() { + PendingFuture<Number,Object> result = grabPendingWrite(); + if (result == null) + return; // already completed + + // kill further writing before releasing waiters + enableWriting(true); + + // set completed and invoke handler + result.setFailure(new InterruptedByTimeoutException()); + Invoker.invokeIndirectly(result.handler(), result); + } + }; + + /** + * Initiates a read or scattering read operation + */ + @Override + @SuppressWarnings("unchecked") + <V extends Number,A> Future<V> writeImpl(ByteBuffer[] srcs, + boolean isGatheringWrite, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<V,? super A> handler) + { + Invoker.GroupAndInvokeCount myGroupAndInvokeCount = + Invoker.getGroupAndInvokeCount(); + boolean invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port); + boolean attemptWrite = (handler == null) || invokeDirect || + !port.isFixedThreadPool(); // okay to attempt read with user thread pool + + AbstractFuture<V,A> result; + try { + begin(); + + int n; + if (attemptWrite) { + if (isGatheringWrite) { + n = (int)IOUtil.write(fd, srcs, nd); + } else { + n = IOUtil.write(fd, srcs[0], -1, nd, null); + } + } else { + n = IOStatus.UNAVAILABLE; + } + + if (n == IOStatus.UNAVAILABLE) { + result = new PendingFuture<V,A>(this, handler, attachment, OpType.WRITE); + + // update evetns so that read will complete asynchronously + synchronized (updateLock) { + this.writeBuffers = srcs; + this.gatheringWrite = isGatheringWrite; + this.pendingWrite = (PendingFuture<Number,Object>)result; + updateEvents(); + } + + // schedule timeout + if (timeout > 0L) { + Future<?> timeoutTask = + port.schedule(writeTimeoutTask, timeout, unit); + ((PendingFuture<V,A>)result).setTimeoutTask(timeoutTask); + } + return result; + } + + // data available + enableWriting(); + if (isGatheringWrite) { + result = (CompletedFuture<V,A>)CompletedFuture + .withResult(this, Long.valueOf(n), attachment); + } else { + result = (CompletedFuture<V,A>)CompletedFuture + .withResult(this, Integer.valueOf(n), attachment); + } + } catch (Throwable x) { + enableWriting(); + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + result = CompletedFuture.withFailure(this, x, attachment); + } finally { + end(); + } + if (invokeDirect) { + Invoker.invokeDirect(myGroupAndInvokeCount, handler, result); + } else { + Invoker.invokeIndirectly(handler, result); + } + return result; + } + + // -- Native methods -- + + private static native void checkConnect(int fdVal) throws IOException; + + static { + Util.load(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java new file mode 100644 index 00000000000..e86ff075c4e --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -0,0 +1,73 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.spi.FileSystemProvider; +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.security.action.GetPropertyAction; + +/** + * Creates this platform's default FileSystemProvider. + */ + +public class DefaultFileSystemProvider { + private DefaultFileSystemProvider() { } + + @SuppressWarnings("unchecked") + private static FileSystemProvider createProvider(final String cn) { + return AccessController + .doPrivileged(new PrivilegedAction<FileSystemProvider>() { + public FileSystemProvider run() { + Class<FileSystemProvider> c; + try { + c = (Class<FileSystemProvider>)Class.forName(cn, true, null); + } catch (ClassNotFoundException x) { + throw new AssertionError(x); + } + try { + return c.newInstance(); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InstantiationException x) { + throw new AssertionError(x); + } + }}); + } + + /** + * Returns the default FileSystemProvider. + */ + public static FileSystemProvider create() { + String osname = AccessController + .doPrivileged(new GetPropertyAction("os.name")); + if (osname.equals("SunOS")) + return createProvider("sun.nio.fs.SolarisFileSystemProvider"); + if (osname.equals("Linux")) + return createProvider("sun.nio.fs.LinuxFileSystemProvider"); + throw new AssertionError("Platform not recognized"); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/DefaultFileTypeDetector.java b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileTypeDetector.java new file mode 100644 index 00000000000..22db3165d01 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileTypeDetector.java @@ -0,0 +1,36 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.spi.FileTypeDetector; + +public class DefaultFileTypeDetector { + private DefaultFileTypeDetector() { } + + public static FileTypeDetector create() { + return new GnomeFileTypeDetector(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java b/jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java new file mode 100644 index 00000000000..bf9e87a8912 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java @@ -0,0 +1,101 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.FileRef; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * File type detector that uses the GNOME I/O library or the deprecated + * GNOME VFS to guess the MIME type of a file. + */ + +public class GnomeFileTypeDetector + extends AbstractFileTypeDetector +{ + private static final String GNOME_VFS_MIME_TYPE_UNKNOWN = + "application/octet-stream"; + + // true if GIO available + private final boolean gioAvailable; + + // true if GNOME VFS available and GIO is not available + private final boolean gnomeVfsAvailable; + + public GnomeFileTypeDetector() { + gioAvailable = initializeGio(); + if (gioAvailable) { + gnomeVfsAvailable = false; + } else { + gnomeVfsAvailable = initializeGnomeVfs(); + } + } + + @Override + public String implProbeContentType(FileRef obj) throws IOException { + if (!gioAvailable && !gnomeVfsAvailable) + return null; + if (!(obj instanceof UnixPath)) + return null; + + UnixPath path = (UnixPath)obj; + NativeBuffer buffer = NativeBuffers.asNativeBuffer(path.getByteArrayForSysCalls()); + try { + if (gioAvailable) { + byte[] type = probeUsingGio(buffer.address()); + return (type == null) ? null : new String(type); + } else { + byte[] type = probeUsingGnomeVfs(buffer.address()); + if (type == null) + return null; + String s = new String(type); + return s.equals(GNOME_VFS_MIME_TYPE_UNKNOWN) ? null : s; + } + + } finally { + buffer.release(); + } + + } + + // GIO + private static native boolean initializeGio(); + private static native byte[] probeUsingGio(long pathAddress); + + // GNOME VFS + private static native boolean initializeGnomeVfs(); + private static native byte[] probeUsingGnomeVfs(long pathAddress); + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java b/jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java new file mode 100644 index 00000000000..85f83e23553 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java @@ -0,0 +1,297 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.io.IOException; +import sun.misc.Unsafe; + +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.UnixConstants.*; + +/** + * Linux implementation of DosFileAttributeView for use on file systems such + * as ext3 that have extended attributes enabled and SAMBA configured to store + * DOS attributes. + */ + +class LinuxDosFileAttributeView + extends UnixFileAttributeViews.Basic implements DosFileAttributeView +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + private static final String READONLY_NAME = "readonly"; + private static final String ARCHIVE_NAME = "archive"; + private static final String SYSTEM_NAME = "system"; + private static final String HIDDEN_NAME = "hidden"; + + private static final String DOS_XATTR_NAME = "user.DOSATTRIB"; + private static final byte[] DOS_XATTR_NAME_AS_BYTES = DOS_XATTR_NAME.getBytes(); + + private static final int DOS_XATTR_READONLY = 0x01; + private static final int DOS_XATTR_HIDDEN = 0x02; + private static final int DOS_XATTR_SYSTEM = 0x04; + private static final int DOS_XATTR_ARCHIVE = 0x20; + + LinuxDosFileAttributeView(UnixPath file, boolean followLinks) { + super(file, followLinks); + } + + @Override + public String name() { + return "dos"; + } + + @Override + public Object getAttribute(String attribute) throws IOException { + if (attribute.equals(READONLY_NAME)) + return readAttributes().isReadOnly(); + if (attribute.equals(ARCHIVE_NAME)) + return readAttributes().isArchive(); + if (attribute.equals(SYSTEM_NAME)) + return readAttributes().isSystem(); + if (attribute.equals(HIDDEN_NAME)) + return readAttributes().isHidden(); + return super.getAttribute(attribute); + } + + @Override + public void setAttribute(String attribute, Object value) + throws IOException + { + if (attribute.equals(READONLY_NAME)) { + setReadOnly((Boolean)value); + return; + } + if (attribute.equals(ARCHIVE_NAME)) { + setArchive((Boolean)value); + return; + } + if (attribute.equals(SYSTEM_NAME)) { + setSystem((Boolean)value); + return; + } + if (attribute.equals(HIDDEN_NAME)) { + setHidden((Boolean)value); + return; + } + super.setAttribute(attribute, value); + } + + @Override + public Map<String,?> readAttributes(String first, String[] rest) + throws IOException + { + AttributesBuilder builder = AttributesBuilder.create(first, rest); + DosFileAttributes attrs = readAttributes(); + addBasicAttributesToBuilder(attrs, builder); + if (builder.match(READONLY_NAME)) + builder.add(READONLY_NAME, attrs.isReadOnly()); + if (builder.match(ARCHIVE_NAME)) + builder.add(ARCHIVE_NAME, attrs.isArchive()); + if (builder.match(SYSTEM_NAME)) + builder.add(SYSTEM_NAME, attrs.isSystem()); + if (builder.match(HIDDEN_NAME)) + builder.add(HIDDEN_NAME, attrs.isHidden()); + return builder.unmodifiableMap(); + } + + @Override + public DosFileAttributes readAttributes() throws IOException { + file.checkRead(); + + int fd = file.openForAttributeAccess(followLinks); + try { + final UnixFileAttributes attrs = UnixFileAttributes.get(fd); + final int dosAttribute = getDosAttribute(fd); + + return new DosFileAttributes() { + @Override + public long lastModifiedTime() { + return attrs.lastModifiedTime(); + } + @Override + public long lastAccessTime() { + return attrs.lastAccessTime(); + } + @Override + public long creationTime() { + return attrs.creationTime(); + } + @Override + public TimeUnit resolution() { + return attrs.resolution(); + } + @Override + public boolean isRegularFile() { + return attrs.isRegularFile(); + } + @Override + public boolean isDirectory() { + return attrs.isDirectory(); + } + @Override + public boolean isSymbolicLink() { + return attrs.isSymbolicLink(); + } + @Override + public boolean isOther() { + return attrs.isOther(); + } + @Override + public long size() { + return attrs.size(); + } + @Override + public int linkCount() { + return attrs.linkCount(); + } + @Override + public Object fileKey() { + return attrs.fileKey(); + } + @Override + public boolean isReadOnly() { + return (dosAttribute & DOS_XATTR_READONLY) != 0; + } + @Override + public boolean isHidden() { + return (dosAttribute & DOS_XATTR_HIDDEN) != 0; + } + @Override + public boolean isArchive() { + return (dosAttribute & DOS_XATTR_ARCHIVE) != 0; + } + @Override + public boolean isSystem() { + return (dosAttribute & DOS_XATTR_SYSTEM) != 0; + } + }; + + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } finally { + close(fd); + } + } + + @Override + public void setReadOnly(boolean value) throws IOException { + updateDosAttribute(DOS_XATTR_READONLY, value); + } + + @Override + public void setHidden(boolean value) throws IOException { + updateDosAttribute(DOS_XATTR_HIDDEN, value); + } + + @Override + public void setArchive(boolean value) throws IOException { + updateDosAttribute(DOS_XATTR_ARCHIVE, value); + } + + @Override + public void setSystem(boolean value) throws IOException { + updateDosAttribute(DOS_XATTR_SYSTEM, value); + } + + /** + * Reads the value of the user.DOSATTRIB extended attribute + */ + private int getDosAttribute(int fd) throws UnixException { + final int size = 24; + + NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); + try { + int len = LinuxNativeDispatcher + .fgetxattr(fd, DOS_XATTR_NAME_AS_BYTES, buffer.address(), size); + + if (len > 0) { + // ignore null terminator + if (unsafe.getByte(buffer.address()+len-1) == 0) + len--; + + // convert to String and parse + byte[] buf = new byte[len]; + unsafe.copyMemory(null, buffer.address(), buf, + Unsafe.ARRAY_BYTE_BASE_OFFSET, len); + String value = new String(buf); // platform encoding + + // should be something like 0x20 + if (value.length() >= 3 && value.startsWith("0x")) { + try { + return Integer.parseInt(value.substring(2), 16); + } catch (NumberFormatException x) { + // ignore + } + } + } + throw new UnixException("Value of " + DOS_XATTR_NAME + " attribute is invalid"); + } catch (UnixException x) { + // default value when attribute does not exist + if (x.errno() == ENODATA) + return 0; + throw x; + } finally { + buffer.release(); + } + } + + /** + * Updates the value of the user.DOSATTRIB extended attribute + */ + private void updateDosAttribute(int flag, boolean enable) throws IOException { + file.checkWrite(); + + int fd = file.openForAttributeAccess(followLinks); + try { + int oldValue = getDosAttribute(fd); + int newValue = oldValue; + if (enable) { + newValue |= flag; + } else { + newValue &= ~flag; + } + if (newValue != oldValue) { + byte[] value = ("0x" + Integer.toHexString(newValue)).getBytes(); + NativeBuffer buffer = NativeBuffers.asNativeBuffer(value); + try { + LinuxNativeDispatcher.fsetxattr(fd, DOS_XATTR_NAME_AS_BYTES, + buffer.address(), value.length+1); + } finally { + buffer.release(); + } + } + } catch (UnixException x) { + x.rethrowAsIOException(file); + } finally { + close(fd); + } + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/LinuxFileStore.java b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileStore.java new file mode 100644 index 00000000000..8c07ce5f66a --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileStore.java @@ -0,0 +1,152 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.util.*; +import java.io.IOException; + +/** + * Linux implementation of FileStore + */ + +class LinuxFileStore + extends UnixFileStore +{ + // used when checking if extended attributes are enabled or not + private volatile boolean xattrChecked; + private volatile boolean xattrEnabled; + + LinuxFileStore(UnixPath file) throws IOException { + super(file); + } + + LinuxFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException { + super(fs, entry); + } + + /** + * Finds, and returns, the mount entry for the file system where the file + * resides. + */ + @Override + UnixMountEntry findMountEntry() throws IOException { + UnixFileSystem fs = file().getFileSystem(); + + // step 1: get realpath + UnixPath path = null; + try { + byte[] rp = UnixNativeDispatcher.realpath(file()); + path = new UnixPath(fs, rp); + } catch (UnixException x) { + x.rethrowAsIOException(file()); + } + + // step 2: find mount point + UnixPath parent = path.getParent(); + while (parent != null) { + UnixFileAttributes attrs = null; + try { + attrs = UnixFileAttributes.get(parent, true); + } catch (UnixException x) { + x.rethrowAsIOException(parent); + } + if (attrs.dev() != dev()) + break; + path = parent; + parent = parent.getParent(); + } + + // step 3: lookup mounted file systems + byte[] dir = path.asByteArray(); + for (UnixMountEntry entry: fs.getMountEntries()) { + if (Arrays.equals(dir, entry.dir())) + return entry; + } + + throw new IOException("Mount point not found in mtab"); + } + + // returns true if extended attributes enabled on file system where given + // file resides, returns false if disabled or unable to determine. + private boolean isExtendedAttributesEnabled(UnixPath path) { + try { + int fd = path.openForAttributeAccess(false); + try { + // fgetxattr returns size if called with size==0 + LinuxNativeDispatcher.fgetxattr(fd, "user.java".getBytes(), 0L, 0); + return true; + } catch (UnixException e) { + // attribute does not exist + if (e.errno() == UnixConstants.ENODATA) + return true; + } finally { + UnixNativeDispatcher.close(fd); + } + } catch (IOException ignore) { + // nothing we can do + } + return false; + } + + @Override + public boolean supportsFileAttributeView(String name) { + // support DosFileAttributeView and NamedAttributeView if extended + // attributes enabled + if (name.equals("dos") || name.equals("xattr")) { + // lookup fstypes.properties + FeatureStatus status = checkIfFeaturePresent("user_xattr"); + if (status == FeatureStatus.PRESENT) + return true; + if (status == FeatureStatus.NOT_PRESENT) + return false; + + // if file system is mounted with user_xattr option then assume + // extended attributes are enabled + if ((entry().hasOption("user_xattr"))) + return true; + + // user_xattr option not present but we special-case ext3/4 as we + // know that extended attributes are not enabled by default. + if (entry().fstype().equals("ext3") || entry().fstype().equals("ext4")) + return false; + + // not ext3/4 so probe mount point + if (!xattrChecked) { + UnixPath dir = new UnixPath(file().getFileSystem(), entry().dir()); + xattrEnabled = isExtendedAttributesEnabled(dir); + xattrChecked = true; + } + return xattrEnabled; + } + + return super.supportsFileAttributeView(name); + } + + @Override + boolean isLoopback() { + return false; + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java new file mode 100644 index 00000000000..d574c9dff09 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java @@ -0,0 +1,175 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; +import static sun.nio.fs.LinuxNativeDispatcher.*; + +/** + * Linux implementation of FileSystem + */ + +class LinuxFileSystem extends UnixFileSystem { + private final boolean hasInotify; + private final boolean hasAtSysCalls; + + LinuxFileSystem(UnixFileSystemProvider provider, String dir) { + super(provider, dir); + + // assume X.Y[-Z] format + String osversion = AccessController + .doPrivileged(new GetPropertyAction("os.version")); + String[] vers = osversion.split("\\.", 0); + assert vers.length >= 2; + + int majorVersion = Integer.parseInt(vers[0]); + int minorVersion = Integer.parseInt(vers[1]); + int microVersion = 0; + if (vers.length > 2) { + String[] microVers = vers[2].split("-", 0); + microVersion = (microVers.length > 0) ? + Integer.parseInt(microVers[0]) : 0; + } + + // inotify available since 2.6.13 + this.hasInotify = ((majorVersion > 2) || + (majorVersion == 2 && minorVersion > 6) || + ((majorVersion == 2) && (minorVersion == 6) && (microVersion >= 13))); + + // openat etc. available since 2.6.16 + this.hasAtSysCalls = ((majorVersion > 2) || + (majorVersion == 2 && minorVersion > 6) || + ((majorVersion == 2) && (minorVersion == 6) && (microVersion >= 16))); + } + + @Override + public WatchService newWatchService() + throws IOException + { + if (hasInotify) { + return new LinuxWatchService(this); + } else { + // use polling implementation on older kernels + return new PollingWatchService(); + } + } + + @Override + @SuppressWarnings("unchecked") + public <V extends FileAttributeView> V newFileAttributeView(Class<V> view, + UnixPath file, + LinkOption... options) + { + if (view == DosFileAttributeView.class) + return (V) new LinuxDosFileAttributeView(file, followLinks(options)); + if (view == UserDefinedFileAttributeView.class) + return (V) new LinuxUserDefinedFileAttributeView(file, followLinks(options)); + return super.newFileAttributeView(view, file, options); + } + + @Override + @SuppressWarnings("unchecked") + public FileAttributeView newFileAttributeView(String name, + UnixPath file, + LinkOption... options) + { + if (name.equals("dos")) + return new LinuxDosFileAttributeView(file, followLinks(options)); + if (name.equals("xattr")) + return new LinuxUserDefinedFileAttributeView(file, followLinks(options)); + return super.newFileAttributeView(name, file, options); + } + + // lazy initialization of the list of supported attribute views + private static class SupportedFileFileAttributeViewsHolder { + static final Set<String> supportedFileAttributeViews = + supportedFileAttributeViews(); + private static Set<String> supportedFileAttributeViews() { + Set<String> result = new HashSet<String>(); + result.addAll(UnixFileSystem.standardFileAttributeViews()); + // additional Linux-specific views + result.add("dos"); + result.add("xattr"); + return Collections.unmodifiableSet(result); + } + } + + @Override + public Set<String> supportedFileAttributeViews() { + return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews; + } + + @Override + void copyNonPosixAttributes(int ofd, int nfd) { + LinuxUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd); + } + + @Override + boolean supportsSecureDirectoryStreams() { + return hasAtSysCalls; + } + + /** + * Returns object to iterate over entries in /etc/mtab + */ + @Override + Iterable<UnixMountEntry> getMountEntries() { + ArrayList<UnixMountEntry> entries = new ArrayList<UnixMountEntry>(); + try { + long fp = setmntent("/etc/mtab".getBytes(), "r".getBytes()); + try { + for (;;) { + UnixMountEntry entry = new UnixMountEntry(); + int res = getextmntent(fp, entry); + if (res < 0) + break; + entries.add(entry); + } + } finally { + endmntent(fp); + } + + } catch (UnixException x) { + // nothing we can do + } + return entries; + } + + @Override + FileStore getFileStore(UnixPath path) throws IOException { + return new LinuxFileStore(path); + } + + @Override + FileStore getFileStore(UnixMountEntry entry) throws IOException { + return new LinuxFileStore(this, entry); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java new file mode 100644 index 00000000000..aa979c4759a --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +/** + * Linux implementation of FileSystemProvider + */ + +public class LinuxFileSystemProvider extends UnixFileSystemProvider { + public LinuxFileSystemProvider() { + super(); + } + + @Override + LinuxFileSystem newFileSystem(String dir) { + return new LinuxFileSystem(this, dir); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java b/jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java new file mode 100644 index 00000000000..65547badccb --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java @@ -0,0 +1,126 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Linux specific system calls. + */ + +class LinuxNativeDispatcher extends UnixNativeDispatcher { + private LinuxNativeDispatcher() { } + + /** + * FILE *setmntent(const char *filename, const char *type); + */ + static long setmntent(byte[] filename, byte[] type) throws UnixException { + NativeBuffer pathBuffer = NativeBuffers.asNativeBuffer(filename); + NativeBuffer typeBuffer = NativeBuffers.asNativeBuffer(type); + try { + return setmntent0(pathBuffer.address(), typeBuffer.address()); + } finally { + typeBuffer.release(); + pathBuffer.release(); + } + } + private static native long setmntent0(long pathAddress, long typeAddress) + throws UnixException; + + /** + * int endmntent(FILE* filep); + */ + static native void endmntent(long stream) throws UnixException; + + /** + * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); + */ + static int fgetxattr(int filedes, byte[] name, long valueAddress, + int valueLen) throws UnixException + { + NativeBuffer buffer = NativeBuffers.asNativeBuffer(name); + try { + return fgetxattr0(filedes, buffer.address(), valueAddress, valueLen); + } finally { + buffer.release(); + } + } + + private static native int fgetxattr0(int filedes, long nameAddress, + long valueAdddress, int valueLen) throws UnixException; + + /** + * fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags); + */ + static void fsetxattr(int filedes, byte[] name, long valueAddress, + int valueLen) throws UnixException + { + NativeBuffer buffer = NativeBuffers.asNativeBuffer(name); + try { + fsetxattr0(filedes, buffer.address(), valueAddress, valueLen); + } finally { + buffer.release(); + } + } + + private static native void fsetxattr0(int filedes, long nameAddress, + long valueAdddress, int valueLen) throws UnixException; + + + /** + * fremovexattr(int filedes, const char *name); + */ + static void fremovexattr(int filedes, byte[] name) throws UnixException { + NativeBuffer buffer = NativeBuffers.asNativeBuffer(name); + try { + fremovexattr0(filedes, buffer.address()); + } finally { + buffer.release(); + } + } + + private static native void fremovexattr0(int filedes, long nameAddress) + throws UnixException; + + /** + * size_t flistxattr(int filedes, const char *list, size_t size) + */ + static native int flistxattr(int filedes, long listAddress, int size) + throws UnixException; + + // initialize + private static native void init(); + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + init(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java b/jdk/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java new file mode 100644 index 00000000000..b51a9e9cb26 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java @@ -0,0 +1,350 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.ByteBuffer; +import java.io.IOException; +import java.util.*; +import sun.misc.Unsafe; + +import static sun.nio.fs.UnixConstants.*; +import static sun.nio.fs.LinuxNativeDispatcher.*; + +/** + * Linux implementation of UserDefinedFileAttributeView using extended attributes. + */ + +class LinuxUserDefinedFileAttributeView + extends AbstractUserDefinedFileAttributeView +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // namespace for extended user attributes + private static final String USER_NAMESPACE = "user."; + + // maximum bytes in extended attribute name (includes namespace) + private static final int XATTR_NAME_MAX = 255; + + private byte[] nameAsBytes(UnixPath file, String name) throws IOException { + if (name == null) + throw new NullPointerException("'name' is null"); + name = USER_NAMESPACE + name; + byte[] bytes = name.getBytes(); + if (bytes.length > XATTR_NAME_MAX) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "'" + name + "' is too big"); + } + return bytes; + } + + // Parses buffer as array of NULL-terminated C strings. + private List<String> asList(long address, int size) { + final List<String> list = new ArrayList<String>(); + int start = 0; + int pos = 0; + while (pos < size) { + if (unsafe.getByte(address + pos) == 0) { + int len = pos - start; + byte[] value = new byte[len]; + unsafe.copyMemory(null, address+start, value, + Unsafe.ARRAY_BYTE_BASE_OFFSET, len); + String s = new String(value); + if (s.startsWith(USER_NAMESPACE)) { + s = s.substring(USER_NAMESPACE.length()); + list.add(s); + } + start = pos + 1; + } + pos++; + } + return list; + } + + private final UnixPath file; + private final boolean followLinks; + + LinuxUserDefinedFileAttributeView(UnixPath file, boolean followLinks) { + this.file = file; + this.followLinks = followLinks; + } + + @Override + public List<String> list() throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + int fd = file.openForAttributeAccess(followLinks); + NativeBuffer buffer = null; + try { + int size = 1024; + buffer = NativeBuffers.getNativeBuffer(size); + for (;;) { + try { + int n = flistxattr(fd, buffer.address(), size); + List<String> list = asList(buffer.address(), n); + return Collections.unmodifiableList(list); + } catch (UnixException x) { + // allocate larger buffer if required + if (x.errno() == ERANGE && size < 32*1024) { + buffer.release(); + size *= 2; + buffer = null; + buffer = NativeBuffers.getNativeBuffer(size); + continue; + } + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Unable to get list of extended attributes: " + + x.getMessage()); + } + } + } finally { + if (buffer != null) + buffer.release(); + close(fd); + } + } + + @Override + public int size(String name) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + int fd = file.openForAttributeAccess(followLinks); + try { + // fgetxattr returns size if called with size==0 + return fgetxattr(fd, nameAsBytes(file,name), 0L, 0); + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Unable to get size of extended attribute '" + name + + "': " + x.getMessage()); + } finally { + close(fd); + } + } + + @Override + public int read(String name, ByteBuffer dst) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + if (dst.isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + int pos = dst.position(); + int lim = dst.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + NativeBuffer nb; + long address; + if (dst instanceof sun.nio.ch.DirectBuffer) { + nb = null; + address = ((sun.nio.ch.DirectBuffer)dst).address() + pos; + } else { + // substitute with native buffer + nb = NativeBuffers.getNativeBuffer(rem); + address = nb.address(); + } + + int fd = file.openForAttributeAccess(followLinks); + try { + try { + int n = fgetxattr(fd, nameAsBytes(file,name), address, rem); + + // if remaining is zero then fgetxattr returns the size + if (rem == 0) { + if (n > 0) + throw new UnixException(ERANGE); + return 0; + } + + // copy from buffer into backing array if necessary + if (nb != null) { + int off = dst.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET; + unsafe.copyMemory(null, address, dst.array(), off, n); + } + dst.position(pos + n); + return n; + } catch (UnixException x) { + String msg = (x.errno() == ERANGE) ? + "Insufficient space in buffer" : x.getMessage(); + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Error reading extended attribute '" + name + "': " + msg); + } finally { + close(fd); + } + } finally { + if (nb != null) + nb.release(); + } + } + + @Override + public int write(String name, ByteBuffer src) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), false, true); + + int pos = src.position(); + int lim = src.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + NativeBuffer nb; + long address; + if (src instanceof sun.nio.ch.DirectBuffer) { + nb = null; + address = ((sun.nio.ch.DirectBuffer)src).address() + pos; + } else { + // substitute with native buffer + nb = NativeBuffers.getNativeBuffer(rem); + address = nb.address(); + + if (src.hasArray()) { + // copy from backing array into buffer + int off = src.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET; + unsafe.copyMemory(src.array(), off, null, address, rem); + } else { + // backing array not accessible so transfer via temporary array + byte[] tmp = new byte[rem]; + src.get(tmp); + src.position(pos); // reset position as write may fail + unsafe.copyMemory(tmp, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, + address, rem); + } + } + + int fd = file.openForAttributeAccess(followLinks); + try { + try { + fsetxattr(fd, nameAsBytes(file,name), address, rem); + src.position(pos + rem); + return rem; + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Error writing extended attribute '" + name + "': " + + x.getMessage()); + } finally { + close(fd); + } + } finally { + if (nb != null) + nb.release(); + } + } + + @Override + public void delete(String name) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), false, true); + + int fd = file.openForAttributeAccess(followLinks); + try { + fremovexattr(fd, nameAsBytes(file,name)); + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Unable to delete extended attribute '" + name + "': " + x.getMessage()); + } finally { + close(fd); + } + } + + /** + * Used by copyTo/moveTo to copy extended attributes from source to target. + * + * @param ofd + * file descriptor for source file + * @param nfd + * file descriptor for target file + */ + static void copyExtendedAttributes(int ofd, int nfd) { + NativeBuffer buffer = null; + try { + + // call flistxattr to get list of extended attributes. + int size = 1024; + buffer = NativeBuffers.getNativeBuffer(size); + for (;;) { + try { + size = flistxattr(ofd, buffer.address(), size); + break; + } catch (UnixException x) { + // allocate larger buffer if required + if (x.errno() == ERANGE && size < 32*1024) { + buffer.release(); + size *= 2; + buffer = null; + buffer = NativeBuffers.getNativeBuffer(size); + continue; + } + + // unable to get list of attributes + return; + } + } + + // parse buffer as array of NULL-terminated C strings. + long address = buffer.address(); + int start = 0; + int pos = 0; + while (pos < size) { + if (unsafe.getByte(address + pos) == 0) { + // extract attribute name and copy attribute to target. + // FIXME: We can avoid needless copying by using address+pos + // as the address of the name. + int len = pos - start; + byte[] name = new byte[len]; + unsafe.copyMemory(null, address+start, name, + Unsafe.ARRAY_BYTE_BASE_OFFSET, len); + try { + copyExtendedAttribute(ofd, name, nfd); + } catch (UnixException ignore) { + // ignore + } + start = pos + 1; + } + pos++; + } + + } finally { + if (buffer != null) + buffer.release(); + } + } + + private static void copyExtendedAttribute(int ofd, byte[] name, int nfd) + throws UnixException + { + int size = fgetxattr(ofd, name, 0L, 0); + NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); + try { + long address = buffer.address(); + size = fgetxattr(ofd, name, address, size); + fsetxattr(nfd, name, address, size); + } finally { + buffer.release(); + } + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/LinuxWatchService.java b/jdk/src/solaris/classes/sun/nio/fs/LinuxWatchService.java new file mode 100644 index 00000000000..0d4a2ffddff --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxWatchService.java @@ -0,0 +1,466 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.*; +import java.io.IOException; +import sun.misc.Unsafe; + +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.UnixConstants.*; + +/** + * Linux implementation of WatchService based on inotify. + * + * In summary a background thread polls inotify plus a socket used for the wakeup + * mechanism. Requests to add or remove a watch, or close the watch service, + * cause the thread to wakeup and process the request. Events are processed + * by the thread which causes it to signal/queue the corresponding watch keys. + */ + +class LinuxWatchService + extends AbstractWatchService +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // background thread to read change events + private final Poller poller; + + LinuxWatchService(UnixFileSystem fs) throws IOException { + // initialize inotify + int ifd = - 1; + try { + ifd = inotifyInit(); + } catch (UnixException x) { + throw new IOException(x.errorString()); + } + + // configure inotify to be non-blocking + // create socketpair used in the close mechanism + int sp[] = new int[2]; + try { + configureBlocking(ifd, false); + socketpair(sp); + configureBlocking(sp[0], false); + } catch (UnixException x) { + UnixNativeDispatcher.close(ifd); + throw new IOException(x.errorString()); + } + + this.poller = new Poller(fs, this, ifd, sp); + this.poller.start(); + } + + @Override + WatchKey register(Path dir, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) + throws IOException + { + // delegate to poller + return poller.register(dir, events, modifiers); + } + + @Override + void implClose() throws IOException { + // delegate to poller + poller.close(); + } + + /** + * WatchKey implementation + */ + private static class LinuxWatchKey extends AbstractWatchKey { + // inotify descriptor + private final int ifd; + // watch descriptor + private volatile int wd; + + LinuxWatchKey(LinuxWatchService watcher, int ifd, int wd) { + super(watcher); + this.ifd = ifd; + this.wd = wd; + } + + int descriptor() { + return wd; + } + + void invalidate(boolean remove) { + if (remove) { + try { + inotifyRmWatch(ifd, wd); + } catch (UnixException x) { + // ignore + } + } + wd = -1; + } + + @Override + public boolean isValid() { + return (wd != -1); + } + + @Override + public void cancel() { + if (isValid()) { + // delegate to poller + ((LinuxWatchService)watcher()).poller.cancel(this); + } + } + } + + /** + * Background thread to read from inotify + */ + private static class Poller extends AbstractPoller { + /** + * struct inotify_event { + * int wd; + * uint32_t mask; + * uint32_t len; + * char name __flexarr; // present if len > 0 + * } act_t; + */ + private static final int SIZEOF_INOTIFY_EVENT = eventSize(); + private static final int[] offsets = eventOffsets(); + private static final int OFFSETOF_WD = offsets[0]; + private static final int OFFSETOF_MASK = offsets[1]; + private static final int OFFSETOF_LEN = offsets[3]; + private static final int OFFSETOF_NAME = offsets[4]; + + private static final int IN_MODIFY = 0x00000002; + private static final int IN_ATTRIB = 0x00000004; + private static final int IN_MOVED_FROM = 0x00000040; + private static final int IN_MOVED_TO = 0x00000080; + private static final int IN_CREATE = 0x00000100; + private static final int IN_DELETE = 0x00000200; + + private static final int IN_UNMOUNT = 0x00002000; + private static final int IN_Q_OVERFLOW = 0x00004000; + private static final int IN_IGNORED = 0x00008000; + + // sizeof buffer for when polling inotify + private static final int BUFFER_SIZE = 8192; + + private final UnixFileSystem fs; + private final LinuxWatchService watcher; + + // inotify file descriptor + private final int ifd; + // socketpair used to shutdown polling thread + private final int socketpair[]; + // maps watch descriptor to Key + private final Map<Integer,LinuxWatchKey> wdToKey; + // address of read buffer + private final long address; + + Poller(UnixFileSystem fs, LinuxWatchService watcher, int ifd, int[] sp) { + this.fs = fs; + this.watcher = watcher; + this.ifd = ifd; + this.socketpair = sp; + this.wdToKey = new HashMap<Integer,LinuxWatchKey>(); + this.address = unsafe.allocateMemory(BUFFER_SIZE); + } + + @Override + void wakeup() throws IOException { + // write to socketpair to wakeup polling thread + try { + write(socketpair[1], address, 1); + } catch (UnixException x) { + throw new IOException(x.errorString()); + } + } + + @Override + Object implRegister(Path obj, + Set<? extends WatchEvent.Kind<?>> events, + WatchEvent.Modifier... modifiers) + { + UnixPath dir = (UnixPath)obj; + + int mask = 0; + for (WatchEvent.Kind<?> event: events) { + if (event == StandardWatchEventKind.ENTRY_CREATE) { + mask |= IN_CREATE | IN_MOVED_TO; + continue; + } + if (event == StandardWatchEventKind.ENTRY_DELETE) { + mask |= IN_DELETE | IN_MOVED_FROM; + continue; + } + if (event == StandardWatchEventKind.ENTRY_MODIFY) { + mask |= IN_MODIFY | IN_ATTRIB; + continue; + } + } + + // no modifiers supported at this time + if (modifiers.length > 0) { + for (WatchEvent.Modifier modifier: modifiers) { + if (modifier == null) + return new NullPointerException(); + if (modifier instanceof com.sun.nio.file.SensitivityWatchEventModifier) + continue; // ignore + return new UnsupportedOperationException("Modifier not supported"); + } + } + + // check file is directory + UnixFileAttributes attrs = null; + try { + attrs = UnixFileAttributes.get(dir, true); + } catch (UnixException x) { + return x.asIOException(dir); + } + if (!attrs.isDirectory()) { + return new NotDirectoryException(dir.getPathForExecptionMessage()); + } + + // register with inotify (replaces existing mask if already registered) + int wd = -1; + try { + NativeBuffer buffer = + NativeBuffers.asNativeBuffer(dir.getByteArrayForSysCalls()); + try { + wd = inotifyAddWatch(ifd, buffer.address(), mask); + } finally { + buffer.release(); + } + } catch (UnixException x) { + if (x.errno() == ENOSPC) { + return new IOException("User limit of inotify watches reached"); + } + return x.asIOException(dir); + } + + // ensure watch descriptor is in map + LinuxWatchKey key = wdToKey.get(wd); + if (key == null) { + key = new LinuxWatchKey(watcher, ifd, wd); + wdToKey.put(wd, key); + } + return key; + } + + // cancel single key + @Override + void implCancelKey(WatchKey obj) { + LinuxWatchKey key = (LinuxWatchKey)obj; + if (key.isValid()) { + wdToKey.remove(key.descriptor()); + key.invalidate(true); + } + } + + // close watch service + @Override + void implCloseAll() { + // invalidate all keys + for (Map.Entry<Integer,LinuxWatchKey> entry: wdToKey.entrySet()) { + entry.getValue().invalidate(true); + } + wdToKey.clear(); + + // free resources + unsafe.freeMemory(address); + UnixNativeDispatcher.close(socketpair[0]); + UnixNativeDispatcher.close(socketpair[1]); + UnixNativeDispatcher.close(ifd); + } + + /** + * Poller main loop + */ + @Override + public void run() { + try { + for (;;) { + int nReady, bytesRead; + + // wait for close or inotify event + nReady = poll(ifd, socketpair[0]); + + // read from inotify + try { + bytesRead = read(ifd, address, BUFFER_SIZE); + } catch (UnixException x) { + if (x.errno() != EAGAIN) + throw x; + bytesRead = 0; + } + + // process any pending requests + if ((nReady > 1) || (nReady == 1 && bytesRead == 0)) { + try { + read(socketpair[0], address, BUFFER_SIZE); + boolean shutdown = processRequests(); + if (shutdown) + break; + } catch (UnixException x) { + if (x.errno() != UnixConstants.EAGAIN) + throw x; + } + } + + // iterate over buffer to decode events + int offset = 0; + while (offset < bytesRead) { + long event = address + offset; + int wd = unsafe.getInt(event + OFFSETOF_WD); + int mask = unsafe.getInt(event + OFFSETOF_MASK); + int len = unsafe.getInt(event + OFFSETOF_LEN); + + // file name + UnixPath name = null; + if (len > 0) { + int actual = len; + + // null-terminated and maybe additional null bytes to + // align the next event + while (actual > 0) { + long last = event + OFFSETOF_NAME + actual - 1; + if (unsafe.getByte(last) != 0) + break; + actual--; + } + if (actual > 0) { + byte[] buf = new byte[actual]; + unsafe.copyMemory(null, event + OFFSETOF_NAME, + buf, Unsafe.ARRAY_BYTE_BASE_OFFSET, actual); + name = new UnixPath(fs, buf); + } + } + + // process event + processEvent(wd, mask, name); + + offset += (SIZEOF_INOTIFY_EVENT + len); + } + } + } catch (UnixException x) { + x.printStackTrace(); + } + } + + + /** + * map inotify event to WatchEvent.Kind + */ + private WatchEvent.Kind<?> maskToEventKind(int mask) { + if ((mask & IN_MODIFY) > 0) + return StandardWatchEventKind.ENTRY_MODIFY; + if ((mask & IN_ATTRIB) > 0) + return StandardWatchEventKind.ENTRY_MODIFY; + if ((mask & IN_CREATE) > 0) + return StandardWatchEventKind.ENTRY_CREATE; + if ((mask & IN_MOVED_TO) > 0) + return StandardWatchEventKind.ENTRY_CREATE; + if ((mask & IN_DELETE) > 0) + return StandardWatchEventKind.ENTRY_DELETE; + if ((mask & IN_MOVED_FROM) > 0) + return StandardWatchEventKind.ENTRY_DELETE; + return null; + } + + /** + * Process event from inotify + */ + private void processEvent(int wd, int mask, final UnixPath name) { + // overflow - signal all keys + if ((mask & IN_Q_OVERFLOW) > 0) { + for (Map.Entry<Integer,LinuxWatchKey> entry: wdToKey.entrySet()) { + entry.getValue() + .signalEvent(StandardWatchEventKind.OVERFLOW, null); + } + return; + } + + // lookup wd to get key + LinuxWatchKey key = wdToKey.get(wd); + if (key == null) + return; // should not happen + + // file deleted + if ((mask & IN_IGNORED) > 0) { + wdToKey.remove(wd); + key.invalidate(false); + key.signal(); + return; + } + + // event for directory itself + if (name == null) + return; + + // map to event and queue to key + WatchEvent.Kind<?> kind = maskToEventKind(mask); + if (kind != null) { + key.signalEvent(kind, name); + } + } + } + + // -- native methods -- + + private static native void init(); + + // sizeof inotify_event + private static native int eventSize(); + + // offsets of inotify_event + private static native int[] eventOffsets(); + + private static native int inotifyInit() throws UnixException; + + private static native int inotifyAddWatch(int fd, long pathAddress, int mask) + throws UnixException; + + private static native void inotifyRmWatch(int fd, int wd) + throws UnixException; + + private static native void configureBlocking(int fd, boolean blocking) + throws UnixException; + + private static native void socketpair(int[] sv) throws UnixException; + + private static native int poll(int fd1, int fd2) throws UnixException; + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + init(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java b/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java new file mode 100644 index 00000000000..e96361e20ba --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java @@ -0,0 +1,408 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.util.*; +import java.io.IOException; +import sun.misc.Unsafe; + +import static sun.nio.fs.UnixConstants.*; +import static sun.nio.fs.SolarisConstants.*; +import static sun.nio.fs.SolarisNativeDispatcher.*; + + +/** + * Solaris implementation of AclFileAttributeView with native support for + * NFSv4 ACLs on ZFS. + */ + +class SolarisAclFileAttributeView + extends AbstractAclFileAttributeView +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // Maximum number of entries allowed in an ACL + private static final int MAX_ACL_ENTRIES = 1024; + + /** + * typedef struct ace { + * uid_t a_who; + * uitn32_t a_access_mark; + * uint16_t a_flags; + * uint16_t a_type; + * } act_t; + */ + private static final short SIZEOF_ACE_T = 12; + private static final short OFFSETOF_UID = 0; + private static final short OFFSETOF_MASK = 4; + private static final short OFFSETOF_FLAGS = 8; + private static final short OFFSETOF_TYPE = 10; + + private final UnixPath file; + private final boolean followLinks; + + SolarisAclFileAttributeView(UnixPath file, boolean followLinks) { + this.file = file; + this.followLinks = followLinks; + } + + /** + * Permission checks to access file + */ + private void checkAccess(UnixPath file, + boolean checkRead, + boolean checkWrite) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (checkRead) + file.checkRead(); + if (checkWrite) + file.checkWrite(); + sm.checkPermission(new RuntimePermission("accessUserInformation")); + } + } + + /** + * Encode the ACL to the given buffer + */ + private static void encode(List<AclEntry> acl, long address) { + long offset = address; + for (AclEntry ace: acl) { + int flags = 0; + + // map UserPrincipal to uid and flags + UserPrincipal who = ace.principal(); + if (!(who instanceof UnixUserPrincipals)) + throw new ProviderMismatchException(); + UnixUserPrincipals.User user = (UnixUserPrincipals.User)who; + int uid; + if (user.isSpecial()) { + uid = -1; + if (who.getName().equals(UnixUserPrincipals.SPECIAL_OWNER.getName())) + flags |= ACE_OWNER; + else if (who.getName().equals(UnixUserPrincipals.SPECIAL_GROUP.getName())) + flags |= ACE_GROUP; + else if (who.getName().equals(UnixUserPrincipals.SPECIAL_EVERYONE.getName())) + flags |= ACE_EVERYONE; + else + throw new AssertionError("Unable to map special identifier"); + } else { + if (user instanceof UnixUserPrincipals.Group) { + uid = user.gid(); + flags |= ACE_IDENTIFIER_GROUP; + } else { + uid = user.uid(); + } + } + + // map ACE type + int type; + switch (ace.type()) { + case ALLOW: + type = ACE_ACCESS_ALLOWED_ACE_TYPE; + break; + case DENY: + type = ACE_ACCESS_DENIED_ACE_TYPE; + break; + case AUDIT: + type = ACE_SYSTEM_AUDIT_ACE_TYPE; + break; + case ALARM: + type = ACE_SYSTEM_ALARM_ACE_TYPE; + break; + default: + throw new AssertionError("Unable to map ACE type"); + } + + // map permissions + Set<AclEntryPermission> aceMask = ace.permissions(); + int mask = 0; + if (aceMask.contains(AclEntryPermission.READ_DATA)) + mask |= ACE_READ_DATA; + if (aceMask.contains(AclEntryPermission.WRITE_DATA)) + mask |= ACE_WRITE_DATA; + if (aceMask.contains(AclEntryPermission.APPEND_DATA)) + mask |= ACE_APPEND_DATA; + if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS)) + mask |= ACE_READ_NAMED_ATTRS; + if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS)) + mask |= ACE_WRITE_NAMED_ATTRS; + if (aceMask.contains(AclEntryPermission.EXECUTE)) + mask |= ACE_EXECUTE; + if (aceMask.contains(AclEntryPermission.DELETE_CHILD)) + mask |= ACE_DELETE_CHILD; + if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES)) + mask |= ACE_READ_ATTRIBUTES; + if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES)) + mask |= ACE_WRITE_ATTRIBUTES; + if (aceMask.contains(AclEntryPermission.DELETE)) + mask |= ACE_DELETE; + if (aceMask.contains(AclEntryPermission.READ_ACL)) + mask |= ACE_READ_ACL; + if (aceMask.contains(AclEntryPermission.WRITE_ACL)) + mask |= ACE_WRITE_ACL; + if (aceMask.contains(AclEntryPermission.WRITE_OWNER)) + mask |= ACE_WRITE_OWNER; + if (aceMask.contains(AclEntryPermission.SYNCHRONIZE)) + mask |= ACE_SYNCHRONIZE; + + // FIXME - it would be desirable to know here if the file is a + // directory or not. Solaris returns EINVAL if an ACE has a directory + // -only flag and the file is not a directory. + Set<AclEntryFlag> aceFlags = ace.flags(); + if (aceFlags.contains(AclEntryFlag.FILE_INHERIT)) + flags |= ACE_FILE_INHERIT_ACE; + if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT)) + flags |= ACE_DIRECTORY_INHERIT_ACE; + if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT)) + flags |= ACE_NO_PROPAGATE_INHERIT_ACE; + if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY)) + flags |= ACE_INHERIT_ONLY_ACE; + + unsafe.putInt(offset + OFFSETOF_UID, uid); + unsafe.putInt(offset + OFFSETOF_MASK, mask); + unsafe.putShort(offset + OFFSETOF_FLAGS, (short)flags); + unsafe.putShort(offset + OFFSETOF_TYPE, (short)type); + + offset += SIZEOF_ACE_T; + } + } + + /** + * Decode the buffer, returning an ACL + */ + private static List<AclEntry> decode(long address, int n) { + ArrayList<AclEntry> acl = new ArrayList<AclEntry>(n); + for (int i=0; i<n; i++) { + long offset = address + i*SIZEOF_ACE_T; + + int uid = unsafe.getInt(offset + OFFSETOF_UID); + int mask = unsafe.getInt(offset + OFFSETOF_MASK); + int flags = (int)unsafe.getShort(offset + OFFSETOF_FLAGS); + int type = (int)unsafe.getShort(offset + OFFSETOF_TYPE); + + // map uid and flags to UserPrincipal + UnixUserPrincipals.User who = null; + if (uid == -1) { + if ((flags & ACE_OWNER) > 0) + who = UnixUserPrincipals.SPECIAL_OWNER; + if ((flags & ACE_GROUP) > 0) + who = UnixUserPrincipals.SPECIAL_GROUP; + if ((flags & ACE_EVERYONE) > 0) + who = UnixUserPrincipals.SPECIAL_EVERYONE; + if (who == null) + throw new AssertionError("ACE who not handled"); + } else { + // can be gid + if ((flags & ACE_IDENTIFIER_GROUP) > 0) + who = UnixUserPrincipals.fromGid(uid); + else + who = UnixUserPrincipals.fromUid(uid); + } + + AclEntryType aceType = null; + switch (type) { + case ACE_ACCESS_ALLOWED_ACE_TYPE: + aceType = AclEntryType.ALLOW; + break; + case ACE_ACCESS_DENIED_ACE_TYPE: + aceType = AclEntryType.DENY; + break; + case ACE_SYSTEM_AUDIT_ACE_TYPE: + aceType = AclEntryType.AUDIT; + break; + case ACE_SYSTEM_ALARM_ACE_TYPE: + aceType = AclEntryType.ALARM; + break; + default: + assert false; + } + + HashSet<AclEntryPermission> aceMask = new HashSet<AclEntryPermission>(); + if ((mask & ACE_READ_DATA) > 0) + aceMask.add(AclEntryPermission.READ_DATA); + if ((mask & ACE_WRITE_DATA) > 0) + aceMask.add(AclEntryPermission.WRITE_DATA); + if ((mask & ACE_APPEND_DATA ) > 0) + aceMask.add(AclEntryPermission.APPEND_DATA); + if ((mask & ACE_READ_NAMED_ATTRS) > 0) + aceMask.add(AclEntryPermission.READ_NAMED_ATTRS); + if ((mask & ACE_WRITE_NAMED_ATTRS) > 0) + aceMask.add(AclEntryPermission.WRITE_NAMED_ATTRS); + if ((mask & ACE_EXECUTE) > 0) + aceMask.add(AclEntryPermission.EXECUTE); + if ((mask & ACE_DELETE_CHILD ) > 0) + aceMask.add(AclEntryPermission.DELETE_CHILD); + if ((mask & ACE_READ_ATTRIBUTES) > 0) + aceMask.add(AclEntryPermission.READ_ATTRIBUTES); + if ((mask & ACE_WRITE_ATTRIBUTES) > 0) + aceMask.add(AclEntryPermission.WRITE_ATTRIBUTES); + if ((mask & ACE_DELETE) > 0) + aceMask.add(AclEntryPermission.DELETE); + if ((mask & ACE_READ_ACL) > 0) + aceMask.add(AclEntryPermission.READ_ACL); + if ((mask & ACE_WRITE_ACL) > 0) + aceMask.add(AclEntryPermission.WRITE_ACL); + if ((mask & ACE_WRITE_OWNER) > 0) + aceMask.add(AclEntryPermission.WRITE_OWNER); + if ((mask & ACE_SYNCHRONIZE) > 0) + aceMask.add(AclEntryPermission.SYNCHRONIZE); + + HashSet<AclEntryFlag> aceFlags = new HashSet<AclEntryFlag>(); + if ((flags & ACE_FILE_INHERIT_ACE) > 0) + aceFlags.add(AclEntryFlag.FILE_INHERIT); + if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0) + aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT); + if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0) + aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT); + if ((flags & ACE_INHERIT_ONLY_ACE ) > 0) + aceFlags.add(AclEntryFlag.INHERIT_ONLY); + + // build the ACL entry and add it to the list + AclEntry ace = AclEntry.newBuilder() + .setType(aceType) + .setPrincipal(who) + .setPermissions(aceMask).setFlags(aceFlags).build(); + acl.add(ace); + } + + return acl; + } + + // Retrns true if NFSv4 ACLs not enabled on file system + private static boolean isAclsEnabled(int fd) { + try { + long enabled = fpathconf(fd, _PC_ACL_ENABLED); + if (enabled == _ACL_ACE_ENABLED) + return true; + } catch (UnixException x) { + } + return false; + } + + @Override + public List<AclEntry> getAcl() + throws IOException + { + // permission check + checkAccess(file, true, false); + + // open file (will fail if file is a link and not following links) + int fd = file.openForAttributeAccess(followLinks); + try { + long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES); + try { + // read ACL and decode it + int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address); + assert n >= 0; + return decode(address, n); + } catch (UnixException x) { + if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, x.getMessage() + " (file system does not support NFSv4 ACLs)"); + } + x.rethrowAsIOException(file); + return null; // keep compiler happy + } finally { + unsafe.freeMemory(address); + } + } finally { + close(fd); + } + } + + @Override + public void setAcl(List<AclEntry> acl) throws IOException { + // permission check + checkAccess(file, false, true); + + // open file (will fail if file is a link and not following links) + int fd = file.openForAttributeAccess(followLinks); + try { + // SECURITY: need to copy list as can change during processing + acl = new ArrayList<AclEntry>(acl); + int n = acl.size(); + + long address = unsafe.allocateMemory(SIZEOF_ACE_T * n); + try { + encode(acl, address); + facl(fd, ACE_SETACL, n, address); + } catch (UnixException x) { + if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, x.getMessage() + " (file system does not support NFSv4 ACLs)"); + } + if (x.errno() == EINVAL && (n < 3)) + throw new IOException("ACL must contain at least 3 entries"); + x.rethrowAsIOException(file); + } finally { + unsafe.freeMemory(address); + } + } finally { + close(fd); + } + } + + @Override + public UserPrincipal getOwner() + throws IOException + { + checkAccess(file, true, false); + + try { + UnixFileAttributes attrs = + UnixFileAttributes.get(file, followLinks); + return UnixUserPrincipals.fromUid(attrs.uid()); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compile happy + } + } + + @Override + public void setOwner(UserPrincipal owner) throws IOException { + checkAccess(file, true, false); + + if (!(owner instanceof UnixUserPrincipals.User)) + throw new ProviderMismatchException(); + if (owner instanceof UnixUserPrincipals.Group) + throw new IOException("'owner' parameter is a group"); + int uid = ((UnixUserPrincipals.User)owner).uid(); + + try { + if (followLinks) { + lchown(file, uid, -1); + } else { + chown(file, uid, -1); + } + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/SolarisFileStore.java b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileStore.java new file mode 100644 index 00000000000..bdf71a5593c --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileStore.java @@ -0,0 +1,103 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.io.IOException; + +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.SolarisConstants.*; + +/** + * Solaris implementation of FileStore + */ + +class SolarisFileStore + extends UnixFileStore +{ + private final boolean xattrEnabled; + + SolarisFileStore(UnixPath file) throws IOException { + super(file); + this.xattrEnabled = xattrEnabled(); + } + + SolarisFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException { + super(fs, entry); + this.xattrEnabled = xattrEnabled(); + } + + // returns true if extended attributes enabled + private boolean xattrEnabled() { + long res = 0L; + try { + res = pathconf(file(), _PC_XATTR_ENABLED); + } catch (UnixException x) { + // ignore + } + return (res != 0L); + } + + @Override + UnixMountEntry findMountEntry() throws IOException { + // On Solaris iterate over the entries in the mount table to find device + for (UnixMountEntry entry: file().getFileSystem().getMountEntries()) { + if (entry.dev() == dev()) { + return entry; + } + } + throw new IOException("Device not found in mnttab"); + } + + @Override + public boolean supportsFileAttributeView(String name) { + if (name.equals("acl")) { + // lookup fstypes.properties + FeatureStatus status = checkIfFeaturePresent("nfsv4acl"); + if (status == FeatureStatus.PRESENT) + return true; + if (status == FeatureStatus.NOT_PRESENT) + return false; + // AclFileAttributeView available on ZFS + return (type().equals("zfs")); + } + if (name.equals("xattr")) { + // lookup fstypes.properties + FeatureStatus status = checkIfFeaturePresent("xattr"); + if (status == FeatureStatus.PRESENT) + return true; + if (status == FeatureStatus.NOT_PRESENT) + return false; + return xattrEnabled; + } + + return super.supportsFileAttributeView(name); + } + + @Override + boolean isLoopback() { + return type().equals("lofs"); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java new file mode 100644 index 00000000000..fa7f34f53b0 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java @@ -0,0 +1,164 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; +import static sun.nio.fs.UnixNativeDispatcher.*; + +/** + * Solaris implementation of FileSystem + */ + +class SolarisFileSystem extends UnixFileSystem { + private final boolean hasSolaris11Features; + + SolarisFileSystem(UnixFileSystemProvider provider, String dir) { + super(provider, dir); + + // check os.version + String osversion = AccessController + .doPrivileged(new GetPropertyAction("os.version")); + String[] vers = osversion.split("\\.", 0); + assert vers.length >= 2; + int majorVersion = Integer.parseInt(vers[0]); + int minorVersion = Integer.parseInt(vers[1]); + this.hasSolaris11Features = + (majorVersion > 5 || (majorVersion == 5 && minorVersion >= 11)); + } + + @Override + boolean isSolaris() { + return true; + } + + @Override + public WatchService newWatchService() + throws IOException + { + // FEN available since Solaris 11 + if (hasSolaris11Features) { + return new SolarisWatchService(this); + } else { + return new PollingWatchService(); + } + } + + @Override + @SuppressWarnings("unchecked") + public <V extends FileAttributeView> V newFileAttributeView(Class<V> view, + UnixPath file, LinkOption... options) + { + if (view == AclFileAttributeView.class) + return (V) new SolarisAclFileAttributeView(file, followLinks(options)); + if (view == UserDefinedFileAttributeView.class) { + return(V) new SolarisUserDefinedFileAttributeView(file, followLinks(options)); + } + return super.newFileAttributeView(view, file, options); + } + + @Override + protected FileAttributeView newFileAttributeView(String name, + UnixPath file, + LinkOption... options) + { + if (name.equals("acl")) + return new SolarisAclFileAttributeView(file, followLinks(options)); + if (name.equals("xattr")) + return new SolarisUserDefinedFileAttributeView(file, followLinks(options)); + return super.newFileAttributeView(name, file, options); + } + + // lazy initialization of the list of supported attribute views + private static class SupportedFileFileAttributeViewsHolder { + static final Set<String> supportedFileAttributeViews = + supportedFileAttributeViews(); + private static Set<String> supportedFileAttributeViews() { + Set<String> result = new HashSet<String>(); + result.addAll(UnixFileSystem.standardFileAttributeViews()); + // additional Solaris-specific views + result.add("acl"); + result.add("xattr"); + return Collections.unmodifiableSet(result); + } + } + + @Override + public Set<String> supportedFileAttributeViews() { + return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews; + } + + @Override + void copyNonPosixAttributes(int ofd, int nfd) { + SolarisUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd); + // TDB: copy ACL from source to target + } + + @Override + boolean supportsSecureDirectoryStreams() { + return true; + } + + /** + * Returns object to iterate over entries in /etc/mnttab + */ + @Override + Iterable<UnixMountEntry> getMountEntries() { + ArrayList<UnixMountEntry> entries = new ArrayList<UnixMountEntry>(); + try { + UnixPath mnttab = new UnixPath(this, "/etc/mnttab"); + long fp = fopen(mnttab, "r"); + try { + for (;;) { + UnixMountEntry entry = new UnixMountEntry(); + int res = getextmntent(fp, entry); + if (res < 0) + break; + entries.add(entry); + } + } finally { + fclose(fp); + } + } catch (UnixException x) { + // nothing we can do + } + return entries; + } + + @Override + FileStore getFileStore(UnixPath path) throws IOException { + return new SolarisFileStore(path); + } + + @Override + FileStore getFileStore(UnixMountEntry entry) throws IOException { + return new SolarisFileStore(this, entry); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java new file mode 100644 index 00000000000..9d3c0845773 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +/** + * Solaris implementation of FileSystemProvider + */ + +public class SolarisFileSystemProvider extends UnixFileSystemProvider { + public SolarisFileSystemProvider() { + super(); + } + + @Override + SolarisFileSystem newFileSystem(String dir) { + return new SolarisFileSystem(this, dir); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java b/jdk/src/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java new file mode 100644 index 00000000000..36f2326ce76 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java @@ -0,0 +1,56 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Solaris specific system calls. + */ + +class SolarisNativeDispatcher extends UnixNativeDispatcher { + private SolarisNativeDispatcher() { } + + /** + * int facl(int filedes, int cmd, int nentries, void aclbufp) + */ + static native int facl(int fd, int cmd, int nentries, long aclbufp) + throws UnixException; + + + // initialize + private static native void init(); + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + init(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java b/jdk/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java new file mode 100644 index 00000000000..040628f6093 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java @@ -0,0 +1,293 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.io.IOException; +import java.util.*; + +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.UnixConstants.*; +import static sun.nio.fs.SolarisConstants.*; + +/** + * Solaris emulation of NamedAttributeView using extended attributes. + */ + +class SolarisUserDefinedFileAttributeView + extends AbstractUserDefinedFileAttributeView +{ + private byte[] nameAsBytes(UnixPath file, String name) throws IOException { + byte[] bytes = name.getBytes(); + // "", "." and ".." not allowed + if (bytes.length == 0 || bytes[0] == '.') { + if (bytes.length <= 1 || + (bytes.length == 2 && bytes[1] == '.')) + { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "'" + name + "' is not a valid name"); + } + } + return bytes; + } + + private final UnixPath file; + private final boolean followLinks; + + SolarisUserDefinedFileAttributeView(UnixPath file, boolean followLinks) { + this.file = file; + this.followLinks = followLinks; + } + + @Override + public List<String> list() throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + int fd = file.openForAttributeAccess(followLinks); + try { + try { + // open extended attribute directory + int dfd = openat(fd, ".".getBytes(), (O_RDONLY|O_XATTR), 0); + long dp; + try { + dp = fdopendir(dfd); + } catch (UnixException x) { + close(dfd); + throw x; + } + + // read list of extended attributes + final List<String> list = new ArrayList<String>(); + try { + byte[] name; + while ((name = readdir(dp)) != null) { + String s = new String(name); + if (!s.equals(".") && !s.equals("..")) + list.add(s); + } + } finally { + closedir(dp); + } + return Collections.unmodifiableList(list); + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Unable to get list of extended attributes: " + + x.getMessage()); + } + } finally { + close(fd); + } + } + + @Override + public int size(String name) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + int fd = file.openForAttributeAccess(followLinks); + try { + try { + // open attribute file + int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0); + try { + // read attribute's attributes + UnixFileAttributes attrs = UnixFileAttributes.get(afd); + long size = attrs.size(); + if (size > Integer.MAX_VALUE) + throw new ArithmeticException("Extended attribute value too large"); + return (int)size; + } finally { + close(afd); + } + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Unable to get size of extended attribute '" + name + + "': " + x.getMessage()); + } + } finally { + close(fd); + } + } + + @Override + public int read(String name, ByteBuffer dst) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + int fd = file.openForAttributeAccess(followLinks); + try { + try { + // open attribute file + int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0); + + // wrap with channel + FileChannel fc = UnixChannelFactory.newFileChannel(afd, true, false); + + // read to EOF (nothing we can do if I/O error occurs) + try { + if (fc.size() > dst.remaining()) + throw new IOException("Extended attribute file too large"); + int total = 0; + while (dst.hasRemaining()) { + int n = fc.read(dst); + if (n < 0) + break; + total += n; + } + return total; + } finally { + fc.close(); + } + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Unable to read extended attribute '" + name + + "': " + x.getMessage()); + } + } finally { + close(fd); + } + } + + @Override + public int write(String name, ByteBuffer src) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), false, true); + + int fd = file.openForAttributeAccess(followLinks); + try { + try { + // open/create attribute file + int afd = openat(fd, nameAsBytes(file,name), + (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR), + UnixFileModeAttribute.ALL_PERMISSIONS); + + // wrap with channel + FileChannel fc = UnixChannelFactory.newFileChannel(afd, false, true); + + // write value (nothing we can do if I/O error occurs) + try { + int rem = src.remaining(); + while (src.hasRemaining()) { + fc.write(src); + } + return rem; + } finally { + fc.close(); + } + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Unable to write extended attribute '" + name + + "': " + x.getMessage()); + } + } finally { + close(fd); + } + } + + @Override + public void delete(String name) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), false, true); + + int fd = file.openForAttributeAccess(followLinks); + try { + int dfd = openat(fd, ".".getBytes(), (O_RDONLY|O_XATTR), 0); + try { + unlinkat(dfd, nameAsBytes(file,name), 0); + } finally { + close(dfd); + } + } catch (UnixException x) { + throw new FileSystemException(file.getPathForExecptionMessage(), + null, "Unable to delete extended attribute '" + name + + "': " + x.getMessage()); + } finally { + close(fd); + } + } + + /** + * Used by copyTo/moveTo to copy extended attributes from source to target. + * + * @param ofd + * file descriptor for source file + * @param nfd + * file descriptor for target file + */ + static void copyExtendedAttributes(int ofd, int nfd) { + try { + // open extended attribute directory + int dfd = openat(ofd, ".".getBytes(), (O_RDONLY|O_XATTR), 0); + long dp = 0L; + try { + dp = fdopendir(dfd); + } catch (UnixException x) { + close(dfd); + throw x; + } + + // copy each extended attribute + try { + byte[] name; + while ((name = readdir(dp)) != null) { + // ignore "." and ".." + if (name[0] == '.') { + if (name.length == 1) + continue; + if (name.length == 2 && name[1] == '.') + continue; + } + copyExtendedAttribute(ofd, name, nfd); + } + } finally { + closedir(dp); + } + } catch (UnixException ignore) { + } + } + + private static void copyExtendedAttribute(int ofd, byte[] name, int nfd) + throws UnixException + { + // open source attribute file + int src = openat(ofd, name, (O_RDONLY|O_XATTR), 0); + try { + // create target attribute file + int dst = openat(nfd, name, (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR), + UnixFileModeAttribute.ALL_PERMISSIONS); + try { + UnixCopyFile.transfer(dst, src, 0L); + } finally { + close(dst); + } + } finally { + close(src); + } + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java b/jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java new file mode 100644 index 00000000000..6a11ebdd7f7 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java @@ -0,0 +1,770 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.*; +import java.io.IOException; +import sun.misc.Unsafe; + +import static sun.nio.fs.UnixConstants.*; + +/** + * Solaris implementation of WatchService based on file events notification + * facility. + */ + +class SolarisWatchService + extends AbstractWatchService +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static int addressSize = unsafe.addressSize(); + + private static int dependsArch(int value32, int value64) { + return (addressSize == 4) ? value32 : value64; + } + + /* + * typedef struct port_event { + * int portev_events; + * ushort_t portev_source; + * ushort_t portev_pad; + * uintptr_t portev_object; + * void *portev_user; + * } port_event_t; + */ + private static final int SIZEOF_PORT_EVENT = dependsArch(16, 24); + private static final int OFFSETOF_EVENTS = 0; + private static final int OFFSETOF_SOURCE = 4; + private static final int OFFSETOF_OBJECT = 8; + + /* + * typedef struct file_obj { + * timestruc_t fo_atime; + * timestruc_t fo_mtime; + * timestruc_t fo_ctime; + * uintptr_t fo_pad[3]; + * char *fo_name; + * } file_obj_t; + */ + private static final int SIZEOF_FILEOBJ = dependsArch(40, 80); + private static final int OFFSET_FO_NAME = dependsArch(36, 72); + + // port sources + private static final short PORT_SOURCE_USER = 3; + private static final short PORT_SOURCE_FILE = 7; + + // user-watchable events + private static final int FILE_MODIFIED = 0x00000002; + private static final int FILE_ATTRIB = 0x00000004; + private static final int FILE_NOFOLLOW = 0x10000000; + + // exception events + private static final int FILE_DELETE = 0x00000010; + private static final int FILE_RENAME_TO = 0x00000020; + private static final int FILE_RENAME_FROM = 0x00000040; + private static final int UNMOUNTED = 0x20000000; + private static final int MOUNTEDOVER = 0x40000000; + + // background thread to read change events + private final Poller poller; + + SolarisWatchService(UnixFileSystem fs) throws IOException { + int port = -1; + try { + port = portCreate(); + } catch (UnixException x) { + throw new IOException(x.errorString()); + } + + this.poller = new Poller(fs, this, port); + this.poller.start(); + } + + @Override + WatchKey register(Path dir, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) + throws IOException + { + // delegate to poller + return poller.register(dir, events, modifiers); + } + + @Override + void implClose() throws IOException { + // delegate to poller + poller.close(); + } + + /** + * WatchKey implementation + */ + private class SolarisWatchKey extends AbstractWatchKey + implements DirectoryNode + { + private final UnixPath dir; + private final UnixFileKey fileKey; + + // pointer to native file_obj object + private final long object; + + // events (may be changed). set to null when watch key is invalid + private volatile Set<? extends WatchEvent.Kind<?>> events; + + // map of entries in directory; created lazily; accessed only by + // poller thread. + private Map<Path,EntryNode> children; + + SolarisWatchKey(SolarisWatchService watcher, + UnixPath dir, + UnixFileKey fileKey, + long object, + Set<? extends WatchEvent.Kind<?>> events) + { + super(watcher); + this.dir = dir; + this.fileKey = fileKey; + this.object = object; + this.events = events; + } + + UnixPath getFileRef() { + return dir; + } + + UnixFileKey getFileKey() { + return fileKey; + } + + @Override + public long object() { + return object; + } + + void invalidate() { + events = null; + } + + Set<? extends WatchEvent.Kind<?>> events() { + return events; + } + + void setEvents(Set<? extends WatchEvent.Kind<?>> events) { + this.events = events; + } + + @Override + public boolean isValid() { + return events != null; + } + + @Override + public void cancel() { + if (isValid()) { + // delegate to poller + poller.cancel(this); + } + } + + @Override + public void addChild(Path name, EntryNode node) { + if (children == null) + children = new HashMap<Path,EntryNode>(); + children.put(name, node); + } + + @Override + public void removeChild(Path name) { + children.remove(name); + } + + @Override + public EntryNode getChild(Path name) { + if (children != null) + return children.get(name); + return null; + } + } + + /** + * Background thread to read from port + */ + private class Poller extends AbstractPoller { + + // maximum number of events to read per call to port_getn + private static final int MAX_EVENT_COUNT = 128; + + // events that map to ENTRY_DELETE + private static final int FILE_REMOVED = + (FILE_DELETE|FILE_RENAME_TO|FILE_RENAME_FROM); + + // events that tell us not to re-associate the object + private static final int FILE_EXCEPTION = + (FILE_REMOVED|UNMOUNTED|MOUNTEDOVER); + + // address of event buffers (used to receive events with port_getn) + private final long bufferAddress; + + private final SolarisWatchService watcher; + + // the I/O port + private final int port; + + // maps file key (dev/inode) to WatchKey + private final Map<UnixFileKey,SolarisWatchKey> fileKey2WatchKey; + + // maps file_obj object to Node + private final Map<Long,Node> object2Node; + + /** + * Create a new instance + */ + Poller(UnixFileSystem fs, SolarisWatchService watcher, int port) { + this.watcher = watcher; + this.port = port; + this.bufferAddress = + unsafe.allocateMemory(SIZEOF_PORT_EVENT * MAX_EVENT_COUNT); + this.fileKey2WatchKey = new HashMap<UnixFileKey,SolarisWatchKey>(); + this.object2Node = new HashMap<Long,Node>(); + } + + @Override + void wakeup() throws IOException { + // write to port to wakeup polling thread + try { + portSend(port, 0); + } catch (UnixException x) { + throw new IOException(x.errorString()); + } + } + + @Override + Object implRegister(Path obj, + Set<? extends WatchEvent.Kind<?>> events, + WatchEvent.Modifier... modifiers) + { + // no modifiers supported at this time + if (modifiers.length > 0) { + for (WatchEvent.Modifier modifier: modifiers) { + if (modifier == null) + return new NullPointerException(); + if (modifier instanceof com.sun.nio.file.SensitivityWatchEventModifier) + continue; // ignore + return new UnsupportedOperationException("Modifier not supported"); + } + } + + UnixPath dir = (UnixPath)obj; + + // check file is directory + UnixFileAttributes attrs = null; + try { + attrs = UnixFileAttributes.get(dir, true); + } catch (UnixException x) { + return x.asIOException(dir); + } + if (!attrs.isDirectory()) { + return new NotDirectoryException(dir.getPathForExecptionMessage()); + } + + // return existing watch key after updating events if already + // registered + UnixFileKey fileKey = attrs.fileKey(); + SolarisWatchKey watchKey = fileKey2WatchKey.get(fileKey); + if (watchKey != null) { + updateEvents(watchKey, events); + return watchKey; + } + + // register directory + long object = 0L; + try { + object = registerImpl(dir, (FILE_MODIFIED | FILE_ATTRIB)); + } catch (UnixException x) { + return x.asIOException(dir); + } + + // create watch key and insert it into maps + watchKey = new SolarisWatchKey(watcher, dir, fileKey, object, events); + object2Node.put(object, watchKey); + fileKey2WatchKey.put(fileKey, watchKey); + + // register all entries in directory + registerChildren(dir, watchKey, false); + + return watchKey; + } + + // cancel single key + @Override + void implCancelKey(WatchKey obj) { + SolarisWatchKey key = (SolarisWatchKey)obj; + if (key.isValid()) { + fileKey2WatchKey.remove(key.getFileKey()); + + // release resources for entries in directory + if (key.children != null) { + for (Map.Entry<Path,EntryNode> entry: key.children.entrySet()) { + EntryNode node = entry.getValue(); + long object = node.object(); + object2Node.remove(object); + releaseObject(object, true); + } + } + + // release resources for directory + long object = key.object(); + object2Node.remove(object); + releaseObject(object, true); + + // and finally invalidate the key + key.invalidate(); + } + } + + // close watch service + @Override + void implCloseAll() { + // release all native resources + for (Long object: object2Node.keySet()) { + releaseObject(object, true); + } + + // invalidate all keys + for (Map.Entry<UnixFileKey,SolarisWatchKey> entry: fileKey2WatchKey.entrySet()) { + entry.getValue().invalidate(); + } + + // clean-up + object2Node.clear(); + fileKey2WatchKey.clear(); + + // free global resources + unsafe.freeMemory(bufferAddress); + UnixNativeDispatcher.close(port); + } + + /** + * Poller main loop. Blocks on port_getn waiting for events and then + * processes them. + */ + @Override + public void run() { + try { + for (;;) { + int n = portGetn(port, bufferAddress, MAX_EVENT_COUNT); + assert n > 0; + + long address = bufferAddress; + for (int i=0; i<n; i++) { + boolean shutdown = processEvent(address); + if (shutdown) + return; + address += SIZEOF_PORT_EVENT; + } + } + } catch (UnixException x) { + x.printStackTrace(); + } + } + + /** + * Process a single port_event + * + * Returns true if poller thread is requested to shutdown. + */ + boolean processEvent(long address) { + // pe->portev_source + short source = unsafe.getShort(address + OFFSETOF_SOURCE); + // pe->portev_object + long object = unsafe.getAddress(address + OFFSETOF_OBJECT); + // pe->portev_events + int events = unsafe.getInt(address + OFFSETOF_EVENTS); + + // user event is trigger to process pending requests + if (source != PORT_SOURCE_FILE) { + if (source == PORT_SOURCE_USER) { + // process any pending requests + boolean shutdown = processRequests(); + if (shutdown) + return true; + } + return false; + } + + // lookup object to get Node + Node node = object2Node.get(object); + if (node == null) { + // should not happen + return false; + } + + // As a workaround for 6642290 and 6636438/6636412 we don't use + // FILE_EXCEPTION events to tell use not to register the file. + // boolean reregister = (events & FILE_EXCEPTION) == 0; + boolean reregister = true; + + // If node is EntryNode then event relates to entry in directory + // If node is a SolarisWatchKey (DirectoryNode) then event relates + // to a watched directory. + boolean isDirectory = (node instanceof SolarisWatchKey); + if (isDirectory) { + processDirectoryEvents((SolarisWatchKey)node, events); + } else { + boolean ignore = processEntryEvents((EntryNode)node, events); + if (ignore) + reregister = false; + } + + // need to re-associate to get further events + if (reregister) { + try { + events = FILE_MODIFIED | FILE_ATTRIB; + if (!isDirectory) events |= FILE_NOFOLLOW; + portAssociate(port, + PORT_SOURCE_FILE, + object, + events); + } catch (UnixException x) { + // unable to re-register + reregister = false; + } + } + + // object is not re-registered so release resources. If + // object is a watched directory then signal key + if (!reregister) { + // release resources + object2Node.remove(object); + releaseObject(object, false); + + // if watch key then signal it + if (isDirectory) { + SolarisWatchKey key = (SolarisWatchKey)node; + fileKey2WatchKey.remove( key.getFileKey() ); + key.invalidate(); + key.signal(); + } else { + // if entry then remove it from parent + EntryNode entry = (EntryNode)node; + SolarisWatchKey key = (SolarisWatchKey)entry.parent(); + key.removeChild(entry.name()); + } + } + + return false; + } + + /** + * Process directory events. If directory is modified then re-scan + * directory to register any new entries + */ + void processDirectoryEvents(SolarisWatchKey key, int mask) { + if ((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) { + registerChildren(key.getFileRef(), key, + key.events().contains(StandardWatchEventKind.ENTRY_CREATE)); + } + } + + /** + * Process events for entries in registered directories. Returns {@code + * true} if events are ignored because the watch key has been cancelled. + */ + boolean processEntryEvents(EntryNode node, int mask) { + SolarisWatchKey key = (SolarisWatchKey)node.parent(); + Set<? extends WatchEvent.Kind<?>> events = key.events(); + if (events == null) { + // key has been cancelled so ignore event + return true; + } + + // entry modified + if (((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) && + events.contains(StandardWatchEventKind.ENTRY_MODIFY)) + { + key.signalEvent(StandardWatchEventKind.ENTRY_MODIFY, node.name()); + } + + // entry removed + if (((mask & (FILE_REMOVED)) != 0) && + events.contains(StandardWatchEventKind.ENTRY_DELETE)) + { + // Due to 6636438/6636412 we may get a remove event for cases + // where a rmdir/unlink/rename is attempted but fails. Until + // this issue is resolved we re-lstat the file to check if it + // exists. If it exists then we ignore the event. To keep the + // workaround simple we don't check the st_ino so it isn't + // effective when the file is replaced. + boolean removed = true; + try { + UnixFileAttributes + .get(key.getFileRef().resolve(node.name()), false); + removed = false; + } catch (UnixException x) { } + + if (removed) + key.signalEvent(StandardWatchEventKind.ENTRY_DELETE, node.name()); + } + return false; + } + + /** + * Registers all entries in the given directory + * + * The {@code sendEvents} parameter indicates if ENTRY_CREATE events + * should be queued when new entries are found. When initially + * registering a directory then will always be false. When re-scanning + * a directory then it depends on if the event is enabled or not. + */ + void registerChildren(UnixPath dir, + SolarisWatchKey parent, + boolean sendEvents) + { + // if the ENTRY_MODIFY event is not enabled then we don't need + // modification events for entries in the directory + int events = FILE_NOFOLLOW; + if (parent.events().contains(StandardWatchEventKind.ENTRY_MODIFY)) + events |= (FILE_MODIFIED | FILE_ATTRIB); + + DirectoryStream<Path> stream = null; + try { + stream = dir.newDirectoryStream(); + } catch (IOException x) { + // nothing we can do + return; + } + try { + for (Path entry: stream) { + Path name = entry.getName(); + + // skip entry if already registered + if (parent.getChild(name) != null) + continue; + + // send ENTRY_CREATE if enabled + if (sendEvents) { + parent.signalEvent(StandardWatchEventKind.ENTRY_CREATE, name); + } + + // register it + long object = 0L; + try { + object = registerImpl((UnixPath)entry, events); + } catch (UnixException x) { + // can't register so ignore for now. + continue; + } + + // create node + EntryNode node = new EntryNode(object, entry.getName(), parent); + // tell the parent about it + parent.addChild(entry.getName(), node); + object2Node.put(object, node); + } + } catch (ConcurrentModificationException x) { + // error during iteration which we ignore for now + } finally { + try { + stream.close(); + } catch (IOException x) { } + } + } + + /** + * Update watch key's events. Where the ENTRY_MODIFY changes then we + * need to update the events of registered children. + */ + void updateEvents(SolarisWatchKey key, Set<? extends WatchEvent.Kind<?>> events) { + // update events, rembering if ENTRY_MODIFY was previously + // enabled or disabled. + boolean wasModifyEnabled = key.events() + .contains(StandardWatchEventKind.ENTRY_MODIFY); + key.setEvents(events); + + // check if ENTRY_MODIFY has changed + boolean isModifyEnabled = events + .contains(StandardWatchEventKind.ENTRY_MODIFY); + if (wasModifyEnabled == isModifyEnabled) { + return; + } + + // if changed then update events of children + if (key.children != null) { + int ev = FILE_NOFOLLOW; + if (isModifyEnabled) + ev |= (FILE_MODIFIED | FILE_ATTRIB); + + for (Map.Entry<Path,EntryNode> entry: key.children.entrySet()) { + long object = entry.getValue().object(); + try { + portAssociate(port, + PORT_SOURCE_FILE, + object, + ev); + } catch (UnixException x) { + // nothing we can do. + } + } + } + } + + /** + * Calls port_associate to register the given path. + * Returns pointer to fileobj structure that is allocated for + * the registration. + */ + long registerImpl(UnixPath dir, int events) + throws UnixException + { + // allocate memory for the path (file_obj->fo_name field) + byte[] path = dir.getByteArrayForSysCalls(); + int len = path.length; + long name = unsafe.allocateMemory(len+1); + unsafe.copyMemory(path, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, + name, (long)len); + unsafe.putByte(name + len, (byte)0); + + // allocate memory for filedatanode structure - this is the object + // to port_associate + long object = unsafe.allocateMemory(SIZEOF_FILEOBJ); + unsafe.setMemory(null, object, SIZEOF_FILEOBJ, (byte)0); + unsafe.putAddress(object + OFFSET_FO_NAME, name); + + // associate the object with the port + try { + portAssociate(port, + PORT_SOURCE_FILE, + object, + events); + } catch (UnixException x) { + // debugging + if (x.errno() == EAGAIN) { + System.err.println("The maximum number of objects associated "+ + "with the port has been reached"); + } + + unsafe.freeMemory(name); + unsafe.freeMemory(object); + throw x; + } + return object; + } + + /** + * Frees all resources for an file_obj object; optionally remove + * association from port + */ + void releaseObject(long object, boolean dissociate) { + // remove association + if (dissociate) { + try { + portDissociate(port, PORT_SOURCE_FILE, object); + } catch (UnixException x) { + // ignore + } + } + + // free native memory + long name = unsafe.getAddress(object + OFFSET_FO_NAME); + unsafe.freeMemory(name); + unsafe.freeMemory(object); + } + } + + /** + * A node with native (file_obj) resources + */ + private static interface Node { + long object(); + } + + /** + * A directory node with a map of the entries in the directory + */ + private static interface DirectoryNode extends Node { + void addChild(Path name, EntryNode node); + void removeChild(Path name); + EntryNode getChild(Path name); + } + + /** + * An implementation of a node that is an entry in a directory. + */ + private static class EntryNode implements Node { + private final long object; + private final Path name; + private final DirectoryNode parent; + + EntryNode(long object, Path name, DirectoryNode parent) { + this.object = object; + this.name = name; + this.parent = parent; + } + + @Override + public long object() { + return object; + } + + Path name() { + return name; + } + + DirectoryNode parent() { + return parent; + } + } + + // -- native methods -- + + private static native void init(); + + private static native int portCreate() throws UnixException; + + private static native void portAssociate(int port, int source, long object, int events) + throws UnixException; + + private static native void portDissociate(int port, int source, long object) + throws UnixException; + + private static native void portSend(int port, int events) + throws UnixException; + + private static native int portGetn(int port, long address, int max) + throws UnixException; + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + init(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixChannelFactory.java b/jdk/src/solaris/classes/sun/nio/fs/UnixChannelFactory.java new file mode 100644 index 00000000000..a8265dca7f6 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixChannelFactory.java @@ -0,0 +1,286 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.channels.*; +import java.io.FileDescriptor; +import java.util.Set; + +import sun.nio.ch.FileChannelImpl; +import sun.nio.ch.ThreadPool; +import sun.nio.ch.SimpleAsynchronousFileChannelImpl; +import sun.misc.SharedSecrets; +import sun.misc.JavaIOFileDescriptorAccess; + +import com.sun.nio.file.ExtendedOpenOption; + +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.UnixConstants.*; + +/** + * Factory for FileChannels and AsynchronousFileChannels + */ + +class UnixChannelFactory { + private static final JavaIOFileDescriptorAccess fdAccess = + SharedSecrets.getJavaIOFileDescriptorAccess(); + + private UnixChannelFactory() { + } + + /** + * Represents the flags from a user-supplied set of open options. + */ + private static class Flags { + boolean read; + boolean write; + boolean append; + boolean truncateExisting; + boolean noFollowLinks; + boolean create; + boolean createNew; + boolean deleteOnClose; + boolean sync; + boolean dsync; + + static Flags toFlags(Set<? extends OpenOption> options) { + Flags flags = new Flags(); + for (OpenOption option: options) { + if (option instanceof StandardOpenOption) { + switch ((StandardOpenOption)option) { + case READ : flags.read = true; break; + case WRITE : flags.write = true; break; + case APPEND : flags.append = true; break; + case TRUNCATE_EXISTING : flags.truncateExisting = true; break; + case CREATE : flags.create = true; break; + case CREATE_NEW : flags.createNew = true; break; + case DELETE_ON_CLOSE : flags.deleteOnClose = true; break; + case SPARSE : /* ignore */ break; + case SYNC : flags.sync = true; break; + case DSYNC : flags.dsync = true; break; + default: throw new UnsupportedOperationException(); + } + continue; + } + if (option == LinkOption.NOFOLLOW_LINKS) { + flags.noFollowLinks = true; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new UnsupportedOperationException(); + } + return flags; + } + } + + + /** + * Constructs a file channel from an existing (open) file descriptor + */ + static FileChannel newFileChannel(int fd, boolean reading, boolean writing) { + FileDescriptor fdObj = new FileDescriptor(); + fdAccess.set(fdObj, fd); + return FileChannelImpl.open(fdObj, reading, writing, null); + } + + /** + * Constructs a file channel by opening a file using a dfd/path pair + */ + static FileChannel newFileChannel(int dfd, + UnixPath path, + String pathForPermissionCheck, + Set<? extends OpenOption> options, + int mode) + throws UnixException + { + Flags flags = Flags.toFlags(options); + + // default is reading; append => writing + if (!flags.read && !flags.write) { + if (flags.append) { + flags.write = true; + } else { + flags.read = true; + } + } + + // validation + if (flags.read && flags.append) + throw new IllegalArgumentException("READ + APPEND not allowed"); + if (flags.append && flags.truncateExisting) + throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed"); + + FileDescriptor fdObj = open(dfd, path, pathForPermissionCheck, flags, mode); + return FileChannelImpl.open(fdObj, flags.read, flags.write, null); + } + + /** + * Constructs a file channel by opening the given file. + */ + static FileChannel newFileChannel(UnixPath path, + Set<? extends OpenOption> options, + int mode) + throws UnixException + { + return newFileChannel(-1, path, null, options, mode); + } + + /** + * Constructs an asynchronous file channel by opening the given file. + */ + static AsynchronousFileChannel newAsynchronousFileChannel(UnixPath path, + Set<? extends OpenOption> options, + int mode, + ThreadPool pool) + throws UnixException + { + Flags flags = Flags.toFlags(options); + + // default is reading + if (!flags.read && !flags.write) { + flags.read = true; + } + + // validation + if (flags.append) + throw new UnsupportedOperationException("APPEND not allowed"); + + // for now use simple implementation + FileDescriptor fdObj = open(-1, path, null, flags, mode); + return SimpleAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool); + } + + /** + * Opens file based on parameters and options, returning a FileDescriptor + * encapsulating the handle to the open file. + */ + static FileDescriptor open(int dfd, + UnixPath path, + String pathForPermissionCheck, + Flags flags, + int mode) + throws UnixException + { + // map to oflags + int oflags; + if (flags.read && flags.write) { + oflags = O_RDWR; + } else { + oflags = (flags.write) ? O_WRONLY : O_RDONLY; + } + if (flags.write) { + if (flags.truncateExisting) + oflags |= O_TRUNC; + if (flags.append) + oflags |= O_APPEND; + + // create flags + if (flags.createNew) { + byte[] pathForSysCall = path.asByteArray(); + + // throw exception if file name is "." to avoid confusing error + if ((pathForSysCall[pathForSysCall.length-1] == '.') && + (pathForSysCall.length == 1 || + (pathForSysCall[pathForSysCall.length-2] == '/'))) + { + throw new UnixException(EEXIST); + } + oflags |= (O_CREAT | O_EXCL); + } else { + if (flags.create) + oflags |= O_CREAT; + } + } + + // follow links by default + boolean followLinks = true; + if (!flags.createNew && (flags.noFollowLinks || flags.deleteOnClose)) { + followLinks = false; + oflags |= O_NOFOLLOW; + } + + if (flags.dsync) + oflags |= O_DSYNC; + if (flags.sync) + oflags |= O_SYNC; + + // permission check before we open the file + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (pathForPermissionCheck == null) + pathForPermissionCheck = path.getPathForPermissionCheck(); + if (flags.read) + sm.checkRead(pathForPermissionCheck); + if (flags.write) + sm.checkWrite(pathForPermissionCheck); + if (flags.deleteOnClose) + sm.checkDelete(pathForPermissionCheck); + } + + int fd; + try { + if (dfd >= 0) { + fd = openat(dfd, path.asByteArray(), oflags, mode); + } else { + fd = UnixNativeDispatcher.open(path, oflags, mode); + } + } catch (UnixException x) { + // Linux error can be EISDIR or EEXIST when file exists + if (flags.createNew && (x.errno() == EISDIR)) { + x.setError(EEXIST); + } + + // handle ELOOP to avoid confusing message + if (!followLinks && (x.errno() == ELOOP)) { + x = new UnixException(x.getMessage() + " (NOFOLLOW_LINKS specified)"); + } + + throw x; + } + + // unlink file immediately if delete on close. The spec is clear that + // an implementation cannot guarantee to unlink the correct file when + // replaced by an attacker after it is opened. + if (flags.deleteOnClose) { + try { + if (dfd >= 0) { + unlinkat(dfd, path.asByteArray(), 0); + } else { + unlink(path); + } + } catch (UnixException ignore) { + // best-effort + } + } + + // create java.io.FileDescriptor + FileDescriptor fdObj = new FileDescriptor(); + fdAccess.set(fdObj, fd); + return fdObj; + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixCopyFile.java b/jdk/src/solaris/classes/sun/nio/fs/UnixCopyFile.java new file mode 100644 index 00000000000..808cc1e34dc --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixCopyFile.java @@ -0,0 +1,608 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.concurrent.ExecutionException; +import com.sun.nio.file.ExtendedCopyOption; + +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.UnixConstants.*; + + +/** + * Unix implementation of Path#copyTo and Path#moveTo methods. + */ + +class UnixCopyFile { + private UnixCopyFile() { } + + // The flags that control how a file is copied or moved + private static class Flags { + boolean replaceExisting; + boolean atomicMove; + boolean followLinks; + boolean interruptible; + + // the attributes to copy + boolean copyBasicAttributes; + boolean copyPosixAttributes; + boolean copyNonPosixAttributes; + + // flags that indicate if we should fail if attributes cannot be copied + boolean failIfUnableToCopyBasic; + boolean failIfUnableToCopyPosix; + boolean failIfUnableToCopyNonPosix; + + static Flags fromCopyOptions(CopyOption... options) { + Flags flags = new Flags(); + flags.followLinks = true; + for (CopyOption option: options) { + if (option == StandardCopyOption.REPLACE_EXISTING) { + flags.replaceExisting = true; + continue; + } + if (option == LinkOption.NOFOLLOW_LINKS) { + flags.followLinks = false; + continue; + } + if (option == StandardCopyOption.COPY_ATTRIBUTES) { + // copy all attributes but only fail if basic attributes + // cannot be copied + flags.copyBasicAttributes = true; + flags.copyPosixAttributes = true; + flags.copyNonPosixAttributes = true; + flags.failIfUnableToCopyBasic = true; + continue; + } + if (option == ExtendedCopyOption.INTERRUPTIBLE) { + flags.interruptible = true; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new UnsupportedOperationException("Unsupported copy option"); + } + return flags; + } + + static Flags fromMoveOptions(CopyOption... options) { + Flags flags = new Flags(); + for (CopyOption option: options) { + if (option == StandardCopyOption.ATOMIC_MOVE) { + flags.atomicMove = true; + continue; + } + if (option == StandardCopyOption.REPLACE_EXISTING) { + flags.replaceExisting = true; + continue; + } + if (option == LinkOption.NOFOLLOW_LINKS) { + // ignore + continue; + } + if (option == null) + throw new NullPointerException(); + throw new UnsupportedOperationException("Unsupported copy option"); + } + + // a move requires that all attributes be copied but only fail if + // the basic attributes cannot be copied + flags.copyBasicAttributes = true; + flags.copyPosixAttributes = true; + flags.copyNonPosixAttributes = true; + flags.failIfUnableToCopyBasic = true; + return flags; + } + } + + // copy directory from source to target + private static void copyDirectory(UnixPath source, + UnixFileAttributes attrs, + UnixPath target, + Flags flags) + throws IOException + { + try { + mkdir(target, attrs.mode()); + } catch (UnixException x) { + x.rethrowAsIOException(target); + } + + // no attributes to copy + if (!flags.copyBasicAttributes && + !flags.copyPosixAttributes && + !flags.copyNonPosixAttributes) return; + + // open target directory if possible (this can fail when copying a + // directory for which we don't have read access). + int dfd = -1; + try { + dfd = open(target, O_RDONLY, 0); + } catch (UnixException x) { + // access to target directory required to copy named attributes + if (flags.copyNonPosixAttributes && flags.failIfUnableToCopyNonPosix) { + try { rmdir(target); } catch (UnixException ignore) { } + x.rethrowAsIOException(target); + } + } + + boolean done = false; + try { + // copy owner/group/permissions + if (flags.copyPosixAttributes){ + try { + if (dfd >= 0) { + fchown(dfd, attrs.uid(), attrs.gid()); + fchmod(dfd, attrs.mode()); + } else { + chown(target, attrs.uid(), attrs.gid()); + chmod(target, attrs.mode()); + } + } catch (UnixException x) { + // unable to set owner/group + if (flags.failIfUnableToCopyPosix) + x.rethrowAsIOException(target); + } + } + // copy other attributes + if (flags.copyNonPosixAttributes && (dfd >= 0)) { + int sfd = -1; + try { + sfd = open(source, O_RDONLY, 0); + } catch (UnixException x) { + if (flags.failIfUnableToCopyNonPosix) + x.rethrowAsIOException(source); + } + if (sfd >= 0) { + source.getFileSystem().copyNonPosixAttributes(sfd, dfd); + close(sfd); + } + } + // copy time stamps last + if (flags.copyBasicAttributes) { + try { + if (dfd >= 0) { + futimes(dfd, attrs.lastAccessTime(), + attrs.lastModifiedTime()); + } else { + utimes(target, attrs.lastAccessTime(), + attrs.lastModifiedTime()); + } + } catch (UnixException x) { + // unable to set times + if (flags.failIfUnableToCopyBasic) + x.rethrowAsIOException(target); + } + } + done = true; + } finally { + if (dfd >= 0) + close(dfd); + if (!done) { + // rollback + try { rmdir(target); } catch (UnixException ignore) { } + } + } + } + + // copy regular file from source to target + private static void copyFile(UnixPath source, + UnixFileAttributes attrs, + UnixPath target, + Flags flags, + long addressToPollForCancel) + throws IOException + { + int fi = -1; + try { + fi = open(source, O_RDONLY, 0); + } catch (UnixException x) { + x.rethrowAsIOException(source); + } + + try { + // open new file + int fo = -1; + try { + fo = open(target, + (O_WRONLY | + O_CREAT | + O_TRUNC), + attrs.mode()); + } catch (UnixException x) { + x.rethrowAsIOException(target); + } + + // set to true when file and attributes copied + boolean complete = false; + try { + // transfer bytes to target file + try { + transfer(fo, fi, addressToPollForCancel); + } catch (UnixException x) { + x.rethrowAsIOException(source, target); + } + // copy owner/permissions + if (flags.copyPosixAttributes) { + try { + fchown(fo, attrs.uid(), attrs.gid()); + fchmod(fo, attrs.mode()); + } catch (UnixException x) { + if (flags.failIfUnableToCopyPosix) + x.rethrowAsIOException(target); + } + } + // copy non POSIX attributes (depends on file system) + if (flags.copyNonPosixAttributes) { + source.getFileSystem().copyNonPosixAttributes(fi, fo); + } + // copy time attributes + if (flags.copyBasicAttributes) { + try { + futimes(fo, attrs.lastAccessTime(), attrs.lastModifiedTime()); + } catch (UnixException x) { + if (flags.failIfUnableToCopyBasic) + x.rethrowAsIOException(target); + } + } + complete = true; + } finally { + close(fo); + + // copy of file or attributes failed so rollback + if (!complete) { + try { + unlink(target); + } catch (UnixException ignore) { } + } + } + } finally { + close(fi); + } + } + + // copy symbolic link from source to target + private static void copyLink(UnixPath source, + UnixFileAttributes attrs, + UnixPath target, + Flags flags) + throws IOException + { + byte[] linktarget = null; + try { + linktarget = readlink(source); + } catch (UnixException x) { + x.rethrowAsIOException(source); + } + try { + symlink(linktarget, target); + + if (flags.copyPosixAttributes) { + try { + lchown(target, attrs.uid(), attrs.gid()); + } catch (UnixException x) { + // ignore since link attributes not required to be copied + } + } + } catch (UnixException x) { + x.rethrowAsIOException(target); + } + } + + // copy special file from source to target + private static void copySpecial(UnixPath source, + UnixFileAttributes attrs, + UnixPath target, + Flags flags) + throws IOException + { + try { + mknod(target, attrs.mode(), attrs.rdev()); + } catch (UnixException x) { + x.rethrowAsIOException(target); + } + boolean done = false; + try { + if (flags.copyPosixAttributes) { + try { + chown(target, attrs.uid(), attrs.gid()); + chmod(target, attrs.mode()); + } catch (UnixException x) { + if (flags.failIfUnableToCopyPosix) + x.rethrowAsIOException(target); + } + } + if (flags.copyBasicAttributes) { + try { + utimes(target, attrs.lastAccessTime(), attrs.lastModifiedTime()); + } catch (UnixException x) { + if (flags.failIfUnableToCopyBasic) + x.rethrowAsIOException(target); + } + } + done = true; + } finally { + if (!done) { + try { unlink(target); } catch (UnixException ignore) { } + } + } + } + + // move file from source to target + static void move(UnixPath source, UnixPath target, CopyOption... options) + throws IOException + { + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + source.checkWrite(); + target.checkWrite(); + } + + // translate options into flags + Flags flags = Flags.fromMoveOptions(options); + + // handle atomic rename case + if (flags.atomicMove) { + try { + rename(source, target); + } catch (UnixException x) { + if (x.errno() == EXDEV) { + throw new AtomicMoveNotSupportedException( + source.getPathForExecptionMessage(), + target.getPathForExecptionMessage(), + x.errorString()); + } + x.rethrowAsIOException(source, target); + } + return; + } + + // move using rename or copy+delete + UnixFileAttributes sourceAttrs = null; + UnixFileAttributes targetAttrs = null; + + // get attributes of source file (don't follow links) + try { + sourceAttrs = UnixFileAttributes.get(source, false); + } catch (UnixException x) { + x.rethrowAsIOException(source); + } + + // get attributes of target file (don't follow links) + try { + targetAttrs = UnixFileAttributes.get(target, false); + } catch (UnixException x) { + // ignore + } + boolean targetExists = (targetAttrs != null); + + // if the target exists: + // 1. check if source and target are the same file + // 2. throw exception if REPLACE_EXISTING option is not set + // 3. delete target if REPLACE_EXISTING option set + if (targetExists) { + if (sourceAttrs.isSameFile(targetAttrs)) + return; // nothing to do as files are identical + if (!flags.replaceExisting) { + throw new FileAlreadyExistsException( + target.getPathForExecptionMessage()); + } + + // attempt to delete target + try { + if (targetAttrs.isDirectory()) { + rmdir(target); + } else { + unlink(target); + } + } catch (UnixException x) { + // target is non-empty directory that can't be replaced. + if (targetAttrs.isDirectory() && + (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) + { + throw new FileAlreadyExistsException( + source.getPathForExecptionMessage(), + target.getPathForExecptionMessage(), + x.getMessage()); + } + x.rethrowAsIOException(target); + } + } + + // first try rename + try { + rename(source, target); + return; + } catch (UnixException x) { + if (x.errno() != EXDEV && x.errno() != EISDIR) { + x.rethrowAsIOException(source, target); + } + } + + // copy source to target + if (sourceAttrs.isDirectory()) { + copyDirectory(source, sourceAttrs, target, flags); + } else { + if (sourceAttrs.isSymbolicLink()) { + copyLink(source, sourceAttrs, target, flags); + } else { + if (sourceAttrs.isDevice()) { + copySpecial(source, sourceAttrs, target, flags); + } else { + copyFile(source, sourceAttrs, target, flags, 0L); + } + } + } + + // delete source + try { + if (sourceAttrs.isDirectory()) { + rmdir(source); + } else { + unlink(source); + } + } catch (UnixException x) { + // file was copied but unable to unlink the source file so attempt + // to remove the target and throw a reasonable exception + try { + if (sourceAttrs.isDirectory()) { + rmdir(target); + } else { + unlink(target); + } + } catch (UnixException ignore) { } + + if (sourceAttrs.isDirectory() && + (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) + { + throw new DirectoryNotEmptyException( + source.getPathForExecptionMessage()); + } + x.rethrowAsIOException(source); + } + } + + // copy file from source to target + static void copy(final UnixPath source, + final UnixPath target, + CopyOption... options) throws IOException + { + // permission checks + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + source.checkRead(); + target.checkWrite(); + } + + // translate options into flags + final Flags flags = Flags.fromCopyOptions(options); + + UnixFileAttributes sourceAttrs = null; + UnixFileAttributes targetAttrs = null; + + // get attributes of source file + try { + sourceAttrs = UnixFileAttributes.get(source, flags.followLinks); + } catch (UnixException x) { + x.rethrowAsIOException(source); + } + + // if source file is symbolic link then we must check LinkPermission + if (sm != null && sourceAttrs.isSymbolicLink()) { + sm.checkPermission(new LinkPermission("symbolic")); + } + + // get attributes of target file (don't follow links) + try { + targetAttrs = UnixFileAttributes.get(target, false); + } catch (UnixException x) { + // ignore + } + boolean targetExists = (targetAttrs != null); + + // if the target exists: + // 1. check if source and target are the same file + // 2. throw exception if REPLACE_EXISTING option is not set + // 3. try to unlink the target + if (targetExists) { + if (sourceAttrs.isSameFile(targetAttrs)) + return; // nothing to do as files are identical + if (!flags.replaceExisting) + throw new FileAlreadyExistsException( + target.getPathForExecptionMessage()); + try { + if (targetAttrs.isDirectory()) { + rmdir(target); + } else { + unlink(target); + } + } catch (UnixException x) { + // target is non-empty directory that can't be replaced. + if (targetAttrs.isDirectory() && + (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) + { + throw new FileAlreadyExistsException( + source.getPathForExecptionMessage(), + target.getPathForExecptionMessage(), + x.getMessage()); + } + x.rethrowAsIOException(target); + } + } + + // do the copy + if (sourceAttrs.isDirectory()) { + copyDirectory(source, sourceAttrs, target, flags); + return; + } + if (sourceAttrs.isSymbolicLink()) { + copyLink(source, sourceAttrs, target, flags); + return; + } + if (!flags.interruptible) { + // non-interruptible file copy + copyFile(source, sourceAttrs, target, flags, 0L); + return; + } + + // interruptible file copy + final UnixFileAttributes attrsToCopy = sourceAttrs; + Cancellable copyTask = new Cancellable() { + @Override public void implRun() throws IOException { + copyFile(source, attrsToCopy, target, flags, + addressToPollForCancel()); + } + }; + try { + Cancellable.runInterruptibly(copyTask); + } catch (ExecutionException e) { + Throwable t = e.getCause(); + if (t instanceof IOException) + throw (IOException)t; + throw new IOException(t); + } + } + + // -- native methods -- + + static native void transfer(int dst, int src, long addressToPollForCancel) + throws UnixException; + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + @Override + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + } + +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java b/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java new file mode 100644 index 00000000000..a723d71adb2 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java @@ -0,0 +1,267 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.util.Iterator; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.util.concurrent.locks.*; +import java.io.IOException; +import static sun.nio.fs.UnixNativeDispatcher.*; + +/** + * Unix implementation of java.nio.file.DirectoryStream + */ + +class UnixDirectoryStream + implements DirectoryStream<Path> +{ + // path to directory when originally opened + private final UnixPath dir; + + // directory pointer (returned by opendir) + private final long dp; + + // filter (may be null) + private final DirectoryStream.Filter<? super Path> filter; + + // used to coorindate closing of directory stream + private final ReentrantReadWriteLock streamLock = + new ReentrantReadWriteLock(true); + + // indicates if directory stream is open (synchronize on closeLock) + private volatile boolean isClosed; + + // directory iterator + private Iterator<Path> iterator; + + /** + * Initializes a new instance + */ + UnixDirectoryStream(UnixPath dir, long dp, DirectoryStream.Filter<? super Path> filter) { + this.dir = dir; + this.dp = dp; + this.filter = filter; + } + + protected final UnixPath directory() { + return dir; + } + + protected final Lock readLock() { + return streamLock.readLock(); + } + + protected final Lock writeLock() { + return streamLock.writeLock(); + } + + protected final boolean isOpen() { + return !isClosed; + } + + protected final boolean closeImpl() throws IOException { + if (!isClosed) { + isClosed = true; + try { + closedir(dp); + } catch (UnixException x) { + throw new IOException(x.errorString()); + } + return true; + } else { + return false; + } + } + + @Override + public void close() + throws IOException + { + writeLock().lock(); + try { + closeImpl(); + } finally { + writeLock().unlock(); + } + } + + protected final Iterator<Path> iterator(DirectoryStream<Path> ds) { + if (isClosed) { + throw new IllegalStateException("Directory stream is closed"); + } + synchronized (this) { + if (iterator != null) + throw new IllegalStateException("Iterator already obtained"); + iterator = new UnixDirectoryIterator(ds); + return iterator; + } + } + + @Override + public Iterator<Path> iterator() { + return iterator(this); + } + + /** + * Iterator implementation + */ + private class UnixDirectoryIterator implements Iterator<Path> { + private final DirectoryStream<Path> stream; + + // true when at EOF + private boolean atEof; + + // next entry to return + private Path nextEntry; + + // previous entry returned by next method (needed by remove method) + private Path prevEntry; + + UnixDirectoryIterator(DirectoryStream<Path> stream) { + atEof = false; + this.stream = stream; + } + + // Return true if file name is "." or ".." + private boolean isSelfOrParent(byte[] nameAsBytes) { + if (nameAsBytes[0] == '.') { + if ((nameAsBytes.length == 1) || + (nameAsBytes.length == 2 && nameAsBytes[1] == '.')) { + return true; + } + } + return false; + } + + // Returns next entry (or null) + private Path readNextEntry() { + assert Thread.holdsLock(this); + + for (;;) { + byte[] nameAsBytes = null; + + // prevent close while reading + readLock().lock(); + try { + if (isClosed) + throwAsConcurrentModificationException(new + ClosedDirectoryStreamException()); + try { + nameAsBytes = readdir(dp); + } catch (UnixException x) { + try { + x.rethrowAsIOException(dir); + } catch (IOException ioe) { + throwAsConcurrentModificationException(ioe); + } + } + } finally { + readLock().unlock(); + } + + // EOF + if (nameAsBytes == null) { + return null; + } + + // ignore "." and ".." + if (!isSelfOrParent(nameAsBytes)) { + Path entry = dir.resolve(nameAsBytes); + + // return entry if no filter or filter accepts it + if (filter.accept(entry)) { + return entry; + } + } + } + } + + @Override + public synchronized boolean hasNext() { + if (nextEntry == null && !atEof) { + nextEntry = readNextEntry(); + + // at EOF? + if (nextEntry == null) + atEof = true; + } + return nextEntry != null; + } + + @Override + public synchronized Path next() { + if (nextEntry == null) { + if (!atEof) { + nextEntry = readNextEntry(); + } + if (nextEntry == null) { + atEof = true; + throw new NoSuchElementException(); + } + } + prevEntry = nextEntry; + nextEntry = null; + return prevEntry; + } + + @Override + public void remove() { + if (isClosed) { + throw new ClosedDirectoryStreamException(); + } + Path entry; + synchronized (this) { + if (prevEntry == null) + throw new IllegalStateException("No previous entry to remove"); + entry = prevEntry; + prevEntry = null; + } + + // use (race-free) unlinkat if available + try { + if (stream instanceof UnixSecureDirectoryStream) { + ((UnixSecureDirectoryStream)stream) + .implDelete(entry.getName(), false, 0); + } else { + entry.delete(true); + } + } catch (IOException ioe) { + throwAsConcurrentModificationException(ioe); + } catch (SecurityException se) { + throwAsConcurrentModificationException(se); + } + } + } + + private static void throwAsConcurrentModificationException(Throwable t) { + ConcurrentModificationException cme = new ConcurrentModificationException(); + cme.initCause(t); + throw cme; + } + +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixException.java b/jdk/src/solaris/classes/sun/nio/fs/UnixException.java new file mode 100644 index 00000000000..3a9967540ae --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixException.java @@ -0,0 +1,113 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.io.IOException; + +/** + * Internal exception thrown by native methods when error detected. + */ + +class UnixException extends Exception { + static final long serialVersionUID = 7227016794320723218L; + + private int errno; + private String msg; + + UnixException(int errno) { + this.errno = errno; + this.msg = null; + } + + UnixException(String msg) { + this.errno = 0; + this.msg = msg; + } + + int errno() { + return errno; + } + + void setError(int errno) { + this.errno = errno; + this.msg = null; + } + + String errorString() { + if (msg != null) { + return msg; + } else { + return new String(UnixNativeDispatcher.strerror(errno())); + } + } + + @Override + public String getMessage() { + return errorString(); + } + + /** + * Map well known errors to specific exceptions where possible; otherwise + * return more general FileSystemException. + */ + private IOException translateToIOException(String file, String other) { + // created with message rather than errno + if (msg != null) + return new IOException(msg); + + // handle specific cases + if (errno() == UnixConstants.EACCES) + return new AccessDeniedException(file, other, null); + if (errno() == UnixConstants.ENOENT) + return new NoSuchFileException(file, other, null); + if (errno() == UnixConstants.EEXIST) + return new FileAlreadyExistsException(file, other, null); + + // fallback to the more general exception + return new FileSystemException(file, other, errorString()); + } + + void rethrowAsIOException(String file) throws IOException { + IOException x = translateToIOException(file, null); + throw x; + } + + void rethrowAsIOException(UnixPath file, UnixPath other) throws IOException { + String a = (file == null) ? null : file.getPathForExecptionMessage(); + String b = (other == null) ? null : other.getPathForExecptionMessage(); + IOException x = translateToIOException(a, b); + throw x; + } + + void rethrowAsIOException(UnixPath file) throws IOException { + rethrowAsIOException(file, null); + } + + IOException asIOException(UnixPath file) { + return translateToIOException(file.getPathForExecptionMessage(), null); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java new file mode 100644 index 00000000000..7bbf925b734 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java @@ -0,0 +1,392 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.io.IOException; + +import static sun.nio.fs.UnixNativeDispatcher.*; + +class UnixFileAttributeViews { + + static class Basic extends AbstractBasicFileAttributeView { + protected final UnixPath file; + protected final boolean followLinks; + + Basic(UnixPath file, boolean followLinks) { + this.file = file; + this.followLinks = followLinks; + } + + @Override + public BasicFileAttributes readAttributes() throws IOException { + file.checkRead(); + try { + UnixFileAttributes attrs = + UnixFileAttributes.get(file, followLinks); + return attrs.asBasicFileAttributes(); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } + } + @Override + public void setTimes(Long lastModifiedTime, + Long lastAccessTime, + Long createTime, + TimeUnit unit) throws IOException + { + // null => don't change + if (lastModifiedTime == null && lastAccessTime == null) { + // no effect + return; + } + + file.checkWrite(); + + int fd = file.openForAttributeAccess(followLinks); + try { + UnixFileAttributes attrs = null; + + // if not changing both attributes then need existing attributes + if (lastModifiedTime == null || lastAccessTime == null) { + try { + attrs = UnixFileAttributes.get(fd); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + } + + // modified time = existing, now, or new value + long modTime; + if (lastModifiedTime == null) { + modTime = attrs.lastModifiedTime(); + } else { + if (lastModifiedTime >= 0L) { + modTime = TimeUnit.MILLISECONDS.convert(lastModifiedTime, unit); + } else { + if (lastModifiedTime != -1L) + throw new IllegalArgumentException(); + modTime = System.currentTimeMillis(); + } + } + + // access time = existing, now, or new value + long accTime; + if (lastAccessTime == null) { + accTime = attrs.lastAccessTime(); + } else { + if (lastAccessTime >= 0L) { + accTime = TimeUnit.MILLISECONDS.convert(lastAccessTime, unit); + } else { + if (lastAccessTime != -1L) + throw new IllegalArgumentException(); + accTime = System.currentTimeMillis(); + } + } + + try { + futimes(fd, accTime, modTime); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + } finally { + close(fd); + } + } + } + + private static class Posix extends Basic implements PosixFileAttributeView { + private static final String PERMISSIONS_NAME = "permissions"; + private static final String OWNER_NAME = "owner"; + private static final String GROUP_NAME = "group"; + + Posix(UnixPath file, boolean followLinks) { + super(file, followLinks); + } + + final void checkReadExtended() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + file.checkRead(); + sm.checkPermission(new RuntimePermission("accessUserInformation")); + } + } + + final void checkWriteExtended() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + file.checkWrite(); + sm.checkPermission(new RuntimePermission("accessUserInformation")); + } + } + + @Override + public String name() { + return "posix"; + } + + @Override + public Object getAttribute(String attribute) throws IOException { + if (attribute.equals(PERMISSIONS_NAME)) + return readAttributes().permissions(); + if (attribute.equals(OWNER_NAME)) + return readAttributes().owner(); + if (attribute.equals(GROUP_NAME)) + return readAttributes().group(); + return super.getAttribute(attribute); + } + + @Override + @SuppressWarnings("unchecked") + public void setAttribute(String attribute, Object value) + throws IOException + { + if (attribute.equals(PERMISSIONS_NAME)) { + setPermissions((Set<PosixFilePermission>)value); + return; + } + if (attribute.equals(OWNER_NAME)) { + setOwner((UserPrincipal)value); + return; + } + if (attribute.equals(GROUP_NAME)) { + setGroup((GroupPrincipal)value); + return; + } + super.setAttribute(attribute, value); + } + + /** + * Invoked by readAttributes or sub-classes to add all matching posix + * attributes to the builder + */ + final void addPosixAttributesToBuilder(PosixFileAttributes attrs, + AttributesBuilder builder) + { + if (builder.match(PERMISSIONS_NAME)) + builder.add(PERMISSIONS_NAME, attrs.permissions()); + if (builder.match(OWNER_NAME)) + builder.add(OWNER_NAME, attrs.owner()); + if (builder.match(GROUP_NAME)) + builder.add(GROUP_NAME, attrs.group()); + } + + @Override + public Map<String,?> readAttributes(String first, String[] rest) + throws IOException + { + AttributesBuilder builder = AttributesBuilder.create(first, rest); + PosixFileAttributes attrs = readAttributes(); + addBasicAttributesToBuilder(attrs, builder); + addPosixAttributesToBuilder(attrs, builder); + return builder.unmodifiableMap(); + } + + @Override + public UnixFileAttributes readAttributes() throws IOException { + checkReadExtended(); + try { + return UnixFileAttributes.get(file, followLinks); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } + } + + // chmod + final void setMode(int mode) throws IOException { + checkWriteExtended(); + try { + if (followLinks) { + chmod(file, mode); + } else { + int fd = file.openForAttributeAccess(false); + try { + fchmod(fd, mode); + } finally { + close(fd); + } + } + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + } + + // chown + final void setOwners(int uid, int gid) throws IOException { + checkWriteExtended(); + try { + if (followLinks) { + chown(file, uid, gid); + } else { + lchown(file, uid, gid); + } + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + } + + @Override + public void setPermissions(Set<PosixFilePermission> perms) + throws IOException + { + setMode(UnixFileModeAttribute.toUnixMode(perms)); + } + + @Override + public void setOwner(UserPrincipal owner) + throws IOException + { + if (owner == null) + throw new NullPointerException("'owner' is null"); + if (!(owner instanceof UnixUserPrincipals.User)) + throw new ProviderMismatchException(); + if (owner instanceof UnixUserPrincipals.Group) + throw new IOException("'owner' parameter can't be a group"); + int uid = ((UnixUserPrincipals.User)owner).uid(); + setOwners(uid, -1); + } + + @Override + public UserPrincipal getOwner() throws IOException { + return readAttributes().owner(); + } + + @Override + public void setGroup(GroupPrincipal group) + throws IOException + { + if (group == null) + throw new NullPointerException("'owner' is null"); + if (!(group instanceof UnixUserPrincipals.Group)) + throw new ProviderMismatchException(); + int gid = ((UnixUserPrincipals.Group)group).gid(); + setOwners(-1, gid); + } + } + + private static class Unix extends Posix { + private static final String MODE_NAME = "mode"; + private static final String INO_NAME = "ino"; + private static final String DEV_NAME = "dev"; + private static final String RDEV_NAME = "rdev"; + private static final String UID_NAME = "uid"; + private static final String GID_NAME = "gid"; + private static final String CTIME_NAME = "ctime"; + + Unix(UnixPath file, boolean followLinks) { + super(file, followLinks); + } + + @Override + public String name() { + return "unix"; + } + + @Override + public Object getAttribute(String attribute) throws IOException { + if (attribute.equals(MODE_NAME)) + return readAttributes().mode(); + if (attribute.equals(INO_NAME)) + return readAttributes().ino(); + if (attribute.equals(DEV_NAME)) + return readAttributes().dev(); + if (attribute.equals(RDEV_NAME)) + return readAttributes().rdev(); + if (attribute.equals(UID_NAME)) + return readAttributes().uid(); + if (attribute.equals(GID_NAME)) + return readAttributes().gid(); + if (attribute.equals(CTIME_NAME)) + return readAttributes().ctime(); + return super.getAttribute(attribute); + } + + @Override + public void setAttribute(String attribute, Object value) + throws IOException + { + if (attribute.equals(MODE_NAME)) { + setMode((Integer)value); + return; + } + if (attribute.equals(UID_NAME)) { + setOwners((Integer)value, -1); + return; + } + if (attribute.equals(GID_NAME)) { + setOwners(-1, (Integer)value); + return; + } + super.setAttribute(attribute, value); + } + + @Override + public Map<String,?> readAttributes(String first, String[] rest) + throws IOException + { + AttributesBuilder builder = AttributesBuilder.create(first, rest); + UnixFileAttributes attrs = readAttributes(); + addBasicAttributesToBuilder(attrs, builder); + addPosixAttributesToBuilder(attrs, builder); + if (builder.match(MODE_NAME)) + builder.add(MODE_NAME, attrs.mode()); + if (builder.match(INO_NAME)) + builder.add(INO_NAME, attrs.ino()); + if (builder.match(DEV_NAME)) + builder.add(DEV_NAME, attrs.dev()); + if (builder.match(RDEV_NAME)) + builder.add(RDEV_NAME, attrs.rdev()); + if (builder.match(UID_NAME)) + builder.add(UID_NAME, attrs.uid()); + if (builder.match(GID_NAME)) + builder.add(GID_NAME, attrs.gid()); + if (builder.match(CTIME_NAME)) + builder.add(CTIME_NAME, attrs.ctime()); + return builder.unmodifiableMap(); + } + } + + static BasicFileAttributeView createBasicView(UnixPath file, boolean followLinks) { + return new Basic(file, followLinks); + } + + static PosixFileAttributeView createPosixView(UnixPath file, boolean followLinks) { + return new Posix(file, followLinks); + } + + static PosixFileAttributeView createUnixView(UnixPath file, boolean followLinks) { + return new Unix(file, followLinks); + } + + static FileOwnerAttributeView createOwnerView(UnixPath file, boolean followLinks) { + return new FileOwnerAttributeViewImpl(createPosixView(file, followLinks)); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java new file mode 100644 index 00000000000..c1882d7536b --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java @@ -0,0 +1,307 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.util.concurrent.TimeUnit; +import java.util.Set; +import java.util.HashSet; + +/** + * Unix implementation of PosixFileAttributes. + */ + +class UnixFileAttributes + implements PosixFileAttributes +{ + private int st_mode; + private long st_ino; + private long st_dev; + private long st_rdev; + private int st_nlink; + private int st_uid; + private int st_gid; + private long st_size; + private long st_atime; + private long st_mtime; + private long st_ctime; + + // created lazily + private volatile UserPrincipal owner; + private volatile GroupPrincipal group; + private volatile UnixFileKey key; + + private UnixFileAttributes() { + } + + // get the UnixFileAttributes for a given file + static UnixFileAttributes get(UnixPath path, boolean followLinks) + throws UnixException + { + UnixFileAttributes attrs = new UnixFileAttributes(); + if (followLinks) { + UnixNativeDispatcher.stat(path, attrs); + } else { + UnixNativeDispatcher.lstat(path, attrs); + } + return attrs; + } + + // get the UnixFileAttributes for an open file + static UnixFileAttributes get(int fd) throws UnixException { + UnixFileAttributes attrs = new UnixFileAttributes(); + UnixNativeDispatcher.fstat(fd, attrs); + return attrs; + } + + // get the UnixFileAttributes for a given file, relative to open directory + static UnixFileAttributes get(int dfd, UnixPath path, boolean followLinks) + throws UnixException + { + UnixFileAttributes attrs = new UnixFileAttributes(); + int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW; + UnixNativeDispatcher.fstatat(dfd, path.asByteArray(), flag, attrs); + return attrs; + } + + // package-private + boolean isSameFile(UnixFileAttributes attrs) { + return ((st_ino == attrs.st_ino) && (st_dev == attrs.st_dev)); + } + + // package-private + int mode() { return st_mode; } + long ino() { return st_ino; } + long dev() { return st_dev; } + long rdev() { return st_rdev; } + int uid() { return st_uid; } + int gid() { return st_gid; } + long ctime() { return st_ctime; } + + boolean isDevice() { + int type = st_mode & UnixConstants.S_IFMT; + return (type == UnixConstants.S_IFCHR || + type == UnixConstants.S_IFBLK || + type == UnixConstants.S_IFIFO); + } + + @Override + public long lastModifiedTime() { + return st_mtime; + } + + @Override + public long lastAccessTime() { + return st_atime; + } + + @Override + public long creationTime() { + return -1L; + } + + @Override + public TimeUnit resolution() { + return TimeUnit.MILLISECONDS; + } + + @Override + public boolean isRegularFile() { + return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG); + } + + @Override + public boolean isDirectory() { + return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR); + } + + @Override + public boolean isSymbolicLink() { + return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFLNK); + } + + @Override + public boolean isOther() { + int type = st_mode & UnixConstants.S_IFMT; + return (type != UnixConstants.S_IFREG && + type != UnixConstants.S_IFDIR && + type != UnixConstants.S_IFLNK); + } + + @Override + public long size() { + return st_size; + } + + @Override + public int linkCount() { + return st_nlink; + } + + @Override + public UnixFileKey fileKey() { + if (key == null) { + synchronized (this) { + if (key == null) { + key = new UnixFileKey(st_dev, st_ino); + } + } + } + return key; + } + + @Override + public UserPrincipal owner() { + if (owner == null) { + synchronized (this) { + if (owner == null) { + owner = UnixUserPrincipals.fromUid(st_uid); + } + } + } + return owner; + } + + @Override + public GroupPrincipal group() { + if (group == null) { + synchronized (this) { + if (group == null) { + group = UnixUserPrincipals.fromGid(st_gid); + } + } + } + return group; + } + + @Override + public Set<PosixFilePermission> permissions() { + int bits = (st_mode & UnixConstants.S_IAMB); + HashSet<PosixFilePermission> perms = new HashSet<PosixFilePermission>(); + + if ((bits & UnixConstants.S_IRUSR) > 0) + perms.add(PosixFilePermission.OWNER_READ); + if ((bits & UnixConstants.S_IWUSR) > 0) + perms.add(PosixFilePermission.OWNER_WRITE); + if ((bits & UnixConstants.S_IXUSR) > 0) + perms.add(PosixFilePermission.OWNER_EXECUTE); + + if ((bits & UnixConstants.S_IRGRP) > 0) + perms.add(PosixFilePermission.GROUP_READ); + if ((bits & UnixConstants.S_IWGRP) > 0) + perms.add(PosixFilePermission.GROUP_WRITE); + if ((bits & UnixConstants.S_IXGRP) > 0) + perms.add(PosixFilePermission.GROUP_EXECUTE); + + if ((bits & UnixConstants.S_IROTH) > 0) + perms.add(PosixFilePermission.OTHERS_READ); + if ((bits & UnixConstants.S_IWOTH) > 0) + perms.add(PosixFilePermission.OTHERS_WRITE); + if ((bits & UnixConstants.S_IXOTH) > 0) + perms.add(PosixFilePermission.OTHERS_EXECUTE); + + return perms; + } + + // wrap this object with BasicFileAttributes object to prevent leaking of + // user information + BasicFileAttributes asBasicFileAttributes() { + return UnixAsBasicFileAttributes.wrap(this); + } + + // unwrap BasicFileAttributes to get the underlying UnixFileAttributes + // object. Returns null is not wrapped. + static UnixFileAttributes toUnixFileAttributes(BasicFileAttributes attrs) { + if (attrs instanceof UnixFileAttributes) + return (UnixFileAttributes)attrs; + if (attrs instanceof UnixAsBasicFileAttributes) { + return ((UnixAsBasicFileAttributes)attrs).unwrap(); + } + return null; + } + + // wrap a UnixFileAttributes object as a BasicFileAttributes + private static class UnixAsBasicFileAttributes implements BasicFileAttributes { + private final UnixFileAttributes attrs; + + private UnixAsBasicFileAttributes(UnixFileAttributes attrs) { + this.attrs = attrs; + } + + static UnixAsBasicFileAttributes wrap(UnixFileAttributes attrs) { + return new UnixAsBasicFileAttributes(attrs); + } + + UnixFileAttributes unwrap() { + return attrs; + } + + @Override + public long lastModifiedTime() { + return attrs.lastModifiedTime(); + } + @Override + public long lastAccessTime() { + return attrs.lastAccessTime(); + } + @Override + public long creationTime() { + return attrs.creationTime(); + } + @Override + public TimeUnit resolution() { + return attrs.resolution(); + } + @Override + public boolean isRegularFile() { + return attrs.isRegularFile(); + } + @Override + public boolean isDirectory() { + return attrs.isDirectory(); + } + @Override + public boolean isSymbolicLink() { + return attrs.isSymbolicLink(); + } + @Override + public boolean isOther() { + return attrs.isOther(); + } + @Override + public long size() { + return attrs.size(); + } + @Override + public int linkCount() { + return attrs.linkCount(); + } + @Override + public Object fileKey() { + return attrs.fileKey(); + } + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileKey.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileKey.java new file mode 100644 index 00000000000..4ab3aec6c30 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileKey.java @@ -0,0 +1,56 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +/** + * Container for device/inode to uniquely identify file. + */ + +class UnixFileKey { + private final long st_dev; + private final long st_ino; + + UnixFileKey(long st_dev, long st_ino) { + this.st_dev = st_dev; + this.st_ino = st_ino; + } + + @Override + public int hashCode() { + return (int)(st_dev ^ (st_dev >>> 32)) + + (int)(st_ino ^ (st_ino >>> 32)); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (!(obj instanceof UnixFileKey)) + return false; + UnixFileKey other = (UnixFileKey)obj; + return (this.st_dev == other.st_dev) && (this.st_ino == other.st_ino); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileModeAttribute.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileModeAttribute.java new file mode 100644 index 00000000000..67ea59e943d --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileModeAttribute.java @@ -0,0 +1,84 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.util.*; + +class UnixFileModeAttribute { + static final int ALL_PERMISSIONS = + UnixConstants.S_IRUSR | UnixConstants.S_IWUSR | UnixConstants.S_IXUSR | + UnixConstants.S_IRGRP | UnixConstants.S_IWGRP | UnixConstants.S_IXGRP | + UnixConstants.S_IROTH | UnixConstants.S_IWOTH | UnixConstants. S_IXOTH; + + static final int ALL_READWRITE = + UnixConstants.S_IRUSR | UnixConstants.S_IWUSR | + UnixConstants.S_IRGRP | UnixConstants.S_IWGRP | + UnixConstants.S_IROTH | UnixConstants.S_IWOTH; + + static final int TEMPFILE_PERMISSIONS = + UnixConstants.S_IRUSR | UnixConstants.S_IWUSR | UnixConstants.S_IXUSR; + + private Set<PosixFilePermission> perms; + + UnixFileModeAttribute() { + perms = Collections.emptySet(); + } + + static int toUnixMode(Set<PosixFilePermission> perms) { + int mode = 0; + for (PosixFilePermission perm: perms) { + if (perm == null) + throw new NullPointerException(); + switch (perm) { + case OWNER_READ : mode |= UnixConstants.S_IRUSR; break; + case OWNER_WRITE : mode |= UnixConstants.S_IWUSR; break; + case OWNER_EXECUTE : mode |= UnixConstants.S_IXUSR; break; + case GROUP_READ : mode |= UnixConstants.S_IRGRP; break; + case GROUP_WRITE : mode |= UnixConstants.S_IWGRP; break; + case GROUP_EXECUTE : mode |= UnixConstants.S_IXGRP; break; + case OTHERS_READ : mode |= UnixConstants.S_IROTH; break; + case OTHERS_WRITE : mode |= UnixConstants.S_IWOTH; break; + case OTHERS_EXECUTE : mode |= UnixConstants.S_IXOTH; break; + } + } + return mode; + } + + @SuppressWarnings("unchecked") + static int toUnixMode(int defaultMode, FileAttribute<?>... attrs) { + int mode = defaultMode; + for (FileAttribute<?> attr: attrs) { + String name = attr.name(); + if (!name.equals("posix:permissions") && !name.equals("unix:permissions")) { + throw new UnsupportedOperationException("'" + attr.name() + + "' not supported as initial attribute"); + } + mode = toUnixMode((Set<PosixFilePermission>)attr.value()); + } + return mode; + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java new file mode 100644 index 00000000000..483a4ea4825 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java @@ -0,0 +1,290 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.channels.*; +import java.util.*; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Base implementation of FileStore for Unix/like implementations. + */ + +abstract class UnixFileStore + extends FileStore +{ + // original path of file that identified file system + private final UnixPath file; + + // device ID + private final long dev; + + // entry in the mount tab + private final UnixMountEntry entry; + + // return the device ID where the given file resides + private static long devFor(UnixPath file) throws IOException { + try { + return UnixFileAttributes.get(file, true).dev(); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return 0L; // keep compiler happy + } + } + + UnixFileStore(UnixPath file) throws IOException { + this.file = file; + this.dev = devFor(file); + this.entry = findMountEntry(); + } + + UnixFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException { + this.file = new UnixPath(fs, entry.dir()); + this.dev = (entry.dev() == 0L) ? devFor(this.file) : entry.dev(); + this.entry = entry; + } + + /** + * Find the mount entry for the file store + */ + abstract UnixMountEntry findMountEntry() throws IOException; + + /** + * Returns true if this file store represents a loopback file system that + * will have the same device ID as undelrying file system. + */ + abstract boolean isLoopback(); + + UnixPath file() { + return file; + } + + long dev() { + return dev; + } + + UnixMountEntry entry() { + return entry; + } + + @Override + public String name() { + return entry.name(); + } + + @Override + public String type() { + return entry.fstype(); + } + + @Override + public boolean isReadOnly() { + return entry.isReadOnly(); + } + + @Override + @SuppressWarnings("unchecked") + public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> viewType) + { + if (viewType == FileStoreSpaceAttributeView.class) + return (V) new UnixFileStoreSpaceAttributeView(this); + return (V) null; + } + + @Override + public FileStoreAttributeView getFileStoreAttributeView(String name) { + if (name.equals("space")) + return new UnixFileStoreSpaceAttributeView(this); + return null; + } + + @Override + public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) { + if (type == BasicFileAttributeView.class) + return true; + if (type == PosixFileAttributeView.class || + type == FileOwnerAttributeView.class) + { + // lookup fstypes.properties + FeatureStatus status = checkIfFeaturePresent("posix"); + if (status == FeatureStatus.NOT_PRESENT) + return false; + return true; + } + return false; + } + + @Override + public boolean supportsFileAttributeView(String name) { + if (name.equals("basic") || name.equals("unix")) + return true; + if (name.equals("posix")) + return supportsFileAttributeView(PosixFileAttributeView.class); + if (name.equals("owner")) + return supportsFileAttributeView(FileOwnerAttributeView.class); + return false; + } + + @Override + public boolean equals(Object ob) { + if (ob == this) + return true; + if (!(ob instanceof UnixFileStore)) + return false; + UnixFileStore other = (UnixFileStore)ob; + if (dev != other.dev) + return false; + // deviceIDs are equal but they may not be equal if one or both of + // them is a loopback file system + boolean thisIsLoopback = isLoopback(); + if (thisIsLoopback != other.isLoopback()) + return false; // one, but not both, are lofs + if (!thisIsLoopback) + return true; // neither is lofs + // both are lofs so compare mount points + return Arrays.equals(this.entry.dir(), other.entry.dir()); + } + + @Override + public int hashCode() { + return (int)(dev ^ (dev >>> 32)); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(new String(entry.dir())); + sb.append(" ("); + sb.append(entry.name()); + sb.append(")"); + return sb.toString(); + } + + private static class UnixFileStoreSpaceAttributeView + extends AbstractFileStoreSpaceAttributeView + { + private final UnixFileStore fs; + + UnixFileStoreSpaceAttributeView(UnixFileStore fs) { + this.fs = fs; + } + + @Override + public FileStoreSpaceAttributes readAttributes() + throws IOException + { + UnixPath file = fs.file(); + final UnixFileStoreAttributes attrs; + try { + attrs = UnixFileStoreAttributes.get(file); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compile happy + } + + return new FileStoreSpaceAttributes() { + @Override + public long totalSpace() { + return attrs.blockSize() * attrs.totalBlocks(); + } + @Override + public long usableSpace() { + return attrs.blockSize() * attrs.availableBlocks(); + } + @Override + public long unallocatedSpace() { + return attrs.blockSize() * attrs.freeBlocks(); + } + }; + } + } + + // -- fstypes.properties -- + + private static final Object loadLock = new Object(); + private static volatile Properties props; + + enum FeatureStatus { + PRESENT, + NOT_PRESENT, + UNKNOWN; + } + + /** + * Returns status to indicate if file system supports a given feature + */ + FeatureStatus checkIfFeaturePresent(String feature) { + if (props == null) { + synchronized (loadLock) { + if (props == null) { + props = AccessController.doPrivileged( + new PrivilegedAction<Properties>() { + @Override + public Properties run() { + return loadProperties(); + }}); + } + } + } + + String value = props.getProperty(type()); + if (value != null) { + String[] values = value.split("\\s"); + for (String s: values) { + s = s.trim().toLowerCase(); + if (s.equals(feature)) { + return FeatureStatus.PRESENT; + } + if (s.startsWith("no")) { + s = s.substring(2); + if (s.equals(feature)) { + return FeatureStatus.NOT_PRESENT; + } + } + } + } + return FeatureStatus.UNKNOWN; + } + + private static Properties loadProperties() { + Properties result = new Properties(); + String fstypes = System.getProperty("java.home") + "/lib/fstypes.properties"; + FileRef file = Paths.get(fstypes); + try { + ReadableByteChannel rbc = file.newByteChannel(); + try { + result.load(Channels.newReader(rbc, "UTF-8")); + } finally { + rbc.close(); + } + } catch (IOException x) { + } + return result; + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java new file mode 100644 index 00000000000..f2cbd17cc1a --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java @@ -0,0 +1,59 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +class UnixFileStoreAttributes { + private long f_frsize; // block size + private long f_blocks; // total + private long f_bfree; // free + private long f_bavail; // usable + + private UnixFileStoreAttributes() { + } + + static UnixFileStoreAttributes get(UnixPath path) throws UnixException { + UnixFileStoreAttributes attrs = new UnixFileStoreAttributes(); + UnixNativeDispatcher.statvfs(path, attrs); + return attrs; + } + + long blockSize() { + return f_frsize; + } + + long totalBlocks() { + return f_blocks; + } + + long freeBlocks() { + return f_bfree; + } + + long availableBlocks() { + return f_bavail; + } + +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java new file mode 100644 index 00000000000..6e46b2647d9 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java @@ -0,0 +1,380 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.*; +import java.io.IOException; +import java.util.*; +import java.util.regex.Pattern; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; + +/** + * Base implementation of FileSystem for Unix-like implementations. + */ + +abstract class UnixFileSystem + extends FileSystem +{ + private final UnixFileSystemProvider provider; + private final byte[] defaultDirectory; + private final boolean needToResolveAgainstDefaultDirectory; + private final UnixPath rootDirectory; + + // package-private + UnixFileSystem(UnixFileSystemProvider provider, String dir) { + this.provider = provider; + this.defaultDirectory = UnixPath.normalizeAndCheck(dir).getBytes(); + if (this.defaultDirectory[0] != '/') { + throw new RuntimeException("default directory must be absolute"); + } + + // if process-wide chdir is allowed or default directory is not the + // process working directory then paths must be resolved against the + // default directory. + String propValue = AccessController.doPrivileged( + new GetPropertyAction("sun.nio.fs.chdirAllowed", "false")); + boolean chdirAllowed = (propValue.length() == 0) ? + true : Boolean.valueOf(propValue); + if (chdirAllowed) { + this.needToResolveAgainstDefaultDirectory = true; + } else { + byte[] cwd = UnixNativeDispatcher.getcwd(); + boolean defaultIsCwd = (cwd.length == defaultDirectory.length); + if (defaultIsCwd) { + for (int i=0; i<cwd.length; i++) { + if (cwd[i] != defaultDirectory[i]) { + defaultIsCwd = false; + break; + } + } + } + this.needToResolveAgainstDefaultDirectory = !defaultIsCwd; + } + + // the root directory + this.rootDirectory = new UnixPath(this, "/"); + } + + // package-private + byte[] defaultDirectory() { + return defaultDirectory; + } + + boolean needToResolveAgainstDefaultDirectory() { + return needToResolveAgainstDefaultDirectory; + } + + UnixPath rootDirectory() { + return rootDirectory; + } + + boolean isSolaris() { + return false; + } + + @Override + public final FileSystemProvider provider() { + return provider; + } + + @Override + public final String getSeparator() { + return "/"; + } + + @Override + public final boolean isOpen() { + return true; + } + + @Override + public final boolean isReadOnly() { + return false; + } + + @Override + public final void close() throws IOException { + throw new UnsupportedOperationException(); + } + + /** + * Copies non-POSIX attributes from the source to target file. + * + * Copying a file preserving attributes, or moving a file, will preserve + * the file owner/group/permissions/timestamps but it does not preserve + * other non-POSIX attributes. This method is invoked by the + * copy or move operation to preserve these attributes. It should copy + * extended attributes, ACLs, or other attributes. + * + * @param sfd + * Open file descriptor to source file + * @param tfd + * Open file descriptor to target file + */ + abstract void copyNonPosixAttributes(int sfd, int tfd); + + /** + * Tells if directory relative system calls (openat, etc.) are available + * on this operating system. + */ + abstract boolean supportsSecureDirectoryStreams(); + + /** + * Unix systems only have a single root directory (/) + */ + @Override + public final Iterable<Path> getRootDirectories() { + final List<Path> allowedList = + Collections.unmodifiableList(Arrays.asList((Path)rootDirectory)); + return new Iterable<Path>() { + public Iterator<Path> iterator() { + try { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkRead(rootDirectory.toString()); + return allowedList.iterator(); + } catch (SecurityException x) { + List<Path> disallowed = Collections.emptyList(); + return disallowed.iterator(); + } + } + }; + } + + /** + * Returns object to iterate over entries in mounttab or equivalent + */ + abstract Iterable<UnixMountEntry> getMountEntries(); + + /** + * Returns a FileStore to represent the file system where the given file + * reside. + */ + abstract FileStore getFileStore(UnixPath path) throws IOException; + + /** + * Returns a FileStore to represent the file system for the given mount + * mount. + */ + abstract FileStore getFileStore(UnixMountEntry entry) throws IOException; + + /** + * Iterator returned by getFileStores method. + */ + private class FileStoreIterator implements Iterator<FileStore> { + private final Iterator<UnixMountEntry> entries; + private FileStore next; + + FileStoreIterator() { + this.entries = getMountEntries().iterator(); + } + + private FileStore readNext() { + assert Thread.holdsLock(this); + for (;;) { + if (!entries.hasNext()) + return null; + UnixMountEntry entry = entries.next(); + + // skip entries with the "ignore" option + if (entry.isIgnored()) + continue; + + // check permission to read mount point + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + sm.checkRead(new String(entry.dir())); + } catch (SecurityException x) { + continue; + } + } + try { + return getFileStore(entry); + } catch (IOException ignore) { + // ignore as per spec + } + } + } + + @Override + public synchronized boolean hasNext() { + if (next != null) + return true; + next = readNext(); + return next != null; + } + + @Override + public synchronized FileStore next() { + if (next == null) + next = readNext(); + if (next == null) { + throw new NoSuchElementException(); + } else { + FileStore result = next; + next = null; + return result; + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + @Override + public final Iterable<FileStore> getFileStores() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); + } catch (SecurityException se) { + return Collections.emptyList(); + } + } + return new Iterable<FileStore>() { + public Iterator<FileStore> iterator() { + return new FileStoreIterator(); + } + }; + } + + @Override + public final UnixPath getPath(String path) { + return new UnixPath(this, path); + } + + @Override + public PathMatcher getPathMatcher(String syntaxAndInput) { + int pos = syntaxAndInput.indexOf(':'); + if (pos <= 0 || pos == syntaxAndInput.length()) + throw new IllegalArgumentException(); + String syntax = syntaxAndInput.substring(0, pos); + String input = syntaxAndInput.substring(pos+1); + + String expr; + if (syntax.equals(GLOB_SYNTAX)) { + expr = Globs.toUnixRegexPattern(input); + } else { + if (syntax.equals(REGEX_SYNTAX)) { + expr = input; + } else { + throw new UnsupportedOperationException("Syntax '" + syntax + + "' not recognized"); + } + } + + // return matcher + final Pattern pattern = Pattern.compile(expr); + return new PathMatcher() { + @Override + public boolean matches(Path path) { + return pattern.matcher(path.toString()).matches(); + } + }; + } + private static final String GLOB_SYNTAX = "glob"; + private static final String REGEX_SYNTAX = "regex"; + + protected boolean followLinks(LinkOption... options) { + boolean followLinks = true; + for (LinkOption option: options) { + if (option == LinkOption.NOFOLLOW_LINKS) { + followLinks = false; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new AssertionError("Should not get here"); + } + return followLinks; + } + + @SuppressWarnings("unchecked") + protected <V extends FileAttributeView> V newFileAttributeView(Class<V> view, + UnixPath file, + LinkOption... options) + { + if (view == null) + throw new NullPointerException(); + boolean followLinks = followLinks(options); + Class<?> c = view; + if (c == BasicFileAttributeView.class) + return (V) UnixFileAttributeViews.createBasicView(file, followLinks); + if (c == PosixFileAttributeView.class) + return (V) UnixFileAttributeViews.createPosixView(file, followLinks); + if (c == FileOwnerAttributeView.class) + return (V) UnixFileAttributeViews.createOwnerView(file, followLinks); + return (V) null; + } + + static List<String> standardFileAttributeViews() { + return Arrays.asList("basic", "posix", "unix", "owner"); + } + + protected FileAttributeView newFileAttributeView(String name, + UnixPath file, + LinkOption... options) + { + boolean followLinks = followLinks(options); + if (name.equals("basic")) + return UnixFileAttributeViews.createBasicView(file, followLinks); + if (name.equals("posix")) + return UnixFileAttributeViews.createPosixView(file, followLinks); + if (name.equals("unix")) + return UnixFileAttributeViews.createUnixView(file, followLinks); + if (name.equals("owner")) + return UnixFileAttributeViews.createOwnerView(file, followLinks); + return null; + } + + @Override + public final UserPrincipalLookupService getUserPrincipalLookupService() { + return theLookupService; + } + + private static final UserPrincipalLookupService theLookupService = + new UserPrincipalLookupService() { + @Override + public UserPrincipal lookupPrincipalByName(String name) + throws IOException + { + return UnixUserPrincipals.lookupUser(name); + } + + @Override + public GroupPrincipal lookupPrincipalByGroupName(String group) + throws IOException + { + return UnixUserPrincipals.lookupGroup(group); + } + }; +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java new file mode 100644 index 00000000000..878fe25c5e4 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java @@ -0,0 +1,139 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.FileSystemProvider; +import java.nio.channels.*; +import java.net.URI; +import java.util.concurrent.ExecutorService; +import java.io.IOException; +import java.util.*; + +import sun.nio.ch.ThreadPool; + +/** + * Base implementation of FileSystemProvider + */ + +public abstract class UnixFileSystemProvider + extends FileSystemProvider +{ + private static final String USER_DIR = "user.dir"; + private final UnixFileSystem theFileSystem; + + public UnixFileSystemProvider() { + String userDir = System.getProperty(USER_DIR); + theFileSystem = newFileSystem(userDir); + } + + /** + * Constructs a new file system using the given default directory. + */ + abstract UnixFileSystem newFileSystem(String dir); + + @Override + public final String getScheme() { + return "file"; + } + + private void checkUri(URI uri) { + if (!uri.getScheme().equalsIgnoreCase(getScheme())) + throw new IllegalArgumentException("URI does not match this provider"); + if (uri.getAuthority() != null) + throw new IllegalArgumentException("Authority component present"); + if (uri.getPath() == null) + throw new IllegalArgumentException("Path component is undefined"); + if (!uri.getPath().equals("/")) + throw new IllegalArgumentException("Path component should be '/'"); + if (uri.getQuery() != null) + throw new IllegalArgumentException("Query component present"); + if (uri.getFragment() != null) + throw new IllegalArgumentException("Fragment component present"); + } + + @Override + public final FileSystem newFileSystem(URI uri, Map<String,?> env) { + checkUri(uri); + throw new FileSystemAlreadyExistsException(); + } + + @Override + public final FileSystem getFileSystem(URI uri) { + checkUri(uri); + return theFileSystem; + } + + @Override + public Path getPath(URI uri) { + return UnixUriUtils.fromUri(theFileSystem, uri); + } + + private UnixPath checkPath(Path obj) { + if (obj == null) + throw new NullPointerException(); + if (!(obj instanceof UnixPath)) + throw new ProviderMismatchException(); + return (UnixPath)obj; + } + + @Override + public final FileChannel newFileChannel(Path obj, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + UnixPath file = checkPath(obj); + int mode = UnixFileModeAttribute + .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); + try { + return UnixChannelFactory.newFileChannel(file, options, mode); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; + } + } + + @Override + public final AsynchronousFileChannel newAsynchronousFileChannel(Path obj, + Set<? extends OpenOption> options, + ExecutorService executor, + FileAttribute<?>... attrs) throws IOException + { + UnixPath file = checkPath(obj); + int mode = UnixFileModeAttribute + .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); + ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0); + try { + return UnixChannelFactory + .newAsynchronousFileChannel(file, options, mode, pool); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; + } + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixMountEntry.java b/jdk/src/solaris/classes/sun/nio/fs/UnixMountEntry.java new file mode 100644 index 00000000000..c4769e7a7d8 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixMountEntry.java @@ -0,0 +1,85 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +/** + * Represents an entry in the mount table. + */ + +class UnixMountEntry { + private byte[] name; // file system name + private byte[] dir; // directory (mount point) + private byte[] fstype; // ufs, nfs, ... + private byte[] opts; // mount options + private long dev; // device ID + + private volatile String fstypeAsString; + private volatile String optionsAsString; + + UnixMountEntry() { + } + + String name() { + return new String(name); + } + + String fstype() { + if (fstypeAsString == null) + fstypeAsString = new String(fstype); + return fstypeAsString; + } + + byte[] dir() { + return dir; + } + + long dev() { + return dev; + } + + /** + * Tells whether the mount entry has the given option. + */ + boolean hasOption(String requested) { + if (optionsAsString == null) + optionsAsString = new String(opts); + for (String opt: optionsAsString.split("\\,", 0)) { + if (opt.equals(requested)) + return true; + } + return false; + } + + // generic option + boolean isIgnored() { + return hasOption("ignore"); + } + + // generic option + boolean isReadOnly() { + return hasOption("ro"); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java b/jdk/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java new file mode 100644 index 00000000000..29140e3ec31 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java @@ -0,0 +1,556 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Unix system and library calls. + */ + +class UnixNativeDispatcher { + protected UnixNativeDispatcher() { } + + // returns a NativeBuffer containing the given path + private static NativeBuffer copyToNativeBuffer(UnixPath path) { + byte[] cstr = path.getByteArrayForSysCalls(); + int size = cstr.length + 1; + NativeBuffer buffer = NativeBuffers.getNativeBufferFromCache(size); + if (buffer == null) { + buffer = NativeBuffers.allocNativeBuffer(size); + } else { + // buffer already contains the path + if (buffer.owner() == path) + return buffer; + } + NativeBuffers.copyCStringToNativeBuffer(cstr, buffer); + buffer.setOwner(path); + return buffer; + } + + /** + * char *getcwd(char *buf, size_t size); + */ + static native byte[] getcwd(); + + /** + * int dup(int filedes) + */ + static native int dup(int filedes) throws UnixException; + + /** + * int open(const char* path, int oflag, mode_t mode) + */ + static int open(UnixPath path, int flags, int mode) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + return open0(buffer.address(), flags, mode); + } finally { + buffer.release(); + } + } + private static native int open0(long pathAddress, int flags, int mode) + throws UnixException; + + /** + * int openat(int dfd, const char* path, int oflag, mode_t mode) + */ + static int openat(int dfd, byte[] path, int flags, int mode) throws UnixException { + NativeBuffer buffer = NativeBuffers.asNativeBuffer(path); + try { + return openat0(dfd, buffer.address(), flags, mode); + } finally { + buffer.release(); + } + } + private static native int openat0(int dfd, long pathAddress, int flags, int mode) + throws UnixException; + + /** + * close(int filedes) + */ + static native void close(int fd); + + /** + * FILE* fopen(const char *filename, const char* mode); + */ + static long fopen(UnixPath filename, String mode) throws UnixException { + NativeBuffer pathBuffer = copyToNativeBuffer(filename); + NativeBuffer modeBuffer = NativeBuffers.asNativeBuffer(mode.getBytes()); + try { + return fopen0(pathBuffer.address(), modeBuffer.address()); + } finally { + modeBuffer.release(); + pathBuffer.release(); + } + } + private static native long fopen0(long pathAddress, long modeAddress) + throws UnixException; + + /** + * fclose(FILE* stream) + */ + static native void fclose(long stream) throws UnixException; + + /** + * link(const char* existing, const char* new) + */ + static void link(UnixPath existing, UnixPath newfile) throws UnixException { + NativeBuffer existingBuffer = copyToNativeBuffer(existing); + NativeBuffer newBuffer = copyToNativeBuffer(newfile); + try { + link0(existingBuffer.address(), newBuffer.address()); + } finally { + newBuffer.release(); + existingBuffer.release(); + } + } + private static native void link0(long existingAddress, long newAddress) + throws UnixException; + + /** + * unlink(const char* path) + */ + static void unlink(UnixPath path) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + unlink0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native void unlink0(long pathAddress) throws UnixException; + + /** + * unlinkat(int dfd, const char* path, int flag) + */ + static void unlinkat(int dfd, byte[] path, int flag) throws UnixException { + NativeBuffer buffer = NativeBuffers.asNativeBuffer(path); + try { + unlinkat0(dfd, buffer.address(), flag); + } finally { + buffer.release(); + } + } + private static native void unlinkat0(int dfd, long pathAddress, int flag) + throws UnixException; + + /** + * mknod(const char* path, mode_t mode, dev_t dev) + */ + static void mknod(UnixPath path, int mode, long dev) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + mknod0(buffer.address(), mode, dev); + } finally { + buffer.release(); + } + } + private static native void mknod0(long pathAddress, int mode, long dev) + throws UnixException; + + /** + * rename(const char* old, const char* new) + */ + static void rename(UnixPath from, UnixPath to) throws UnixException { + NativeBuffer fromBuffer = copyToNativeBuffer(from); + NativeBuffer toBuffer = copyToNativeBuffer(to); + try { + rename0(fromBuffer.address(), toBuffer.address()); + } finally { + toBuffer.release(); + fromBuffer.release(); + } + } + private static native void rename0(long fromAddress, long toAddress) + throws UnixException; + + /** + * renameat(int fromfd, const char* old, int tofd, const char* new) + */ + static void renameat(int fromfd, byte[] from, int tofd, byte[] to) throws UnixException { + NativeBuffer fromBuffer = NativeBuffers.asNativeBuffer(from); + NativeBuffer toBuffer = NativeBuffers.asNativeBuffer(to); + try { + renameat0(fromfd, fromBuffer.address(), tofd, toBuffer.address()); + } finally { + toBuffer.release(); + fromBuffer.release(); + } + } + private static native void renameat0(int fromfd, long fromAddress, int tofd, long toAddress) + throws UnixException; + + /** + * mkdir(const char* path, mode_t mode) + */ + static void mkdir(UnixPath path, int mode) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + mkdir0(buffer.address(), mode); + } finally { + buffer.release(); + } + } + private static native void mkdir0(long pathAddress, int mode) throws UnixException; + + /** + * rmdir(const char* path) + */ + static void rmdir(UnixPath path) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + rmdir0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native void rmdir0(long pathAddress) throws UnixException; + + /** + * readlink(const char* path, char* buf, size_t bufsize) + * + * @return link target + */ + static byte[] readlink(UnixPath path) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + return readlink0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native byte[] readlink0(long pathAddress) throws UnixException; + + /** + * realpath(const char* path, char* resolved_name) + * + * @return resolved path + */ + static byte[] realpath(UnixPath path) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + return realpath0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native byte[] realpath0(long pathAddress) throws UnixException; + + /** + * symlink(const char* name1, const char* name2) + */ + static void symlink(byte[] name1, UnixPath name2) throws UnixException { + NativeBuffer targetBuffer = NativeBuffers.asNativeBuffer(name1); + NativeBuffer linkBuffer = copyToNativeBuffer(name2); + try { + symlink0(targetBuffer.address(), linkBuffer.address()); + } finally { + linkBuffer.release(); + targetBuffer.release(); + } + } + private static native void symlink0(long name1, long name2) + throws UnixException; + + /** + * stat(const char* path, struct stat* buf) + */ + static void stat(UnixPath path, UnixFileAttributes attrs) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + stat0(buffer.address(), attrs); + } finally { + buffer.release(); + } + } + private static native void stat0(long pathAddress, UnixFileAttributes attrs) + throws UnixException; + + /** + * lstat(const char* path, struct stat* buf) + */ + static void lstat(UnixPath path, UnixFileAttributes attrs) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + lstat0(buffer.address(), attrs); + } finally { + buffer.release(); + } + } + private static native void lstat0(long pathAddress, UnixFileAttributes attrs) + throws UnixException; + + /** + * fstat(int filedes, struct stat* buf) + */ + static native void fstat(int fd, UnixFileAttributes attrs) throws UnixException; + + /** + * fstatat(int filedes,const char* path, struct stat* buf, int flag) + */ + static void fstatat(int dfd, byte[] path, int flag, UnixFileAttributes attrs) + throws UnixException + { + NativeBuffer buffer = NativeBuffers.asNativeBuffer(path); + try { + fstatat0(dfd, buffer.address(), flag, attrs); + } finally { + buffer.release(); + } + } + private static native void fstatat0(int dfd, long pathAddress, int flag, + UnixFileAttributes attrs) throws UnixException; + + /** + * chown(const char* path, uid_t owner, gid_t group) + */ + static void chown(UnixPath path, int uid, int gid) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + chown0(buffer.address(), uid, gid); + } finally { + buffer.release(); + } + } + private static native void chown0(long pathAddress, int uid, int gid) + throws UnixException; + + /** + * lchown(const char* path, uid_t owner, gid_t group) + */ + static void lchown(UnixPath path, int uid, int gid) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + lchown0(buffer.address(), uid, gid); + } finally { + buffer.release(); + } + } + private static native void lchown0(long pathAddress, int uid, int gid) + throws UnixException; + + /** + * fchown(int filedes, uid_t owner, gid_t group) + */ + static native void fchown(int fd, int uid, int gid) throws UnixException; + + /** + * chmod(const char* path, mode_t mode) + */ + static void chmod(UnixPath path, int mode) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + chmod0(buffer.address(), mode); + } finally { + buffer.release(); + } + } + private static native void chmod0(long pathAddress, int mode) + throws UnixException; + + /** + * fchmod(int fildes, mode_t mode) + */ + static native void fchmod(int fd, int mode) throws UnixException; + + /** + * utimes(conar char* path, const struct timeval times[2]) + */ + static void utimes(UnixPath path, long times0, long times1) + throws UnixException + { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + utimes0(buffer.address(), times0, times1); + } finally { + buffer.release(); + } + } + private static native void utimes0(long pathAddress, long times0, long times1) + throws UnixException; + + /** + * futimes(int fildes,, const struct timeval times[2]) + */ + static native void futimes(int fd, long times0, long times1) throws UnixException; + + /** + * DIR *opendir(const char* dirname) + */ + static long opendir(UnixPath path) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + return opendir0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native long opendir0(long pathAddress) throws UnixException; + + /** + * DIR* fdopendir(int filedes) + */ + static native long fdopendir(int dfd) throws UnixException; + + + /** + * closedir(DIR* dirp) + */ + static native void closedir(long dir) throws UnixException; + + /** + * struct dirent* readdir(DIR *dirp) + * + * @return dirent->d_name + */ + static native byte[] readdir(long dir) throws UnixException; + + /** + * size_t read(int fildes, void* buf, size_t nbyte) + */ + static native int read(int fildes, long buf, int nbyte) throws UnixException; + + /** + * size_t writeint fildes, void* buf, size_t nbyte) + */ + static native int write(int fildes, long buf, int nbyte) throws UnixException; + + /** + * access(const char* path, int amode); + */ + static void access(UnixPath path, int amode) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + access0(buffer.address(), amode); + } finally { + buffer.release(); + } + } + private static native void access0(long pathAddress, int amode) throws UnixException; + + /** + * struct passwd *getpwuid(uid_t uid); + * + * @return passwd->pw_name + */ + static native byte[] getpwuid(int uid) throws UnixException; + + /** + * struct group *getgrgid(gid_t gid); + * + * @return group->gr_name + */ + static native byte[] getgrgid(int gid) throws UnixException; + + /** + * struct passwd *getpwnam(const char *name); + * + * @return passwd->pw_uid + */ + static int getpwnam(String name) throws UnixException { + NativeBuffer buffer = NativeBuffers.asNativeBuffer(name.getBytes()); + try { + return getpwnam0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native int getpwnam0(long nameAddress) throws UnixException; + + /** + * struct group *getgrnam(const char *name); + * + * @return group->gr_name + */ + static int getgrnam(String name) throws UnixException { + NativeBuffer buffer = NativeBuffers.asNativeBuffer(name.getBytes()); + try { + return getgrnam0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native int getgrnam0(long nameAddress) throws UnixException; + + /** + * int getextmntent(FILE *fp, struct extmnttab *mp, int len); + */ + static native int getextmntent(long fp, UnixMountEntry entry) throws UnixException; + + /** + * statvfs(const char* path, struct statvfs *buf) + */ + static void statvfs(UnixPath path, UnixFileStoreAttributes attrs) + throws UnixException + { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + statvfs0(buffer.address(), attrs); + } finally { + buffer.release(); + } + } + private static native void statvfs0(long pathAddress, UnixFileStoreAttributes attrs) + throws UnixException; + + /** + * long int pathconf(const char *path, int name); + */ + static long pathconf(UnixPath path, int name) throws UnixException { + NativeBuffer buffer = copyToNativeBuffer(path); + try { + return pathconf0(buffer.address(), name); + } finally { + buffer.release(); + } + } + private static native long pathconf0(long pathAddress, int name) + throws UnixException; + + /** + * long fpathconf(int fildes, int name); + */ + static native long fpathconf(int filedes, int name) throws UnixException; + + /** + * char* strerror(int errnum) + */ + static native byte[] strerror(int errnum); + + // initialize field IDs + private static native void initIDs(); + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + initIDs(); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java new file mode 100644 index 00000000000..c1330f005ce --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java @@ -0,0 +1,1228 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.AbstractPath; +import java.nio.charset.*; +import java.nio.channels.*; +import java.security.AccessController; +import java.io.*; +import java.net.URI; +import java.util.*; +import java.lang.ref.SoftReference; +import sun.security.util.SecurityConstants; + +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.UnixConstants.*; + +/** + * Solaris/Linux implementation of java.nio.file.Path + */ + +class UnixPath + extends AbstractPath +{ + private static ThreadLocal<SoftReference<CharsetEncoder>> encoder = + new ThreadLocal<SoftReference<CharsetEncoder>>(); + + // FIXME - eliminate this reference to reduce space + private final UnixFileSystem fs; + + // internal representation + private final byte[] path; + + // String representation (created lazily) + private volatile String stringValue; + + // cached hashcode (created lazily, no need to be volatile) + private int hash; + + // array of offsets of elements in path (created lazily) + private volatile int[] offsets; + + // file permissions (created lazily) + private volatile FilePermission[] perms; + + UnixPath(UnixFileSystem fs, byte[] path) { + this.fs = fs; + this.path = path; + } + + UnixPath(UnixFileSystem fs, String input) { + // removes redundant slashes and checks for invalid characters + this(fs, encode(normalizeAndCheck(input))); + } + + // package-private + // removes redundant slashes and check input for invalid characters + static String normalizeAndCheck(String input) { + int n = input.length(); + if (n == 0) + throw new InvalidPathException(input, "Path is empty"); + char prevChar = 0; + for (int i=0; i < n; i++) { + char c = input.charAt(i); + if (c == '\u0000') + throw new InvalidPathException(input, "Nul character not allowed"); + if ((c == '/') && (prevChar == '/')) + return normalize(input, n, i - 1); + prevChar = c; + } + if (prevChar == '/') + return normalize(input, n, n - 1); + return input; + } + + private static String normalize(String input, int len, int off) { + if (len == 0) + return input; + int n = len; + while ((n > 0) && (input.charAt(n - 1) == '/')) n--; + if (n == 0) + return "/"; + StringBuilder sb = new StringBuilder(input.length()); + if (off > 0) + sb.append(input.substring(0, off)); + char prevChar = 0; + for (int i=off; i < n; i++) { + char c = input.charAt(i); + if ((c == '/') && (prevChar == '/')) + continue; + sb.append(c); + prevChar = c; + } + return sb.toString(); + } + + // encodes the given path-string into a sequence of bytes + private static byte[] encode(String input) { + SoftReference<CharsetEncoder> ref = encoder.get(); + CharsetEncoder ce = (ref != null) ? ref.get() : null; + if (ce == null) { + ce = Charset.defaultCharset().newEncoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + encoder.set(new SoftReference<CharsetEncoder>(ce)); + } + + char[] ca = input.toCharArray(); + + // size output buffer for worse-case size + byte[] ba = new byte[(int)(ca.length * (double)ce.maxBytesPerChar())]; + + // encode + ByteBuffer bb = ByteBuffer.wrap(ba); + CharBuffer cb = CharBuffer.wrap(ca); + ce.reset(); + CoderResult cr = ce.encode(cb, bb, true); + boolean error; + if (!cr.isUnderflow()) { + error = true; + } else { + cr = ce.flush(bb); + error = !cr.isUnderflow(); + } + if (error) { + throw new InvalidPathException(input, + "Malformed input or input contains unmappable chacraters"); + } + + // trim result to actual length if required + int len = bb.position(); + if (len != ba.length) + ba = Arrays.copyOf(ba, len); + + return ba; + } + + // package-private + byte[] asByteArray() { + return path; + } + + // use this path when making system/library calls + byte[] getByteArrayForSysCalls() { + // resolve against default directory if required (chdir allowed or + // file system default directory is not working directory) + if (getFileSystem().needToResolveAgainstDefaultDirectory()) { + return resolve(getFileSystem().defaultDirectory(), path); + } else { + return path; + } + } + + // use this message when throwing exceptions + String getPathForExecptionMessage() { + return toString(); + } + + // use this path for permission checks + String getPathForPermissionCheck() { + if (getFileSystem().needToResolveAgainstDefaultDirectory()) { + return new String(getByteArrayForSysCalls()); + } else { + return toString(); + } + } + + // Checks that the given file is a UnixPath + private UnixPath checkPath(FileRef obj) { + if (obj == null) + throw new NullPointerException(); + if (!(obj instanceof UnixPath)) + throw new ProviderMismatchException(); + return (UnixPath)obj; + } + + // create offset list if not already created + private void initOffsets() { + if (offsets == null) { + int count, index; + + // count names + count = 0; + index = 0; + while (index < path.length) { + byte c = path[index++]; + if (c != '/') { + count++; + while (index < path.length && path[index] != '/') + index++; + } + } + + // populate offsets + int[] result = new int[count]; + count = 0; + index = 0; + while (index < path.length) { + byte c = path[index]; + if (c == '/') { + index++; + } else { + result[count++] = index++; + while (index < path.length && path[index] != '/') + index++; + } + } + synchronized (this) { + if (offsets == null) + offsets = result; + } + } + } + + @Override + public UnixFileSystem getFileSystem() { + return fs; + } + + @Override + public UnixPath getRoot() { + if (path[0] == '/') { + return getFileSystem().rootDirectory(); + } else { + return null; + } + } + + @Override + public UnixPath getName() { + initOffsets(); + + int count = offsets.length; + if (count == 0) + return null; // no elements so no name + + if (count == 1 && path[0] != '/') + return this; + + int lastOffset = offsets[count-1]; + int len = path.length - lastOffset; + byte[] result = new byte[len]; + System.arraycopy(path, lastOffset, result, 0, len); + return new UnixPath(getFileSystem(), result); + } + + @Override + public UnixPath getParent() { + initOffsets(); + + int count = offsets.length; + if (count == 0) { + // no elements so no parent + return null; + } + int len = offsets[count-1] - 1; + if (len <= 0) { + // parent is root only (may be null) + return getRoot(); + } + byte[] result = new byte[len]; + System.arraycopy(path, 0, result, 0, len); + return new UnixPath(getFileSystem(), result); + } + + @Override + public int getNameCount() { + initOffsets(); + return offsets.length; + } + + @Override + public UnixPath getName(int index) { + initOffsets(); + if (index < 0) + throw new IllegalArgumentException(); + if (index >= offsets.length) + throw new IllegalArgumentException(); + + int begin = offsets[index]; + int len; + if (index == (offsets.length-1)) { + len = path.length - begin; + } else { + len = offsets[index+1] - begin - 1; + } + + // construct result + byte[] result = new byte[len]; + System.arraycopy(path, begin, result, 0, len); + return new UnixPath(getFileSystem(), result); + } + + @Override + public UnixPath subpath(int beginIndex, int endIndex) { + initOffsets(); + + if (beginIndex < 0) + throw new IllegalArgumentException(); + if (beginIndex >= offsets.length) + throw new IllegalArgumentException(); + if (endIndex > offsets.length) + throw new IllegalArgumentException(); + if (beginIndex >= endIndex) { + throw new IllegalArgumentException(); + } + + // starting offset and length + int begin = offsets[beginIndex]; + int len; + if (endIndex == offsets.length) { + len = path.length - begin; + } else { + len = offsets[endIndex] - begin - 1; + } + + // construct result + byte[] result = new byte[len]; + System.arraycopy(path, begin, result, 0, len); + return new UnixPath(getFileSystem(), result); + } + + @Override + public boolean isAbsolute() { + return (path[0] == '/'); + } + + // Resolve child against given base + private static byte[] resolve(byte[] base, byte[] child) { + if (child[0] == '/') + return child; + byte[] result; + if (base.length == 1 && base[0] == '/') { + result = new byte[child.length + 1]; + result[0] = '/'; + System.arraycopy(child, 0, result, 1, child.length); + } else { + result = new byte[base.length + 1 + child.length]; + System.arraycopy(base, 0, result, 0, base.length); + result[base.length] = '/'; + System.arraycopy(child, 0, result, base.length+1, child.length); + } + return result; + } + + @Override + public UnixPath resolve(Path obj) { + if (obj == null) + return this; + byte[] other = checkPath(obj).path; + if (other[0] == '/') + return ((UnixPath)obj); + byte[] result = resolve(path, other); + return new UnixPath(getFileSystem(), result); + } + + @Override + public UnixPath resolve(String other) { + return resolve(new UnixPath(getFileSystem(), other)); + } + + UnixPath resolve(byte[] other) { + return resolve(new UnixPath(getFileSystem(), other)); + } + + @Override + public UnixPath relativize(Path obj) { + UnixPath other = checkPath(obj); + if (other.equals(this)) + return null; + + // can only relativize paths of the same type + if (this.isAbsolute() != other.isAbsolute()) + throw new IllegalArgumentException("'other' is different type of Path"); + + int bn = this.getNameCount(); + int cn = other.getNameCount(); + + // skip matching names + int n = (bn > cn) ? cn : bn; + int i = 0; + while (i < n) { + if (!this.getName(i).equals(other.getName(i))) + break; + i++; + } + + int dotdots = bn - i; + if (i < cn) { + // remaining name components in other + UnixPath remainder = other.subpath(i, cn); + if (dotdots == 0) + return remainder; + + // result is a "../" for each remaining name in base + // followed by the remaining names in other + byte[] result = new byte[dotdots*3 + remainder.path.length]; + int pos = 0; + while (dotdots > 0) { + result[pos++] = (byte)'.'; + result[pos++] = (byte)'.'; + result[pos++] = (byte)'/'; + dotdots--; + } + System.arraycopy(remainder.path, 0, result, pos, remainder.path.length); + return new UnixPath(getFileSystem(), result); + } else { + // no remaining names in other so result is simply a sequence of ".." + byte[] result = new byte[dotdots*3 - 1]; + int pos = 0; + while (dotdots > 0) { + result[pos++] = (byte)'.'; + result[pos++] = (byte)'.'; + // no tailing slash at the end + if (dotdots > 1) + result[pos++] = (byte)'/'; + dotdots--; + } + return new UnixPath(getFileSystem(), result); + } + } + + @Override + public Path normalize() { + final int count = getNameCount(); + if (count == 0) + return this; + + boolean[] ignore = new boolean[count]; // true => ignore name + int[] size = new int[count]; // length of name + int remaining = count; // number of names remaining + boolean hasDotDot = false; // has at least one .. + boolean isAbsolute = path[0] == '/'; + + // first pass: + // 1. compute length of names + // 2. mark all occurences of "." to ignore + // 3. and look for any occurences of ".." + for (int i=0; i<count; i++) { + int begin = offsets[i]; + int len; + if (i == (offsets.length-1)) { + len = path.length - begin; + } else { + len = offsets[i+1] - begin - 1; + } + size[i] = len; + + if (path[begin] == '.') { + if (len == 1) { + ignore[i] = true; // ignore "." + remaining--; + } + else { + if (path[begin+1] == '.') // ".." found + hasDotDot = true; + } + } + } + + // multiple passes to eliminate all occurences of name/.. + if (hasDotDot) { + int prevRemaining; + do { + prevRemaining = remaining; + int prevName = -1; + for (int i=0; i<count; i++) { + if (ignore[i]) + continue; + + // not a ".." + if (size[i] != 2) { + prevName = i; + continue; + } + + int begin = offsets[i]; + if (path[begin] != '.' || path[begin+1] != '.') { + prevName = i; + continue; + } + + // ".." found + if (prevName >= 0) { + // name/<ignored>/.. found so mark name and ".." to be + // ignored + ignore[prevName] = true; + ignore[i] = true; + remaining = remaining - 2; + prevName = -1; + } else { + // Case: /<ignored>/.. so mark ".." as ignored + if (isAbsolute) { + boolean hasPrevious = false; + for (int j=0; j<i; j++) { + if (!ignore[j]) { + hasPrevious = true; + break; + } + } + if (!hasPrevious) { + // all proceeding names are ignored + ignore[i] = true; + remaining--; + } + } + } + } + } while (prevRemaining > remaining); + } + + // no redundant names + if (remaining == count) + return this; + + // corner case - all names removed + if (remaining == 0) { + return isAbsolute ? getFileSystem().rootDirectory() : null; + } + + // compute length of result + int len = remaining - 1; + if (isAbsolute) + len++; + + for (int i=0; i<count; i++) { + if (!ignore[i]) + len += size[i]; + } + byte[] result = new byte[len]; + + // copy names into result + int pos = 0; + if (isAbsolute) + result[pos++] = '/'; + for (int i=0; i<count; i++) { + if (!ignore[i]) { + System.arraycopy(path, offsets[i], result, pos, size[i]); + pos += size[i]; + if (--remaining > 0) { + result[pos++] = '/'; + } + } + } + return new UnixPath(getFileSystem(), result); + } + + @Override + public boolean startsWith(Path other) { + UnixPath that = checkPath(other); + + // other path is longer + if (that.path.length > path.length) + return false; + + int thisOffsetCount = getNameCount(); + int thatOffsetCount = that.getNameCount(); + + // other path has no name elements + if (thatOffsetCount == 0 && this.isAbsolute()) + return true; + + // given path has more elements that this path + if (thatOffsetCount > thisOffsetCount) + return false; + + // same number of elements so must be exact match + if ((thatOffsetCount == thisOffsetCount) && + (path.length != that.path.length)) { + return false; + } + + // check offsets of elements match + for (int i=0; i<thatOffsetCount; i++) { + Integer o1 = offsets[i]; + Integer o2 = that.offsets[i]; + if (!o1.equals(o2)) + return false; + } + + // offsets match so need to compare bytes + int i=0; + while (i < that.path.length) { + if (this.path[i] != that.path[i]) + return false; + i++; + } + + // final check that match is on name boundary + if (i < path.length && this.path[i] != '/') + return false; + + return true; + } + + @Override + public boolean endsWith(Path other) { + UnixPath that = checkPath(other); + + // other path is longer + if (that.path.length > path.length) + return false; + + // other path is absolute so this path must be absolute + if (that.isAbsolute() && !this.isAbsolute()) + return false; + + int thisOffsetCount = getNameCount(); + int thatOffsetCount = that.getNameCount(); + + // given path has more elements that this path + if (thatOffsetCount > thisOffsetCount) { + return false; + } else { + // same number of elements + if (thatOffsetCount == thisOffsetCount) { + if (thisOffsetCount == 0) + return true; + int expectedLen = path.length; + if (this.isAbsolute() && !that.isAbsolute()) + expectedLen--; + if (that.path.length != expectedLen) + return false; + } else { + // this path has more elements so given path must be relative + if (that.isAbsolute()) + return false; + } + } + + // compare bytes + int thisPos = offsets[thisOffsetCount - thatOffsetCount]; + int thatPos = that.offsets[0]; + while (thatPos < that.path.length) { + if (this.path[thisPos++] != that.path[thatPos++]) + return false; + } + + return true; + } + + @Override + public int compareTo(Path other) { + int len1 = path.length; + int len2 = ((UnixPath) other).path.length; + + int n = Math.min(len1, len2); + byte v1[] = path; + byte v2[] = ((UnixPath) other).path; + + int k = 0; + while (k < n) { + int c1 = v1[k] & 0xff; + int c2 = v2[k] & 0xff; + if (c1 != c2) { + return c1 - c2; + } + k++; + } + return len1 - len2; + } + + @Override + public boolean equals(Object ob) { + if ((ob != null) && (ob instanceof UnixPath)) { + return compareTo((Path)ob) == 0; + } + return false; + } + + @Override + public int hashCode() { + // OK if two or more threads compute hash + int h = hash; + if (h == 0) { + for (int i = 0; i< path.length; i++) { + h = 31*h + (path[i] & 0xff); + } + hash = h; + } + return h; + } + + @Override + public String toString() { + // OK if two or more threads create a String + if (stringValue == null) + stringValue = new String(path); // platform encoding + return stringValue; + } + + @Override + public Iterator<Path> iterator() { + initOffsets(); + return new Iterator<Path>() { + int i = 0; + @Override + public boolean hasNext() { + return (i < offsets.length); + } + @Override + public Path next() { + if (i < offsets.length) { + Path result = getName(i); + i++; + return result; + } else { + throw new NoSuchElementException(); + } + } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + // -- file operations -- + + // package-private + int openForAttributeAccess(boolean followLinks) throws IOException { + int flags = O_RDONLY; + if (!followLinks) + flags |= O_NOFOLLOW; + try { + return open(this, flags, 0); + } catch (UnixException x) { + // HACK: EINVAL instead of ELOOP on Solaris 10 prior to u4 (see 6460380) + if (getFileSystem().isSolaris() && x.errno() == EINVAL) + x.setError(ELOOP); + + if (x.errno() == ELOOP) + throw new FileSystemException(getPathForExecptionMessage(), null, + x.getMessage() + " or unable to access attributes of symbolic link"); + + x.rethrowAsIOException(this); + return -1; // keep compile happy + } + } + + // create file permissions used for read and write checks + private void checkReadOrWrite(boolean checkRead) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) + return; + if (perms == null) { + synchronized (this) { + if (perms == null) { + FilePermission[] p = new FilePermission[2]; + String pathForPermCheck = getPathForPermissionCheck(); + p[0] = new FilePermission(pathForPermCheck, + SecurityConstants.FILE_READ_ACTION); + p[1] = new FilePermission(pathForPermCheck, + SecurityConstants.FILE_WRITE_ACTION); + perms = p; + } + } + } + if (checkRead) { + sm.checkPermission(perms[0]); + } else { + sm.checkPermission(perms[1]); + } + } + + void checkRead() { + checkReadOrWrite(true); + } + + void checkWrite() { + checkReadOrWrite(false); + } + + void checkDelete() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // permission not cached + sm.checkDelete(getPathForPermissionCheck()); + } + } + + @Override + public FileStore getFileStore() + throws IOException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); + checkRead(); + } + return getFileSystem().getFileStore(this); + } + + @Override + public void checkAccess(AccessMode... modes) throws IOException { + boolean e = false; + boolean r = false; + boolean w = false; + boolean x = false; + + if (modes.length == 0) { + e = true; + } else { + for (AccessMode mode: modes) { + switch (mode) { + case READ : r = true; break; + case WRITE : w = true; break; + case EXECUTE : x = true; break; + default: throw new AssertionError("Should not get here"); + } + } + } + + int mode = 0; + if (e || r) { + checkRead(); + mode |= (r) ? R_OK : F_OK; + } + if (w) { + checkWrite(); + mode |= W_OK; + } + if (x) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // not cached + sm.checkExec(getPathForPermissionCheck()); + } + mode |= X_OK; + } + try { + access(this, mode); + } catch (UnixException exc) { + exc.rethrowAsIOException(this); + } + } + + @Override + public void delete(boolean failIfNotExists) throws IOException { + checkDelete(); + + // need file attributes to know if file is directory + UnixFileAttributes attrs = null; + try { + attrs = UnixFileAttributes.get(this, false); + if (attrs.isDirectory()) { + rmdir(this); + } else { + unlink(this); + } + } catch (UnixException x) { + // no-op if file does not exist + if (!failIfNotExists && x.errno() == ENOENT) + return; + + // DirectoryNotEmptyException if not empty + if (attrs != null && attrs.isDirectory() && + (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) + throw new DirectoryNotEmptyException(getPathForExecptionMessage()); + + x.rethrowAsIOException(this); + } + } + + @Override + public DirectoryStream<Path> newDirectoryStream(DirectoryStream.Filter<? super Path> filter) + throws IOException + { + if (filter == null) + throw new NullPointerException(); + checkRead(); + + // can't return SecureDirectoryStream on older kernels. + if (!getFileSystem().supportsSecureDirectoryStreams()) { + try { + long ptr = opendir(this); + return new UnixDirectoryStream(this, ptr, filter); + } catch (UnixException x) { + if (x.errno() == UnixConstants.ENOTDIR) + throw new NotDirectoryException(getPathForExecptionMessage()); + x.rethrowAsIOException(this); + } + } + + // open directory and dup file descriptor for use by + // opendir/readdir/closedir + int dfd1 = -1; + int dfd2 = -1; + long dp = 0L; + try { + dfd1 = open(this, O_RDONLY, 0); + dfd2 = dup(dfd1); + dp = fdopendir(dfd1); + } catch (UnixException x) { + if (dfd1 != -1) + close(dfd1); + if (dfd2 != -1) + close(dfd2); + if (x.errno() == UnixConstants.ENOTDIR) + throw new NotDirectoryException(getPathForExecptionMessage()); + x.rethrowAsIOException(this); + } + return new UnixSecureDirectoryStream(this, dp, dfd2, filter); + } + + // invoked by AbstractPath#copyTo + @Override + public void implCopyTo(Path obj, CopyOption... options) + throws IOException + { + UnixPath target = (UnixPath)obj; + UnixCopyFile.copy(this, target, options); + } + + @Override + public void implMoveTo(Path obj, CopyOption... options) + throws IOException + { + UnixPath target = (UnixPath)obj; + UnixCopyFile.move(this, target, options); + } + + @Override + @SuppressWarnings("unchecked") + public <V extends FileAttributeView> V + getFileAttributeView(Class<V> type, LinkOption... options) + { + FileAttributeView view = getFileSystem() + .newFileAttributeView(type, this, options); + if (view == null) + return null; + return (V) view; + } + + @Override + public FileAttributeView getFileAttributeView(String name, LinkOption... options) { + return getFileSystem().newFileAttributeView(name, this, options); + } + + @Override + public Path createDirectory(FileAttribute<?>... attrs) + throws IOException + { + checkWrite(); + + int mode = UnixFileModeAttribute + .toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs); + try { + mkdir(this, mode); + } catch (UnixException x) { + x.rethrowAsIOException(this); + } + return this; + } + + @Override + public InputStream newInputStream()throws IOException { + try { + Set<OpenOption> options = Collections.emptySet(); + FileChannel fc = UnixChannelFactory.newFileChannel(this, options, 0); + return Channels.newInputStream(fc); + } catch (UnixException x) { + x.rethrowAsIOException(this); + return null; // keep compiler happy + } + } + + @Override + public SeekableByteChannel newByteChannel(Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + int mode = UnixFileModeAttribute + .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); + try { + return UnixChannelFactory.newFileChannel(this, options, mode); + } catch (UnixException x) { + x.rethrowAsIOException(this); + return null; // keep compiler happy + } + } + + @Override + public OutputStream newOutputStream(Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + // need to copy options to add WRITE + Set<OpenOption> opts = new HashSet<OpenOption>(options); + if (opts.contains(StandardOpenOption.READ)) + throw new IllegalArgumentException("READ not allowed"); + opts.add(StandardOpenOption.WRITE); + + int mode = UnixFileModeAttribute + .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); + try { + FileChannel fc = UnixChannelFactory.newFileChannel(this, opts, mode); + return Channels.newOutputStream(fc); + } catch (UnixException x) { + x.rethrowAsIOException(this); + return null; // keep compiler happy + } + } + + @Override + public boolean isSameFile(FileRef obj) throws IOException { + if (this.equals(obj)) + return true; + if (!(obj instanceof UnixPath)) // includes null check + return false; + UnixPath other = (UnixPath)obj; + + // check security manager access to both files + this.checkRead(); + other.checkRead(); + + UnixFileAttributes thisAttrs; + UnixFileAttributes otherAttrs; + try { + thisAttrs = UnixFileAttributes.get(this, true); + } catch (UnixException x) { + x.rethrowAsIOException(this); + return false; // keep compiler happy + } + try { + otherAttrs = UnixFileAttributes.get(other, true); + } catch (UnixException x) { + x.rethrowAsIOException(other); + return false; // keep compiler happy + } + return thisAttrs.isSameFile(otherAttrs); + } + + @Override + public Path createSymbolicLink(Path obj, FileAttribute<?>... attrs) + throws IOException + { + UnixPath target = checkPath(obj); + + // no attributes supported when creating links + if (attrs.length > 0) { + UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE + throw new UnsupportedOperationException("Initial file attributes" + + "not supported when creating symbolic link"); + } + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new LinkPermission("symbolic")); + checkWrite(); + } + + // create link + try { + symlink(target.asByteArray(), this); + } catch (UnixException x) { + x.rethrowAsIOException(this); + } + + return this; + } + + @Override + public Path createLink(Path obj) throws IOException { + UnixPath existing = checkPath(obj); + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new LinkPermission("hard")); + this.checkWrite(); + existing.checkWrite(); + } + try { + link(existing, this); + } catch (UnixException x) { + x.rethrowAsIOException(this, existing); + } + return this; + } + + @Override + public Path readSymbolicLink() throws IOException { + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + FilePermission perm = new FilePermission(getPathForPermissionCheck(), + SecurityConstants.FILE_READLINK_ACTION); + AccessController.checkPermission(perm); + } + try { + byte[] target = readlink(this); + return new UnixPath(getFileSystem(), target); + } catch (UnixException x) { + if (x.errno() == UnixConstants.EINVAL) + throw new NotLinkException(getPathForExecptionMessage()); + x.rethrowAsIOException(this); + return null; // keep compiler happy + } + } + + @Override + public UnixPath toAbsolutePath() { + if (isAbsolute()) { + return this; + } + // The path is relative so need to resolve against default directory, + // taking care not to reveal the user.dir + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPropertyAccess("user.dir"); + } + return new UnixPath(getFileSystem(), + resolve(getFileSystem().defaultDirectory(), path)); + } + + @Override + public UnixPath toRealPath(boolean resolveLinks) throws IOException { + checkRead(); + + UnixPath absolute = toAbsolutePath(); + + // if resolveLinks is true then use realpath + if (resolveLinks) { + try { + byte[] rp = realpath(absolute); + return new UnixPath(getFileSystem(), rp); + } catch (UnixException x) { + x.rethrowAsIOException(this); + } + } + + // if resolveLinks is false then eliminate "." and also ".." + // where the previous element is not a link. + UnixPath root = getFileSystem().rootDirectory(); + UnixPath result = root; + for (int i=0; i<absolute.getNameCount(); i++) { + UnixPath element = absolute.getName(i); + + // eliminate "." + if ((element.asByteArray().length == 1) && (element.asByteArray()[0] == '.')) + continue; + + // cannot eliminate ".." if previous element is a link + if ((element.asByteArray().length == 2) && (element.asByteArray()[0] == '.') && + (element.asByteArray()[1] == '.')) + { + UnixFileAttributes attrs = null; + try { + attrs = UnixFileAttributes.get(result, false); + } catch (UnixException x) { + x.rethrowAsIOException(result); + } + if (!attrs.isSymbolicLink()) { + result = result.getParent(); + if (result == null) { + result = root; + } + continue; + } + } + result = result.resolve(element); + } + + // finally check that file exists + try { + UnixFileAttributes.get(result, true); + } catch (UnixException x) { + x.rethrowAsIOException(result); + } + return result; + } + + @Override + public boolean isHidden() { + checkRead(); + UnixPath name = getName(); + if (name == null) + return false; + return (name.asByteArray()[0] == '.'); + } + + @Override + public URI toUri() { + return UnixUriUtils.toUri(this); + } + + @Override + public WatchKey register(WatchService watcher, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) + throws IOException + { + if (watcher == null) + throw new NullPointerException(); + if (!(watcher instanceof AbstractWatchService)) + throw new ProviderMismatchException(); + checkRead(); + return ((AbstractWatchService)watcher).register(this, events, modifiers); + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java b/jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java new file mode 100644 index 00000000000..e5894878709 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java @@ -0,0 +1,643 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.channels.SeekableByteChannel; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.io.IOException; + +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.UnixConstants.*; + +/** + * Unix implementation of SecureDirectoryStream. + */ + +class UnixSecureDirectoryStream + extends SecureDirectoryStream +{ + private final UnixDirectoryStream ds; + private final int dfd; + + UnixSecureDirectoryStream(UnixPath dir, + long dp, + int dfd, + DirectoryStream.Filter<? super Path> filter) + { + this.ds = new UnixDirectoryStream(dir, dp, filter); + this.dfd = dfd; + } + + @Override + public void close() + throws IOException + { + ds.writeLock().lock(); + try { + if (ds.closeImpl()) { + UnixNativeDispatcher.close(dfd); + } + } finally { + ds.writeLock().unlock(); + } + } + + @Override + public Iterator<Path> iterator() { + return ds.iterator(this); + } + + private UnixPath getName(Path obj) { + if (obj == null) + throw new NullPointerException(); + if (!(obj instanceof UnixPath)) + throw new ProviderMismatchException(); + return (UnixPath)obj; + } + + /** + * Opens sub-directory in this directory + */ + @Override + public SecureDirectoryStream newDirectoryStream(Path obj, + boolean followLinks, + DirectoryStream.Filter<? super Path> filter) + throws IOException + { + UnixPath file = getName(obj); + UnixPath child = ds.directory().resolve(file); + + // permission check using name resolved against original path of directory + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + child.checkRead(); + } + + ds.readLock().lock(); + try { + if (!ds.isOpen()) + throw new ClosedDirectoryStreamException(); + + // open directory and create new secure directory stream + int newdfd1 = -1; + int newdfd2 = -1; + long ptr = 0L; + try { + int flags = O_RDONLY; + if (!followLinks) + flags |= O_NOFOLLOW; + newdfd1 = openat(dfd, file.asByteArray(), flags , 0); + newdfd2 = dup(newdfd1); + ptr = fdopendir(newdfd1); + } catch (UnixException x) { + if (newdfd1 != -1) + UnixNativeDispatcher.close(newdfd1); + if (newdfd2 != -1) + UnixNativeDispatcher.close(newdfd2); + if (x.errno() == UnixConstants.ENOTDIR) + throw new NotDirectoryException(file.toString()); + x.rethrowAsIOException(file); + } + return new UnixSecureDirectoryStream(child, ptr, newdfd2, filter); + } finally { + ds.readLock().unlock(); + } + } + + /** + * Opens file in this directory + */ + @Override + public SeekableByteChannel newByteChannel(Path obj, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + UnixPath file = getName(obj); + + int mode = UnixFileModeAttribute + .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); + + // path for permission check + String pathToCheck = ds.directory().resolve(file).getPathForPermissionCheck(); + + ds.readLock().lock(); + try { + if (!ds.isOpen()) + throw new ClosedDirectoryStreamException(); + try { + return UnixChannelFactory.newFileChannel(dfd, file, pathToCheck, options, mode); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } + } finally { + ds.readLock().unlock(); + } + } + + /** + * Deletes file/directory in this directory. Works in a race-free manner + * when invoked with flags. + */ + void implDelete(Path obj, boolean haveFlags, int flags) + throws IOException + { + UnixPath file = getName(obj); + + // permission check using name resolved against original path of directory + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + ds.directory().resolve(file).checkDelete(); + } + + ds.readLock().lock(); + try { + if (!ds.isOpen()) + throw new ClosedDirectoryStreamException(); + + if (!haveFlags) { + // need file attribute to know if file is directory. This creates + // a race in that the file may be replaced by a directory or a + // directory replaced by a file between the time we query the + // file type and unlink it. + UnixFileAttributes attrs = null; + try { + attrs = UnixFileAttributes.get(dfd, file, false); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + flags = (attrs.isDirectory()) ? AT_REMOVEDIR : 0; + } + + try { + unlinkat(dfd, file.asByteArray(), flags); + } catch (UnixException x) { + if ((flags & AT_REMOVEDIR) != 0) { + if (x.errno() == EEXIST || x.errno() == ENOTEMPTY) { + throw new DirectoryNotEmptyException(null); + } + } + x.rethrowAsIOException(file); + } + } finally { + ds.readLock().unlock(); + } + } + + @Override + public void deleteFile(Path file) throws IOException { + implDelete(file, true, 0); + } + + @Override + public void deleteDirectory(Path dir) throws IOException { + implDelete(dir, true, AT_REMOVEDIR); + } + + /** + * Rename/move file in this directory to another (open) directory + */ + @Override + public void move(Path fromObj, SecureDirectoryStream dir, Path toObj) + throws IOException + { + UnixPath from = getName(fromObj); + UnixPath to = getName(toObj); + if (dir == null) + throw new NullPointerException(); + if (!(dir instanceof UnixSecureDirectoryStream)) + throw new ProviderMismatchException(); + UnixSecureDirectoryStream that = (UnixSecureDirectoryStream)dir; + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + this.ds.directory().resolve(from).checkWrite(); + that.ds.directory().resolve(to).checkWrite(); + } + + // lock ordering doesn't matter + this.ds.readLock().lock(); + try { + that.ds.readLock().lock(); + try { + if (!this.ds.isOpen() || !that.ds.isOpen()) + throw new ClosedDirectoryStreamException(); + try { + renameat(this.dfd, from.asByteArray(), that.dfd, to.asByteArray()); + } catch (UnixException x) { + if (x.errno() == EXDEV) { + throw new AtomicMoveNotSupportedException( + from.toString(), to.toString(), x.errorString()); + } + x.rethrowAsIOException(from, to); + } + } finally { + that.ds.readLock().unlock(); + } + } finally { + this.ds.readLock().unlock(); + } + } + + @SuppressWarnings("unchecked") + private <V extends FileAttributeView> V getFileAttributeViewImpl(UnixPath file, + Class<V> type, + boolean followLinks) + { + if (type == null) + throw new NullPointerException(); + Class<?> c = type; + if (c == BasicFileAttributeView.class) { + return (V) new BasicFileAttributeViewImpl(file, followLinks); + } + if (c == PosixFileAttributeView.class || c == FileOwnerAttributeView.class) { + return (V) new PosixFileAttributeViewImpl(file, followLinks); + } + // TBD - should also support AclFileAttributeView + return (V) null; + } + + /** + * Returns file attribute view bound to this directory + */ + @Override + public <V extends FileAttributeView> V getFileAttributeView(Class<V> type) { + return getFileAttributeViewImpl(null, type, false); + } + + /** + * Returns file attribute view bound to dfd/filename. + */ + @Override + public <V extends FileAttributeView> V getFileAttributeView(Path obj, + Class<V> type, + LinkOption... options) + { + UnixPath file = getName(obj); + boolean followLinks = file.getFileSystem().followLinks(options); + return getFileAttributeViewImpl(file, type, followLinks); + } + + /** + * A BasicFileAttributeView implementation that using a dfd/name pair. + */ + private class BasicFileAttributeViewImpl + extends AbstractBasicFileAttributeView + { + final UnixPath file; + final boolean followLinks; + + // set to true when binding to another object + volatile boolean forwarding; + + BasicFileAttributeViewImpl(UnixPath file, boolean followLinks) + { + this.file = file; + this.followLinks = followLinks; + } + + int open() throws IOException { + int oflags = O_RDONLY; + if (!followLinks) + oflags |= O_NOFOLLOW; + try { + return openat(dfd, file.asByteArray(), oflags, 0); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return -1; // keep compiler happy + } + } + + private void checkWriteAccess() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + ds.directory().resolve(file).checkWrite(); + } + } + + @Override + public String name() { + return "basic"; + } + + @Override + public BasicFileAttributes readAttributes() throws IOException { + ds.readLock().lock(); + try { + if (!ds.isOpen()) + throw new ClosedDirectoryStreamException(); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (file == null) { + ds.directory().checkRead(); + } else { + ds.directory().resolve(file).checkRead(); + } + } + try { + UnixFileAttributes attrs = (file == null) ? + UnixFileAttributes.get(dfd) : + UnixFileAttributes.get(dfd, file, followLinks); + + // SECURITY: must return as BasicFileAttribute + return attrs.asBasicFileAttributes(); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } + } finally { + ds.readLock().unlock(); + } + } + + @Override + public void setTimes(Long lastModifiedTime, + Long lastAccessTime, + Long createTime, // ignore + TimeUnit unit) + throws IOException + { + // no effect + if (lastModifiedTime == null && lastAccessTime == null) { + return; + } + + checkWriteAccess(); + + ds.readLock().lock(); + try { + if (!ds.isOpen()) + throw new ClosedDirectoryStreamException(); + + int fd = (file == null) ? dfd : open(); + try { + UnixFileAttributes attrs = null; + + // if not changing both attributes then need existing attributes + if (lastModifiedTime == null || lastAccessTime == null) { + try { + attrs = UnixFileAttributes.get(fd); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + } + + // modified time = existing, now, or new value + long modTime; + if (lastModifiedTime == null) { + modTime = attrs.lastModifiedTime(); + } else { + if (lastModifiedTime >= 0L) { + modTime = TimeUnit.MILLISECONDS.convert(lastModifiedTime, unit); + } else { + if (lastModifiedTime != -1L) + throw new IllegalArgumentException(); + modTime = System.currentTimeMillis(); + } + } + + // access time = existing, now, or new value + long accTime; + if (lastAccessTime == null) { + accTime = attrs.lastAccessTime(); + } else { + if (lastAccessTime >= 0L) { + accTime = TimeUnit.MILLISECONDS.convert(lastAccessTime, unit); + } else { + if (lastAccessTime != -1L) + throw new IllegalArgumentException(); + accTime = System.currentTimeMillis(); + } + } + + try { + futimes(fd, accTime, modTime); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + } finally { + if (file != null) + UnixNativeDispatcher.close(fd); + } + } finally { + ds.readLock().unlock(); + } + } + } + + /** + * A PosixFileAttributeView implementation that using a dfd/name pair. + */ + private class PosixFileAttributeViewImpl + extends BasicFileAttributeViewImpl implements PosixFileAttributeView + { + private static final String PERMISSIONS_NAME = "permissions"; + private static final String OWNER_NAME = "owner"; + private static final String GROUP_NAME = "group"; + + PosixFileAttributeViewImpl(UnixPath file, boolean followLinks) { + super(file, followLinks); + } + + private void checkWriteAndUserAccess() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + super.checkWriteAccess(); + sm.checkPermission(new RuntimePermission("accessUserInformation")); + } + } + + @Override + public String name() { + return "posix"; + } + + @Override + public Object getAttribute(String attribute) throws IOException { + if (attribute.equals(PERMISSIONS_NAME)) + return readAttributes().permissions(); + if (attribute.equals(OWNER_NAME)) + return readAttributes().owner(); + if (attribute.equals(GROUP_NAME)) + return readAttributes().group(); + return super.getAttribute(attribute); + } + + @Override + @SuppressWarnings("unchecked") + public void setAttribute(String attribute, Object value) + throws IOException + { + if (attribute.equals(PERMISSIONS_NAME)) { + setPermissions((Set<PosixFilePermission>)value); + return; + } + if (attribute.equals(OWNER_NAME)) { + setOwner((UserPrincipal)value); + return; + } + if (attribute.equals(GROUP_NAME)) { + setGroup((GroupPrincipal)value); + return; + } + super.setAttribute(attribute, value); + } + + final void addPosixAttributesToBuilder(PosixFileAttributes attrs, + AttributesBuilder builder) + { + if (builder.match(PERMISSIONS_NAME)) + builder.add(PERMISSIONS_NAME, attrs.permissions()); + if (builder.match(OWNER_NAME)) + builder.add(OWNER_NAME, attrs.owner()); + if (builder.match(GROUP_NAME)) + builder.add(GROUP_NAME, attrs.group()); + } + + @Override + public Map<String,?> readAttributes(String first, String[] rest) + throws IOException + { + AttributesBuilder builder = AttributesBuilder.create(first, rest); + PosixFileAttributes attrs = readAttributes(); + addBasicAttributesToBuilder(attrs, builder); + addPosixAttributesToBuilder(attrs, builder); + return builder.unmodifiableMap(); + } + + @Override + public PosixFileAttributes readAttributes() throws IOException { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (file == null) + ds.directory().checkRead(); + else + ds.directory().resolve(file).checkRead(); + sm.checkPermission(new RuntimePermission("accessUserInformation")); + } + + ds.readLock().lock(); + try { + if (!ds.isOpen()) + throw new ClosedDirectoryStreamException(); + + try { + UnixFileAttributes attrs = (file == null) ? + UnixFileAttributes.get(dfd) : + UnixFileAttributes.get(dfd, file, followLinks); + return attrs; + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } + } finally { + ds.readLock().unlock(); + } + } + + @Override + public void setPermissions(Set<PosixFilePermission> perms) + throws IOException + { + // permission check + checkWriteAndUserAccess(); + + ds.readLock().lock(); + try { + if (!ds.isOpen()) + throw new ClosedDirectoryStreamException(); + + int fd = (file == null) ? dfd : open(); + try { + fchmod(fd, UnixFileModeAttribute.toUnixMode(perms)); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } finally { + if (file != null && fd >= 0) + UnixNativeDispatcher.close(fd); + } + } finally { + ds.readLock().unlock(); + } + } + + private void setOwners(int uid, int gid) throws IOException { + // permission check + checkWriteAndUserAccess(); + + ds.readLock().lock(); + try { + if (!ds.isOpen()) + throw new ClosedDirectoryStreamException(); + + int fd = (file == null) ? dfd : open(); + try { + fchown(fd, uid, gid); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } finally { + if (file != null && fd >= 0) + UnixNativeDispatcher.close(fd); + } + } finally { + ds.readLock().unlock(); + } + } + + @Override + public UserPrincipal getOwner() throws IOException { + return readAttributes().owner(); + } + + @Override + public void setOwner(UserPrincipal owner) + throws IOException + { + if (!(owner instanceof UnixUserPrincipals.User)) + throw new ProviderMismatchException(); + if (owner instanceof UnixUserPrincipals.Group) + throw new IOException("'owner' parameter can't be a group"); + int uid = ((UnixUserPrincipals.User)owner).uid(); + setOwners(uid, -1); + } + + @Override + public void setGroup(GroupPrincipal group) + throws IOException + { + if (!(group instanceof UnixUserPrincipals.Group)) + throw new ProviderMismatchException(); + int gid = ((UnixUserPrincipals.Group)group).gid(); + setOwners(-1, gid); + } + } +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixUriUtils.java b/jdk/src/solaris/classes/sun/nio/fs/UnixUriUtils.java new file mode 100644 index 00000000000..bf3c78d6352 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixUriUtils.java @@ -0,0 +1,216 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.net.URI; +import java.net.URISyntaxException; + +/** + * Unix specific Path <--> URI conversion + */ + +class UnixUriUtils { + private UnixUriUtils() { } + + /** + * Converts URI to Path + */ + static UnixPath fromUri(UnixFileSystem fs, URI uri) { + if (!uri.isAbsolute()) + throw new IllegalArgumentException("URI is not absolute"); + if (uri.isOpaque()) + throw new IllegalArgumentException("URI is not hierarchical"); + String scheme = uri.getScheme(); + if ((scheme == null) || !scheme.equalsIgnoreCase("file")) + throw new IllegalArgumentException("URI scheme is not \"file\""); + if (uri.getAuthority() != null) + throw new IllegalArgumentException("URI has an authority component"); + if (uri.getFragment() != null) + throw new IllegalArgumentException("URI has a fragment component"); + if (uri.getQuery() != null) + throw new IllegalArgumentException("URI has a query component"); + + String path = uri.getPath(); + if (path.equals("")) + throw new IllegalArgumentException("URI path component is empty"); + if (path.endsWith("/") && (path.length() > 1)) { + // "/foo/" --> "/foo", but "/" --> "/" + path = path.substring(0, path.length() - 1); + } + + // preserve bytes + byte[] result = new byte[path.length()]; + for (int i=0; i<path.length(); i++) { + byte v = (byte)(path.charAt(i)); + if (v == 0) + throw new IllegalArgumentException("Nul character not allowed"); + result[i] = v; + } + return new UnixPath(fs, result); + } + + /** + * Converts Path to URI + */ + static URI toUri(UnixPath up) { + byte[] path = up.toAbsolutePath().asByteArray(); + StringBuilder sb = new StringBuilder("file:///"); + assert path[0] == '/'; + for (int i=1; i<path.length; i++) { + char c = (char)(path[i] & 0xff); + if (match(c, L_PATH, H_PATH)) { + sb.append(c); + } else { + sb.append('%'); + sb.append(hexDigits[(c >> 4) & 0x0f]); + sb.append(hexDigits[(c >> 0) & 0x0f]); + } + } + + // trailing slash if directory + if (sb.charAt(sb.length()-1) != '/') { + try { + if (UnixFileAttributes.get(up, true).isDirectory()) + sb.append('/'); + } catch (UnixException x) { + // ignore + } + } + + try { + return new URI(sb.toString()); + } catch (URISyntaxException x) { + throw new AssertionError(x); // should not happen + } + } + + // The following is copied from java.net.URI + + // Compute the low-order mask for the characters in the given string + private static long lowMask(String chars) { + int n = chars.length(); + long m = 0; + for (int i = 0; i < n; i++) { + char c = chars.charAt(i); + if (c < 64) + m |= (1L << c); + } + return m; + } + + // Compute the high-order mask for the characters in the given string + private static long highMask(String chars) { + int n = chars.length(); + long m = 0; + for (int i = 0; i < n; i++) { + char c = chars.charAt(i); + if ((c >= 64) && (c < 128)) + m |= (1L << (c - 64)); + } + return m; + } + + // Compute a low-order mask for the characters + // between first and last, inclusive + private static long lowMask(char first, char last) { + long m = 0; + int f = Math.max(Math.min(first, 63), 0); + int l = Math.max(Math.min(last, 63), 0); + for (int i = f; i <= l; i++) + m |= 1L << i; + return m; + } + + // Compute a high-order mask for the characters + // between first and last, inclusive + private static long highMask(char first, char last) { + long m = 0; + int f = Math.max(Math.min(first, 127), 64) - 64; + int l = Math.max(Math.min(last, 127), 64) - 64; + for (int i = f; i <= l; i++) + m |= 1L << i; + return m; + } + + // Tell whether the given character is permitted by the given mask pair + private static boolean match(char c, long lowMask, long highMask) { + if (c < 64) + return ((1L << c) & lowMask) != 0; + if (c < 128) + return ((1L << (c - 64)) & highMask) != 0; + return false; + } + + // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | + // "8" | "9" + private static final long L_DIGIT = lowMask('0', '9'); + private static final long H_DIGIT = 0L; + + // upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | + // "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | + // "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" + private static final long L_UPALPHA = 0L; + private static final long H_UPALPHA = highMask('A', 'Z'); + + // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | + // "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | + // "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" + private static final long L_LOWALPHA = 0L; + private static final long H_LOWALPHA = highMask('a', 'z'); + + // alpha = lowalpha | upalpha + private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA; + private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA; + + // alphanum = alpha | digit + private static final long L_ALPHANUM = L_DIGIT | L_ALPHA; + private static final long H_ALPHANUM = H_DIGIT | H_ALPHA; + + // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | + // "(" | ")" + private static final long L_MARK = lowMask("-_.!~*'()"); + private static final long H_MARK = highMask("-_.!~*'()"); + + // unreserved = alphanum | mark + private static final long L_UNRESERVED = L_ALPHANUM | L_MARK; + private static final long H_UNRESERVED = H_ALPHANUM | H_MARK; + + // pchar = unreserved | escaped | + // ":" | "@" | "&" | "=" | "+" | "$" | "," + private static final long L_PCHAR + = L_UNRESERVED | lowMask(":@&=+$,"); + private static final long H_PCHAR + = H_UNRESERVED | highMask(":@&=+$,"); + + // All valid path characters + private static final long L_PATH = L_PCHAR | lowMask(";/"); + private static final long H_PATH = H_PCHAR | highMask(";/"); + + private final static char[] hexDigits = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; +} diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixUserPrincipals.java b/jdk/src/solaris/classes/sun/nio/fs/UnixUserPrincipals.java new file mode 100644 index 00000000000..88dfe9c4d90 --- /dev/null +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixUserPrincipals.java @@ -0,0 +1,175 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.io.IOException; +import static sun.nio.fs.UnixNativeDispatcher.*; + +/** + * Unix implementation of java.nio.file.attribute.UserPrincipal + */ + +class UnixUserPrincipals { + private static User createSpecial(String name) { return new User(-1, name); } + + static final User SPECIAL_OWNER = createSpecial("OWNER@"); + static final User SPECIAL_GROUP = createSpecial("GROUP@"); + static final User SPECIAL_EVERYONE = createSpecial("EVERYONE@"); + + static class User implements UserPrincipal { + private final int id; // uid or gid + private final boolean isGroup; + private final String name; + + private User(int id, boolean isGroup, String name) { + this.id = id; + this.isGroup = isGroup; + this.name = name; + } + + User(int id, String name) { + this(id, false, name); + } + + int uid() { + if (isGroup) + throw new AssertionError(); + return id; + } + + int gid() { + if (isGroup) + return id; + throw new AssertionError(); + } + + boolean isSpecial() { + return id == -1; + } + + @Override + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (!(obj instanceof User)) + return false; + User other = (User)obj; + if ((this.id != other.id) || + (this.isGroup != other.isGroup)) { + return false; + } + // specials + if (this.id == -1 && other.id == -1) + return this.name.equals(other.name); + + return true; + } + + @Override + public int hashCode() { + return (id != -1) ? id : name.hashCode(); + } + } + + static class Group extends User implements GroupPrincipal { + Group(int id, String name) { + super(id, true, name); + } + } + + // return UserPrincipal representing given uid + static User fromUid(int uid) { + String name = null; + try { + name = new String(getpwuid(uid)); + } catch (UnixException x) { + name = Integer.toString(uid); + } + return new User(uid, name); + } + + // return GroupPrincipal representing given gid + static Group fromGid(int gid) { + String name = null; + try { + name = new String(getgrgid(gid)); + } catch (UnixException x) { + name = Integer.toString(gid); + } + return new Group(gid, name); + } + + // lookup user or group name + private static int lookupName(String name, boolean isGroup) + throws IOException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("lookupUserInformation")); + } + int id = -1; + try { + id = (isGroup) ? getgrnam(name) : getpwnam(name); + } catch (UnixException x) { + throw new IOException(name + ": " + x.errorString()); + } + if (id == -1) + throw new UserPrincipalNotFoundException(name); + return id; + + } + + // lookup user name + static UserPrincipal lookupUser(String name) throws IOException { + if (name.equals(SPECIAL_OWNER.getName())) + return SPECIAL_OWNER; + if (name.equals(SPECIAL_GROUP.getName())) + return SPECIAL_GROUP; + if (name.equals(SPECIAL_EVERYONE.getName())) + return SPECIAL_EVERYONE; + int uid = lookupName(name, false); + return new User(uid, name); + } + + // lookup group name + static GroupPrincipal lookupGroup(String group) + throws IOException + { + int gid = lookupName(group, true); + return new Group(gid, group); + } +} diff --git a/jdk/src/solaris/classes/sun/print/IPPPrintService.java b/jdk/src/solaris/classes/sun/print/IPPPrintService.java index 07b68b18fa8..ec5344ae379 100644 --- a/jdk/src/solaris/classes/sun/print/IPPPrintService.java +++ b/jdk/src/solaris/classes/sun/print/IPPPrintService.java @@ -661,6 +661,12 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { } } } else if (category == OrientationRequested.class) { + if (flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) || + flavor.equals(DocFlavor.URL.POSTSCRIPT) || + flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT)) { + return null; + } + boolean revPort = false; OrientationRequested[] orientSup = null; diff --git a/jdk/src/solaris/classes/sun/print/UnixPrintJob.java b/jdk/src/solaris/classes/sun/print/UnixPrintJob.java index 1a96e92f2c8..b4da652a8fc 100644 --- a/jdk/src/solaris/classes/sun/print/UnixPrintJob.java +++ b/jdk/src/solaris/classes/sun/print/UnixPrintJob.java @@ -362,10 +362,10 @@ public class UnixPrintJob implements CancelablePrintJob { mOptions += " number-up="+nUp.getValue(); } - if (orient == OrientationRequested.LANDSCAPE && + if (orient != OrientationRequested.PORTRAIT && (flavor != null) && !flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE)) { - mOptions += " landscape"; + mOptions += " orientation-requested="+orient.getValue(); } if (sides != null) { diff --git a/jdk/src/solaris/lib/sdp/sdp.conf.template b/jdk/src/solaris/lib/sdp/sdp.conf.template new file mode 100644 index 00000000000..71cb5c2ce84 --- /dev/null +++ b/jdk/src/solaris/lib/sdp/sdp.conf.template @@ -0,0 +1,30 @@ +# +# Configuration file to enable InfiniBand Sockets Direct Protocol. +# +# Each line that does not start with a comment (#) is a rule to indicate when +# the SDP transport protocol should be used. The format of a rule is as follows: +# ("bind"|"connect") 1*LWSP-char (hostname|ipaddress["/"prefix]) 1*LWSP-char ("*"|port)["-"("*"|port)] +# +# A "bind" rule indicates that the SDP protocol transport should be used when +# a TCP socket binds to an address/port that matches the rule. A "connect" rule +# indicates that the SDP protocol transport should be used when an unbound +# TCP socket attempts to connect to an address/port that matches the rule. +# Addresses may be specified as hostnames or literal Internet Protocol (IP) +# addresses. When a literal IP address is used then a prefix length may be used +# to indicate the number of bits for matching (useful when a block of addresses +# or subnet is allocated to the InfiniBand fabric). + +# Use SDP for all sockets that bind to specific local addresses +#bind 192.168.1.1 * +#bind fe80::21b:24ff:fe3d:7896 * + +# Use SDP for all sockets that bind to the wildcard address in a port range +#bind 0.0.0.0 5000-5999 +#bind ::0 5000-5999 + +# Use SDP when connecting to all application services on 192.168.1.* +#connect 192.168.1.0/24 1024-* + +# Use SDP when connecting to the http server or MySQL database on hpccluster. +#connect hpccluster.foo.com 80 +#connect hpccluster.foo.com 3306 diff --git a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c index a41aa96e10f..9e3cca486db 100644 --- a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c +++ b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c @@ -165,16 +165,18 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); CHECK_NULL_RETURN(hostname, NULL); +#ifdef __solaris__ /* * Workaround for Solaris bug 4160367 - if a hostname contains a * white space then 0.0.0.0 is returned */ - if (isspace(hostname[0])) { + if (isspace((unsigned char)hostname[0])) { JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", (char *)hostname); JNU_ReleaseStringPlatformChars(env, host, hostname); return NULL; } +#endif /* Try once, with our static buffer. */ #ifdef __GLIBC__ @@ -325,7 +327,8 @@ static jboolean ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout, struct sockaddr_in* netif, jint ttl) { jint size; - jint n, len, hlen1, icmplen; + jint n, hlen1, icmplen; + socklen_t len; char sendbuf[1500]; char recvbuf[1500]; struct icmp *icmp; diff --git a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c index 181307fcba8..5ecedbc6c4f 100644 --- a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c +++ b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c @@ -196,16 +196,18 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_UNSPEC; +#ifdef __solaris__ /* * Workaround for Solaris bug 4160367 - if a hostname contains a * white space then 0.0.0.0 is returned */ - if (isspace(hostname[0])) { + if (isspace((unsigned char)hostname[0])) { JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", (char *)hostname); JNU_ReleaseStringPlatformChars(env, host, hostname); return NULL; } +#endif error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res); @@ -455,7 +457,8 @@ static jboolean ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout, struct sockaddr_in6* netif, jint ttl) { jint size; - jint n, len; + jint n; + socklen_t len; char sendbuf[1500]; unsigned char recvbuf[1500]; struct icmp6_hdr *icmp6; diff --git a/jdk/src/solaris/native/java/net/NetworkInterface.c b/jdk/src/solaris/native/java/net/NetworkInterface.c index 14273f5c132..9580c816455 100644 --- a/jdk/src/solaris/native/java/net/NetworkInterface.c +++ b/jdk/src/solaris/native/java/net/NetworkInterface.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -969,13 +969,39 @@ netif *addif(JNIEnv *env, netif *ifs, char *if_name, int index, int family, // Got access to parent, so create it if necessary. strcpy(vname, name); *unit = '\0'; - } - else { + } else { +#if defined(__solaris__) && defined(AF_INET6) + struct lifreq lifr; + memset((char *) &lifr, 0, sizeof(lifr)); + strcpy(lifr.lifr_name, vname); + + /* Try with an IPv6 socket in case the interface has only IPv6 + * addresses assigned to it */ + close(sock); + sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0); + + if (sock < 0) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", + "Socket creation failed"); + return ifs; /* return untouched list */ + } + + if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) >= 0) { + // Got access to parent, so create it if necessary. + strcpy(vname, name); + *unit = '\0'; + } else { + // failed to access parent interface do not create parent. + // We are a virtual interface with no parent. + isVirtual = 1; + vname[0] = 0; + } +#else // failed to access parent interface do not create parent. // We are a virtual interface with no parent. isVirtual = 1; - vname[0] = 0; +#endif } } close(sock); diff --git a/jdk/src/solaris/native/sun/awt/gtk2_interface.c b/jdk/src/solaris/native/sun/awt/gtk2_interface.c index cfbc5ef6f6e..1afeeef173b 100644 --- a/jdk/src/solaris/native/sun/awt/gtk2_interface.c +++ b/jdk/src/solaris/native/sun/awt/gtk2_interface.c @@ -93,6 +93,7 @@ static int gtk2_pixbuf_height = 0; /* Static buffer for conversion from java.lang.String to UTF-8 */ static char convertionBuffer[CONV_BUFFER_SIZE]; +static gboolean new_combo = TRUE; const char ENV_PREFIX[] = "GTK_MODULES="; /*******************/ @@ -608,6 +609,7 @@ gboolean gtk2_load() dlsym(gtk2_libhandle, "gtk_combo_box_entry_new"); if (fp_gtk_combo_box_entry_new == NULL) { fp_gtk_combo_box_entry_new = dl_symbol("gtk_combo_new"); + new_combo = FALSE; } fp_gtk_separator_tool_item_new = @@ -1423,17 +1425,13 @@ static GtkWidget *gtk2_get_widget(WidgetType widget_type) */ GtkWidget *combo = (*fp_gtk_combo_box_entry_new)(); - if (widget_type == COMBO_BOX_TEXT_FIELD) - (*fp_gtk_container_add)((GtkContainer *)combo, result); - else - { + if (new_combo && widget_type == COMBO_BOX_ARROW_BUTTON) { (*fp_gtk_widget_set_parent)(result, combo); ((GtkBin*)combo)->child = result; + } else { + (*fp_gtk_container_add)((GtkContainer *)combo, result); } - (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, combo); - (*fp_gtk_widget_realize)(result); - return result; } else if (widget_type != TOOL_TIP && widget_type != INTERNAL_FRAME && diff --git a/jdk/src/solaris/native/sun/net/spi/SdpProvider.c b/jdk/src/solaris/native/sun/net/spi/SdpProvider.c new file mode 100644 index 00000000000..00d7f4ba6dc --- /dev/null +++ b/jdk/src/solaris/native/sun/net/spi/SdpProvider.c @@ -0,0 +1,74 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#if defined(__solaris__) && !defined(PROTO_SDP) +#define PROTO_SDP 257 +#endif + +#include "jni.h" +#include "jni_util.h" +#include "net_util.h" + +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + +JNIEXPORT void JNICALL +Java_sun_net_spi_SdpProvider_convert(JNIEnv *env, jclass cls, jint fd) +{ +#ifdef PROTO_SDP + int domain = ipv6_available() ? AF_INET6 : AF_INET; + int s = socket(domain, SOCK_STREAM, PROTO_SDP); + if (s < 0) { + JNU_ThrowIOExceptionWithLastError(env, "socket"); + } else { + int arg, len, res; + struct linger linger; + + /* copy socket options that are relevant to SDP */ + len = sizeof(arg); + if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0) + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len); + len = sizeof(arg); + if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0) + setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len); + len = sizeof(linger); + if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (void*)&linger, &len) == 0) + setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&linger, len); + + RESTARTABLE(dup2(s, fd), res); + if (res < 0) + JNU_ThrowIOExceptionWithLastError(env, "dup2"); + RESTARTABLE(close(s), res); + } +#else + JNU_ThrowInternalError(env, "should not reach here"); +#endif +} diff --git a/jdk/src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c b/jdk/src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c index 090c77e6774..fa36f612bff 100644 --- a/jdk/src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c +++ b/jdk/src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c @@ -28,6 +28,7 @@ #include "jvm.h" #include "jlong.h" #include "sun_nio_ch_DevPollArrayWrapper.h" +#include "java_lang_Integer.h" #include <sys/poll.h> #include <sys/resource.h> #include <unistd.h> @@ -192,7 +193,11 @@ Java_sun_nio_ch_DevPollArrayWrapper_fdLimit(JNIEnv *env, jclass this) JNU_ThrowIOExceptionWithLastError(env, "getrlimit failed"); } - return (jint)rlp.rlim_max; + if (rlp.rlim_max < 0 || rlp.rlim_max > java_lang_Integer_MAX_VALUE) { + return java_lang_Integer_MAX_VALUE; + } else { + return (jint)rlp.rlim_max; + } } JNIEXPORT void JNICALL diff --git a/jdk/src/solaris/native/sun/nio/ch/EPoll.c b/jdk/src/solaris/native/sun/nio/ch/EPoll.c new file mode 100644 index 00000000000..fc9cab72cc2 --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/ch/EPoll.c @@ -0,0 +1,151 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio_util.h" + +#include "sun_nio_ch_EPoll.h" + +#include <dlfcn.h> +#include <unistd.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* epoll_wait(2) man page */ + +typedef union epoll_data { + void *ptr; + int fd; + __uint32_t u32; + __uint64_t u64; +} epoll_data_t; + +struct epoll_event { + __uint32_t events; /* Epoll events */ + epoll_data_t data; /* User data variable */ +} __attribute__ ((__packed__)); + +#ifdef __cplusplus +} +#endif + +/* + * epoll event notification is new in 2.6 kernel. As the offical build + * platform for the JDK is on a 2.4-based distribution then we must + * obtain the addresses of the epoll functions dynamically. + */ +typedef int (*epoll_create_t)(int size); +typedef int (*epoll_ctl_t) (int epfd, int op, int fd, struct epoll_event *event); +typedef int (*epoll_wait_t) (int epfd, struct epoll_event *events, int maxevents, int timeout); + +static epoll_create_t epoll_create_func; +static epoll_ctl_t epoll_ctl_func; +static epoll_wait_t epoll_wait_func; + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_EPoll_init(JNIEnv *env, jclass this) +{ + epoll_create_func = (epoll_create_t) dlsym(RTLD_DEFAULT, "epoll_create"); + epoll_ctl_func = (epoll_ctl_t) dlsym(RTLD_DEFAULT, "epoll_ctl"); + epoll_wait_func = (epoll_wait_t) dlsym(RTLD_DEFAULT, "epoll_wait"); + + if ((epoll_create_func == NULL) || (epoll_ctl_func == NULL) || + (epoll_wait_func == NULL)) { + JNU_ThrowInternalError(env, "unable to get address of epoll functions, pre-2.6 kernel?"); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_eventSize(JNIEnv* env, jclass this) +{ + return sizeof(struct epoll_event); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_eventsOffset(JNIEnv* env, jclass this) +{ + return offsetof(struct epoll_event, events); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_dataOffset(JNIEnv* env, jclass this) +{ + return offsetof(struct epoll_event, data); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_epollCreate(JNIEnv *env, jclass c) { + /* + * epoll_create expects a size as a hint to the kernel about how to + * dimension internal structures. We can't predict the size in advance. + */ + int epfd = (*epoll_create_func)(256); + if (epfd < 0) { + JNU_ThrowIOExceptionWithLastError(env, "epoll_create failed"); + } + return epfd; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_epollCtl(JNIEnv *env, jclass c, jint epfd, + jint opcode, jint fd, jint events) +{ + struct epoll_event event; + int res; + + event.events = events; + event.data.fd = fd; + + RESTARTABLE((*epoll_ctl_func)(epfd, (int)opcode, (int)fd, &event), res); + + return (res == 0) ? 0 : errno; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_epollWait(JNIEnv *env, jclass c, + jint epfd, jlong address, jint numfds) +{ + struct epoll_event *events = jlong_to_ptr(address); + int res; + + RESTARTABLE((*epoll_wait_func)(epfd, events, numfds, -1), res); + if (res < 0) { + JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed"); + } + return res; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_EPoll_close0(JNIEnv *env, jclass c, jint epfd) { + int res; + RESTARTABLE(close(epfd), res); +} diff --git a/jdk/src/solaris/native/sun/nio/ch/EPollPort.c b/jdk/src/solaris/native/sun/nio/ch/EPollPort.c new file mode 100644 index 00000000000..8d34dd8dd4b --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/ch/EPollPort.c @@ -0,0 +1,76 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio_util.h" + +#include "sun_nio_ch_EPollPort.h" + +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> + +JNIEXPORT void JNICALL +Java_sun_nio_ch_EPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) { + int sp[2]; + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); + } else { + jint res[2]; + res[0] = (jint)sp[0]; + res[1] = (jint)sp[1]; + (*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_EPollPort_interrupt(JNIEnv *env, jclass c, jint fd) { + int res; + int buf[1]; + buf[0] = 1; + RESTARTABLE(write(fd, buf, 1), res); + if (res < 0) { + JNU_ThrowIOExceptionWithLastError(env, "write failed"); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_EPollPort_drain1(JNIEnv *env, jclass cl, jint fd) { + int res; + char buf[1]; + RESTARTABLE(read(fd, buf, 1), res); + if (res < 0) { + JNU_ThrowIOExceptionWithLastError(env, "drain1 failed"); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_EPollPort_close0(JNIEnv *env, jclass c, jint fd) { + int res; + RESTARTABLE(close(fd), res); +} diff --git a/jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c b/jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c index b42c899e521..c1c3cc9e826 100644 --- a/jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c +++ b/jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ #include <sys/stat.h> #include "sun_nio_ch_FileChannelImpl.h" #include "java_lang_Integer.h" -#include "java_lang_Long.h" #include "nio.h" #include "nio_util.h" #include <dlfcn.h> @@ -145,32 +144,6 @@ Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this, } -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileChannelImpl_truncate0(JNIEnv *env, jobject this, - jobject fdo, jlong size) -{ - return handle(env, - ftruncate64(fdval(env, fdo), size), - "Truncation failed"); -} - - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileChannelImpl_force0(JNIEnv *env, jobject this, - jobject fdo, jboolean md) -{ - jint fd = fdval(env, fdo); - int result = 0; - - if (md == JNI_FALSE) { - result = fdatasync(fd); - } else { - result = fsync(fd); - } - return handle(env, result, "Force failed"); -} - - JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this, jobject fdo, jlong offset) @@ -187,17 +160,6 @@ Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this, } -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileChannelImpl_size0(JNIEnv *env, jobject this, jobject fdo) -{ - struct stat64 fbuf; - - if (fstat64(fdval(env, fdo), &fbuf) < 0) - return handle(env, -1, "Size failed"); - return fbuf.st_size; -} - - JNIEXPORT void JNICALL Java_sun_nio_ch_FileChannelImpl_close0(JNIEnv *env, jobject this, jobject fdo) { @@ -269,6 +231,8 @@ Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, if (result < 0) { if (errno == EAGAIN) return IOS_UNAVAILABLE; + if (errno == EOPNOTSUPP) + return IOS_UNSUPPORTED_CASE; if ((errno == EINVAL) && ((ssize_t)count >= 0)) return IOS_UNSUPPORTED_CASE; if (errno == EINTR) @@ -280,65 +244,3 @@ Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, } #endif } - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileChannelImpl_lock0(JNIEnv *env, jobject this, jobject fdo, - jboolean block, jlong pos, jlong size, - jboolean shared) -{ - jint fd = fdval(env, fdo); - jint lockResult = 0; - int cmd = 0; - struct flock64 fl; - - fl.l_whence = SEEK_SET; - if (size == (jlong)java_lang_Long_MAX_VALUE) { - fl.l_len = (off64_t)0; - } else { - fl.l_len = (off64_t)size; - } - fl.l_start = (off64_t)pos; - if (shared == JNI_TRUE) { - fl.l_type = F_RDLCK; - } else { - fl.l_type = F_WRLCK; - } - if (block == JNI_TRUE) { - cmd = F_SETLKW64; - } else { - cmd = F_SETLK64; - } - lockResult = fcntl(fd, cmd, &fl); - if (lockResult < 0) { - if ((cmd == F_SETLK64) && (errno == EAGAIN)) - return sun_nio_ch_FileChannelImpl_NO_LOCK; - if (errno == EINTR) - return sun_nio_ch_FileChannelImpl_INTERRUPTED; - JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); - } - return 0; -} - - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileChannelImpl_release0(JNIEnv *env, jobject this, - jobject fdo, jlong pos, jlong size) -{ - jint fd = fdval(env, fdo); - jint lockResult = 0; - struct flock64 fl; - int cmd = F_SETLK64; - - fl.l_whence = SEEK_SET; - if (size == (jlong)java_lang_Long_MAX_VALUE) { - fl.l_len = (off64_t)0; - } else { - fl.l_len = (off64_t)size; - } - fl.l_start = (off64_t)pos; - fl.l_type = F_UNLCK; - lockResult = fcntl(fd, cmd, &fl); - if (lockResult < 0) { - JNU_ThrowIOExceptionWithLastError(env, "Release failed"); - } -} diff --git a/jdk/src/solaris/native/sun/nio/ch/FileDispatcher.c b/jdk/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c similarity index 50% rename from jdk/src/solaris/native/sun/nio/ch/FileDispatcher.c rename to jdk/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c index fd3c0e3d6ee..ed658893338 100644 --- a/jdk/src/solaris/native/sun/nio/ch/FileDispatcher.c +++ b/jdk/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,13 @@ #include "jni_util.h" #include "jvm.h" #include "jlong.h" -#include "sun_nio_ch_FileDispatcher.h" +#include "sun_nio_ch_FileDispatcherImpl.h" +#include "java_lang_Long.h" #include <sys/types.h> #include <sys/socket.h> #include <fcntl.h> #include <sys/uio.h> +#include "nio.h" #include "nio_util.h" @@ -40,7 +42,7 @@ static int preCloseFD = -1; /* File descriptor to which we dup other fd's JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcher_init(JNIEnv *env, jclass cl) +Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { @@ -52,7 +54,7 @@ Java_sun_nio_ch_FileDispatcher_init(JNIEnv *env, jclass cl) } JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcher_read0(JNIEnv *env, jclass clazz, +Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { jint fd = fdval(env, fdo); @@ -62,7 +64,7 @@ Java_sun_nio_ch_FileDispatcher_read0(JNIEnv *env, jclass clazz, } JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcher_pread0(JNIEnv *env, jclass clazz, jobject fdo, +Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len, jlong offset) { jint fd = fdval(env, fdo); @@ -72,7 +74,7 @@ Java_sun_nio_ch_FileDispatcher_pread0(JNIEnv *env, jclass clazz, jobject fdo, } JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcher_readv0(JNIEnv *env, jclass clazz, +Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { jint fd = fdval(env, fdo); @@ -84,7 +86,7 @@ Java_sun_nio_ch_FileDispatcher_readv0(JNIEnv *env, jclass clazz, } JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcher_write0(JNIEnv *env, jclass clazz, +Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { jint fd = fdval(env, fdo); @@ -94,7 +96,7 @@ Java_sun_nio_ch_FileDispatcher_write0(JNIEnv *env, jclass clazz, } JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcher_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, +Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len, jlong offset) { jint fd = fdval(env, fdo); @@ -104,7 +106,7 @@ Java_sun_nio_ch_FileDispatcher_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, } JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcher_writev0(JNIEnv *env, jclass clazz, +Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { jint fd = fdval(env, fdo); @@ -115,6 +117,113 @@ Java_sun_nio_ch_FileDispatcher_writev0(JNIEnv *env, jclass clazz, return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE); } +static jlong +handle(JNIEnv *env, jlong rv, char *msg) +{ + if (rv >= 0) + return rv; + if (errno == EINTR) + return IOS_INTERRUPTED; + JNU_ThrowIOExceptionWithLastError(env, msg); + return IOS_THROWN; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, + jobject fdo, jboolean md) +{ + jint fd = fdval(env, fdo); + int result = 0; + + if (md == JNI_FALSE) { + result = fdatasync(fd); + } else { + result = fsync(fd); + } + return handle(env, result, "Force failed"); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, + jobject fdo, jlong size) +{ + return handle(env, + ftruncate64(fdval(env, fdo), size), + "Truncation failed"); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) +{ + struct stat64 fbuf; + + if (fstat64(fdval(env, fdo), &fbuf) < 0) + return handle(env, -1, "Size failed"); + return fbuf.st_size; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, + jboolean block, jlong pos, jlong size, + jboolean shared) +{ + jint fd = fdval(env, fdo); + jint lockResult = 0; + int cmd = 0; + struct flock64 fl; + + fl.l_whence = SEEK_SET; + if (size == (jlong)java_lang_Long_MAX_VALUE) { + fl.l_len = (off64_t)0; + } else { + fl.l_len = (off64_t)size; + } + fl.l_start = (off64_t)pos; + if (shared == JNI_TRUE) { + fl.l_type = F_RDLCK; + } else { + fl.l_type = F_WRLCK; + } + if (block == JNI_TRUE) { + cmd = F_SETLKW64; + } else { + cmd = F_SETLK64; + } + lockResult = fcntl(fd, cmd, &fl); + if (lockResult < 0) { + if ((cmd == F_SETLK64) && (errno == EAGAIN)) + return sun_nio_ch_FileDispatcherImpl_NO_LOCK; + if (errno == EINTR) + return sun_nio_ch_FileDispatcherImpl_INTERRUPTED; + JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); + } + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, + jobject fdo, jlong pos, jlong size) +{ + jint fd = fdval(env, fdo); + jint lockResult = 0; + struct flock64 fl; + int cmd = F_SETLK64; + + fl.l_whence = SEEK_SET; + if (size == (jlong)java_lang_Long_MAX_VALUE) { + fl.l_len = (off64_t)0; + } else { + fl.l_len = (off64_t)size; + } + fl.l_start = (off64_t)pos; + fl.l_type = F_UNLCK; + lockResult = fcntl(fd, cmd, &fl); + if (lockResult < 0) { + JNU_ThrowIOExceptionWithLastError(env, "Release failed"); + } +} + + static void closeFileDescriptor(JNIEnv *env, int fd) { if (fd != -1) { int result = close(fd); @@ -124,14 +233,14 @@ static void closeFileDescriptor(JNIEnv *env, int fd) { } JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcher_close0(JNIEnv *env, jclass clazz, jobject fdo) +Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) { jint fd = fdval(env, fdo); closeFileDescriptor(env, fd); } JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcher_preClose0(JNIEnv *env, jclass clazz, jobject fdo) +Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo) { jint fd = fdval(env, fdo); if (preCloseFD >= 0) { @@ -141,7 +250,7 @@ Java_sun_nio_ch_FileDispatcher_preClose0(JNIEnv *env, jclass clazz, jobject fdo) } JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcher_closeIntFD(JNIEnv *env, jclass clazz, jint fd) +Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd) { closeFileDescriptor(env, fd); } diff --git a/jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c b/jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c index 1524326b6b0..812ff4bedd8 100644 --- a/jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c +++ b/jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2001 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ #include "jni_util.h" #include "jvm.h" #include "jlong.h" -#include "sun_nio_ch_FileDispatcher.h" /* this is a fake c file to make the build happy since there is no real SocketDispatcher.c file on Solaris but there is on windows. */ diff --git a/jdk/src/solaris/native/sun/nio/ch/SolarisEventPort.c b/jdk/src/solaris/native/sun/nio/ch/SolarisEventPort.c new file mode 100644 index 00000000000..649475946ab --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/ch/SolarisEventPort.c @@ -0,0 +1,120 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio_util.h" + +#include <stdlib.h> +#include <dlfcn.h> +#include <sys/types.h> +#include <port.h> // Solaris 10 + +#include "sun_nio_ch_SolarisEventPort.h" + +JNIEXPORT void JNICALL +Java_sun_nio_ch_SolarisEventPort_init(JNIEnv *env, jclass clazz) +{ +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_SolarisEventPort_portCreate + (JNIEnv* env, jclass clazz) +{ + int port = port_create(); + if (port == -1) { + JNU_ThrowIOExceptionWithLastError(env, "port_create"); + } + return (jint)port; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_SolarisEventPort_portClose + (JNIEnv* env, jclass clazz, jint port) +{ + int res; + RESTARTABLE(close(port), res); +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_SolarisEventPort_portAssociate + (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events) +{ + uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress); + + if (port_associate((int)port, (int)source, object, (int)events, NULL) == -1) { + JNU_ThrowIOExceptionWithLastError(env, "port_associate"); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_SolarisEventPort_portDissociate + (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress) +{ + uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress); + + if (port_dissociate((int)port, (int)source, object) == -1) { + JNU_ThrowIOExceptionWithLastError(env, "port_dissociate"); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_SolarisEventPort_portSend(JNIEnv* env, jclass clazz, + jint port, jint events) +{ + if (port_send((int)port, (int)events, NULL) == -1) { + JNU_ThrowIOExceptionWithLastError(env, "port_send"); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_SolarisEventPort_portGet(JNIEnv* env, jclass clazz, + jint port, jlong eventAddress) +{ + int res; + port_event_t* ev = (port_event_t*)jlong_to_ptr(eventAddress); + + RESTARTABLE(port_get((int)port, ev, NULL), res); + if (res == -1) { + JNU_ThrowIOExceptionWithLastError(env, "port_get"); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_SolarisEventPort_portGetn(JNIEnv* env, jclass clazz, + jint port, jlong arrayAddress, jint max) +{ + int res; + uint_t n = 1; + port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress); + + RESTARTABLE(port_getn((int)port, list, (uint_t)max, &n, NULL), res); + if (res == -1) { + JNU_ThrowIOExceptionWithLastError(env, "port_getn"); + } + return (jint)n; +} diff --git a/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.c b/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.c new file mode 100644 index 00000000000..9c92cc2ad51 --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.c @@ -0,0 +1,47 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "sun_nio_ch_UnixAsynchronousServerSocketChannelImpl.h" + +extern void Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv* env, + jclass c); + +extern jint Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv* env, + jobject this, jobject ssfdo, jobject newfdo, jobjectArray isaa); + +JNIEXPORT void JNICALL +Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs(JNIEnv* env, + jclass c) +{ + Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(env, c); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0(JNIEnv* env, + jobject this, jobject ssfdo, jobject newfdo, jobjectArray isaa) +{ + return Java_sun_nio_ch_ServerSocketChannelImpl_accept0(env, this, + ssfdo, newfdo, isaa); +} diff --git a/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousSocketChannelImpl.c b/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousSocketChannelImpl.c new file mode 100644 index 00000000000..461d97f405c --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousSocketChannelImpl.c @@ -0,0 +1,53 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include "jni.h" +#include "jni_util.h" +#include "net_util.h" +#include "jlong.h" +#include "sun_nio_ch_UnixAsynchronousSocketChannelImpl.h" +#include "nio_util.h" +#include "nio.h" + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect(JNIEnv *env, + jobject this, int fd) +{ + int error = 0; + int n = sizeof(error); + int result; + + result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n); + if (result < 0) { + JNU_ThrowIOExceptionWithLastError(env, "getsockopt"); + } else { + if (error) + handleSocketError(env, error); + } +} diff --git a/jdk/src/solaris/native/sun/nio/fs/GnomeFileTypeDetector.c b/jdk/src/solaris/native/sun/nio/fs/GnomeFileTypeDetector.c new file mode 100644 index 00000000000..0a169a94d89 --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/fs/GnomeFileTypeDetector.c @@ -0,0 +1,205 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" + +#include <stdlib.h> +#include <dlfcn.h> +#include <link.h> + +#ifdef __solaris__ +#include <strings.h> +#endif + +#ifdef __linux__ +#include <string.h> +#endif + +/* Definitions for GIO */ + +#define G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "standard::content-type" + +typedef void* gpointer; +typedef struct _GFile GFile; +typedef struct _GFileInfo GFileInfo; +typedef struct _GCancellable GCancellable; +typedef struct _GError GError; + +typedef enum { + G_FILE_QUERY_INFO_NONE = 0 +} GFileQueryInfoFlags; + +typedef void (*g_type_init_func)(void); +typedef void (*g_object_unref_func)(gpointer object); +typedef GFile* (*g_file_new_for_path_func)(const char* path); +typedef GFileInfo* (*g_file_query_info_func)(GFile *file, + const char *attributes, GFileQueryInfoFlags flags, + GCancellable *cancellable, GError **error); +typedef char* (*g_file_info_get_content_type_func)(GFileInfo *info); + +static g_type_init_func g_type_init; +static g_object_unref_func g_object_unref; +static g_file_new_for_path_func g_file_new_for_path; +static g_file_query_info_func g_file_query_info; +static g_file_info_get_content_type_func g_file_info_get_content_type; + + +/* Definitions for GNOME VFS */ + +typedef int gboolean; + +typedef gboolean (*gnome_vfs_init_function)(void); +typedef const char* (*gnome_vfs_mime_type_from_name_function) + (const char* filename); + +static gnome_vfs_init_function gnome_vfs_init; +static gnome_vfs_mime_type_from_name_function gnome_vfs_mime_type_from_name; + + +#include "sun_nio_fs_GnomeFileTypeDetector.h" + + +JNIEXPORT jboolean JNICALL +Java_sun_nio_fs_GnomeFileTypeDetector_initializeGio + (JNIEnv* env, jclass this) +{ + void* gio_handle; + + gio_handle = dlopen("libgio-2.0.so", RTLD_LAZY); + if (gio_handle == NULL) { + gio_handle = dlopen("libgio-2.0.so.0", RTLD_LAZY); + if (gio_handle == NULL) { + return JNI_FALSE; + } + } + + g_type_init = (g_type_init_func)dlsym(gio_handle, "g_type_init"); + (*g_type_init)(); + + g_object_unref = (g_object_unref_func)dlsym(gio_handle, "g_object_unref"); + + g_file_new_for_path = + (g_file_new_for_path_func)dlsym(gio_handle, "g_file_new_for_path"); + + g_file_query_info = + (g_file_query_info_func)dlsym(gio_handle, "g_file_query_info"); + + g_file_info_get_content_type = (g_file_info_get_content_type_func) + dlsym(gio_handle, "g_file_info_get_content_type"); + + + if (g_type_init == NULL || + g_object_unref == NULL || + g_file_new_for_path == NULL || + g_file_query_info == NULL || + g_file_info_get_content_type == NULL) + { + dlclose(gio_handle); + return JNI_FALSE; + } + + (*g_type_init)(); + return JNI_TRUE; +} + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGio + (JNIEnv* env, jclass this, jlong pathAddress) +{ + char* path = (char*)jlong_to_ptr(pathAddress); + GFile* gfile; + GFileInfo* gfileinfo; + jbyteArray result = NULL; + + gfile = (*g_file_new_for_path)(path); + gfileinfo = (*g_file_query_info)(gfile, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + G_FILE_QUERY_INFO_NONE, NULL, NULL); + if (gfileinfo != NULL) { + const char* mime = (*g_file_info_get_content_type)(gfileinfo); + if (mime != NULL) { + jsize len = strlen(mime); + result = (*env)->NewByteArray(env, len); + if (result != NULL) { + (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)mime); + } + } + (*g_object_unref)(gfileinfo); + } + (*g_object_unref)(gfile); + + return result; +} + +JNIEXPORT jboolean JNICALL +Java_sun_nio_fs_GnomeFileTypeDetector_initializeGnomeVfs + (JNIEnv* env, jclass this) +{ + void* vfs_handle; + + vfs_handle = dlopen("libgnomevfs-2.so", RTLD_LAZY); + if (vfs_handle == NULL) { + vfs_handle = dlopen("libgnomevfs-2.so.0", RTLD_LAZY); + } + if (vfs_handle == NULL) { + return JNI_FALSE; + } + + gnome_vfs_init = (gnome_vfs_init_function)dlsym(vfs_handle, "gnome_vfs_init"); + gnome_vfs_mime_type_from_name = (gnome_vfs_mime_type_from_name_function) + dlsym(vfs_handle, "gnome_vfs_mime_type_from_name"); + + if (gnome_vfs_init == NULL || + gnome_vfs_mime_type_from_name == NULL) + { + dlclose(vfs_handle); + return JNI_FALSE; + } + + (*gnome_vfs_init)(); + return JNI_TRUE; +} + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGnomeVfs + (JNIEnv* env, jclass this, jlong pathAddress) +{ + char* path = (char*)jlong_to_ptr(pathAddress); + const char* mime = (*gnome_vfs_mime_type_from_name)(path); + + if (mime == NULL) { + return NULL; + } else { + jbyteArray result; + jsize len = strlen(mime); + result = (*env)->NewByteArray(env, len); + if (result != NULL) { + (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)mime); + } + return result; + } +} diff --git a/jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c b/jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c new file mode 100644 index 00000000000..8e4fa669611 --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c @@ -0,0 +1,160 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" + +#include <stdio.h> +#include <dlfcn.h> +#include <errno.h> +#include <mntent.h> + +#include "sun_nio_fs_LinuxNativeDispatcher.h" + +typedef size_t fgetxattr_func(int fd, const char* name, void* value, size_t size); +typedef int fsetxattr_func(int fd, const char* name, void* value, size_t size, int flags); +typedef int fremovexattr_func(int fd, const char* name); +typedef int flistxattr_func(int fd, char* list, size_t size); + +fgetxattr_func* my_fgetxattr_func = NULL; +fsetxattr_func* my_fsetxattr_func = NULL; +fremovexattr_func* my_fremovexattr_func = NULL; +flistxattr_func* my_flistxattr_func = NULL; + +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz) +{ + my_fgetxattr_func = (fgetxattr_func*)dlsym(RTLD_DEFAULT, "fgetxattr"); + my_fsetxattr_func = (fsetxattr_func*)dlsym(RTLD_DEFAULT, "fsetxattr"); + my_fremovexattr_func = (fremovexattr_func*)dlsym(RTLD_DEFAULT, "fremovexattr"); + my_flistxattr_func = (flistxattr_func*)dlsym(RTLD_DEFAULT, "flistxattr"); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz, + jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) +{ + size_t res = -1; + const char* name = jlong_to_ptr(nameAddress); + void* value = jlong_to_ptr(valueAddress); + + if (my_fgetxattr_func == NULL) { + errno = ENOTSUP; + } else { + /* EINTR not documented */ + res = (*my_fgetxattr_func)(fd, name, value, valueLen); + } + if (res == (size_t)-1) + throwUnixException(env, errno); + return (jint)res; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz, + jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) +{ + int res = -1; + const char* name = jlong_to_ptr(nameAddress); + void* value = jlong_to_ptr(valueAddress); + + if (my_fsetxattr_func == NULL) { + errno = ENOTSUP; + } else { + /* EINTR not documented */ + res = (*my_fsetxattr_func)(fd, name, value, valueLen, 0); + } + if (res == -1) + throwUnixException(env, errno); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz, + jint fd, jlong nameAddress) +{ + int res = -1; + const char* name = jlong_to_ptr(nameAddress); + + if (my_fremovexattr_func == NULL) { + errno = ENOTSUP; + } else { + /* EINTR not documented */ + res = (*my_fremovexattr_func)(fd, name); + } + if (res == -1) + throwUnixException(env, errno); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz, + jint fd, jlong listAddress, jint size) +{ + size_t res = -1; + char* list = jlong_to_ptr(listAddress); + + if (my_flistxattr_func == NULL) { + errno = ENOTSUP; + } else { + /* EINTR not documented */ + res = (*my_flistxattr_func)(fd, list, (size_t)size); + } + if (res == (size_t)-1) + throwUnixException(env, errno); + return (jint)res; +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong pathAddress, + jlong modeAddress) +{ + FILE* fp = NULL; + const char* path = (const char*)jlong_to_ptr(pathAddress); + const char* mode = (const char*)jlong_to_ptr(modeAddress); + + do { + fp = setmntent(path, mode); + } while (fp == NULL && errno == EINTR); + if (fp == NULL) { + throwUnixException(env, errno); + } + return ptr_to_jlong(fp); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_endmntent(JNIEnv* env, jclass this, jlong stream) +{ + FILE* fp = jlong_to_ptr(stream); + /* FIXME - man page doesn't explain how errors are returned */ + endmntent(fp); +} diff --git a/jdk/src/solaris/native/sun/nio/fs/LinuxWatchService.c b/jdk/src/solaris/native/sun/nio/fs/LinuxWatchService.c new file mode 100644 index 00000000000..74a15407916 --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/fs/LinuxWatchService.c @@ -0,0 +1,195 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" + +#include <stdlib.h> +#include <dlfcn.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/poll.h> + +#include "sun_nio_fs_LinuxWatchService.h" + +/* inotify.h may not be available at build time */ +#ifdef __cplusplus +extern "C" { +#endif +struct inotify_event +{ + int wd; + uint32_t mask; + uint32_t cookie; + uint32_t len; + char name __flexarr; +}; +#ifdef __cplusplus +} +#endif + +typedef int inotify_init_func(void); +typedef int inotify_add_watch_func(int fd, const char* path, uint32_t mask); +typedef int inotify_rm_watch_func(int fd, uint32_t wd); + +inotify_init_func* my_inotify_init_func = NULL; +inotify_add_watch_func* my_inotify_add_watch_func = NULL; +inotify_rm_watch_func* my_inotify_rm_watch_func = NULL; + +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxWatchService_init(JNIEnv *env, jclass clazz) +{ + my_inotify_init_func = (inotify_init_func*) + dlsym(RTLD_DEFAULT, "inotify_init"); + my_inotify_add_watch_func = + (inotify_add_watch_func*) dlsym(RTLD_DEFAULT, "inotify_add_watch"); + my_inotify_rm_watch_func = + (inotify_rm_watch_func*) dlsym(RTLD_DEFAULT, "inotify_rm_watch"); + + if ((my_inotify_init_func == NULL) || (my_inotify_add_watch_func == NULL) || + (my_inotify_rm_watch_func == NULL)) { + JNU_ThrowInternalError(env, "unable to get address of inotify functions"); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxWatchService_eventSize(JNIEnv *env, jclass clazz) +{ + return (jint)sizeof(struct inotify_event); +} + +JNIEXPORT jintArray JNICALL +Java_sun_nio_fs_LinuxWatchService_eventOffsets(JNIEnv *env, jclass clazz) +{ + jintArray result = (*env)->NewIntArray(env, 5); + if (result != NULL) { + jint arr[5]; + arr[0] = (jint)offsetof(struct inotify_event, wd); + arr[1] = (jint)offsetof(struct inotify_event, mask); + arr[2] = (jint)offsetof(struct inotify_event, cookie); + arr[3] = (jint)offsetof(struct inotify_event, len); + arr[4] = (jint)offsetof(struct inotify_event, name); + (*env)->SetIntArrayRegion(env, result, 0, 5, arr); + } + return result; +} + + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxWatchService_inotifyInit + (JNIEnv* env, jclass clazz) +{ + int ifd = (*my_inotify_init_func)(); + if (ifd == -1) { + throwUnixException(env, errno); + } + return (jint)ifd; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxWatchService_inotifyAddWatch + (JNIEnv* env, jclass clazz, jint fd, jlong address, jint mask) +{ + int wfd = -1; + const char* path = (const char*)jlong_to_ptr(address); + + wfd = (*my_inotify_add_watch_func)((int)fd, path, mask); + if (wfd == -1) { + throwUnixException(env, errno); + } + return (jint)wfd; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxWatchService_inotifyRmWatch + (JNIEnv* env, jclass clazz, jint fd, jint wd) +{ + int err = (*my_inotify_rm_watch_func)((int)fd, (int)wd); + if (err == -1) + throwUnixException(env, errno); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxWatchService_configureBlocking + (JNIEnv* env, jclass clazz, jint fd, jboolean blocking) +{ + int flags = fcntl(fd, F_GETFL); + + if ((blocking == JNI_FALSE) && !(flags & O_NONBLOCK)) + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + else if ((blocking == JNI_TRUE) && (flags & O_NONBLOCK)) + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxWatchService_socketpair + (JNIEnv* env, jclass clazz, jintArray sv) +{ + int sp[2]; + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + throwUnixException(env, errno); + } else { + jint res[2]; + res[0] = (jint)sp[0]; + res[1] = (jint)sp[1]; + (*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]); + } + +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxWatchService_poll + (JNIEnv* env, jclass clazz, jint fd1, jint fd2) +{ + struct pollfd ufds[2]; + int n; + + ufds[0].fd = fd1; + ufds[0].events = POLLIN; + ufds[1].fd = fd2; + ufds[1].events = POLLIN; + + n = poll(&ufds[0], 2, -1); + if (n == -1) { + if (errno == EINTR) { + n = 0; + } else { + throwUnixException(env, errno); + } + } + return (jint)n; + + +} diff --git a/jdk/src/solaris/native/sun/nio/fs/SolarisNativeDispatcher.c b/jdk/src/solaris/native/sun/nio/fs/SolarisNativeDispatcher.c new file mode 100644 index 00000000000..a57009c67bc --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/fs/SolarisNativeDispatcher.c @@ -0,0 +1,61 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" + +#include <dlfcn.h> +#include <errno.h> +#include <sys/acl.h> + +#include "sun_nio_fs_SolarisNativeDispatcher.h" + +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisNativeDispatcher_init(JNIEnv *env, jclass clazz) { +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_SolarisNativeDispatcher_facl(JNIEnv* env, jclass this, jint fd, + jint cmd, jint nentries, jlong address) +{ + void* aclbufp = jlong_to_ptr(address); + int n = -1; + + n = facl((int)fd, (int)cmd, (int)nentries, aclbufp); + if (n == -1) { + throwUnixException(env, errno); + } + return (jint)n; +} diff --git a/jdk/src/solaris/native/sun/nio/fs/SolarisWatchService.c b/jdk/src/solaris/native/sun/nio/fs/SolarisWatchService.c new file mode 100644 index 00000000000..776227f9955 --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/fs/SolarisWatchService.c @@ -0,0 +1,104 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" + +#include <stdlib.h> +#include <dlfcn.h> +#include <sys/types.h> +#include <port.h> // Solaris 10 + +#include "sun_nio_fs_SolarisWatchService.h" + +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisWatchService_init(JNIEnv *env, jclass clazz) +{ +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_SolarisWatchService_portCreate + (JNIEnv* env, jclass clazz) +{ + int port = port_create(); + if (port == -1) { + throwUnixException(env, errno); + } + return (jint)port; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisWatchService_portAssociate + (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events) +{ + uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress); + + if (port_associate((int)port, (int)source, object, (int)events, NULL) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisWatchService_portDissociate + (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress) +{ + uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress); + + if (port_dissociate((int)port, (int)source, object) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisWatchService_portSend(JNIEnv* env, jclass clazz, + jint port, jint events) +{ + if (port_send((int)port, (int)events, NULL) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_SolarisWatchService_portGetn(JNIEnv* env, jclass clazz, + jint port, jlong arrayAddress, jint max) +{ + uint_t n = 1; + port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress); + + if (port_getn((int)port, list, (uint_t)max, &n, NULL) == -1) { + throwUnixException(env, errno); + } + return (jint)n; +} diff --git a/jdk/src/solaris/native/sun/nio/fs/UnixCopyFile.c b/jdk/src/solaris/native/sun/nio/fs/UnixCopyFile.c new file mode 100644 index 00000000000..526ccba9668 --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/fs/UnixCopyFile.c @@ -0,0 +1,85 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" + +#include <unistd.h> +#include <errno.h> + +#include "sun_nio_fs_UnixCopyFile.h" + +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +/** + * Transfer all bytes from src to dst via user-space buffers + */ +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixCopyFile_transfer + (JNIEnv* env, jclass this, jint dst, jint src, jlong cancelAddress) +{ + char buf[8192]; + volatile jint* cancel = (jint*)jlong_to_ptr(cancelAddress); + + for (;;) { + ssize_t n, pos, len; + RESTARTABLE(read((int)src, &buf, sizeof(buf)), n); + if (n <= 0) { + if (n < 0) + throwUnixException(env, errno); + return; + } + if (cancel != NULL && *cancel != 0) { + throwUnixException(env, ECANCELED); + return; + } + pos = 0; + len = n; + do { + char* bufp = buf; + bufp += pos; + RESTARTABLE(write((int)dst, bufp, len), n); + if (n == -1) { + throwUnixException(env, errno); + return; + } + pos += n; + len -= n; + } while (len > 0); + } +} diff --git a/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c b/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c new file mode 100644 index 00000000000..13a1a3a215f --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c @@ -0,0 +1,1080 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <fcntl.h> +#include <dirent.h> +#include <unistd.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <dlfcn.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <sys/time.h> + +#ifdef __solaris__ +#include <strings.h> +#include <sys/mnttab.h> +#include <sys/mkdev.h> +#endif + +#ifdef __linux__ +#include <string.h> +#include <mntent.h> +#endif + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" + +#include "sun_nio_fs_UnixNativeDispatcher.h" + +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + +static jfieldID attrs_st_mode; +static jfieldID attrs_st_ino; +static jfieldID attrs_st_dev; +static jfieldID attrs_st_rdev; +static jfieldID attrs_st_nlink; +static jfieldID attrs_st_uid; +static jfieldID attrs_st_gid; +static jfieldID attrs_st_size; +static jfieldID attrs_st_atime; +static jfieldID attrs_st_mtime; +static jfieldID attrs_st_ctime; + +static jfieldID attrs_f_frsize; +static jfieldID attrs_f_blocks; +static jfieldID attrs_f_bfree; +static jfieldID attrs_f_bavail; + +static jfieldID entry_name; +static jfieldID entry_dir; +static jfieldID entry_fstype; +static jfieldID entry_options; +static jfieldID entry_dev; + +/** + * System calls that may not be available at build time. + */ +typedef int openat64_func(int, const char *, int, ...); +typedef int fstatat64_func(int, const char *, struct stat64 *, int); +typedef int unlinkat_func(int, const char*, int); +typedef int renameat_func(int, const char*, int, const char*); +typedef int futimesat_func(int, const char *, const struct timeval *); +typedef DIR* fdopendir_func(int); + +static openat64_func* my_openat64_func = NULL; +static fstatat64_func* my_fstatat64_func = NULL; +static unlinkat_func* my_unlinkat_func = NULL; +static renameat_func* my_renameat_func = NULL; +static futimesat_func* my_futimesat_func = NULL; +static fdopendir_func* my_fdopendir_func = NULL; + +/** + * fstatat missing from glibc on Linux. Temporary workaround + * for x86/x64. + */ +#if defined(__linux__) && defined(__i386) +#define FSTATAT64_SYSCALL_AVAILABLE +static int fstatat64_wrapper(int dfd, const char *path, + struct stat64 *statbuf, int flag) +{ + #ifndef __NR_fstatat64 + #define __NR_fstatat64 300 + #endif + return syscall(__NR_fstatat64, dfd, path, statbuf, flag); +} +#endif + +#if defined(__linux__) && defined(__x86_64__) +#define FSTATAT64_SYSCALL_AVAILABLE +static int fstatat64_wrapper(int dfd, const char *path, + struct stat64 *statbuf, int flag) +{ + #ifndef __NR_newfstatat + #define __NR_newfstatat 262 + #endif + return syscall(__NR_newfstatat, dfd, path, statbuf, flag); +} +#endif + +/** + * Call this to throw an internal UnixException when a system/library + * call fails + */ +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +/** + * Initialize jfieldIDs + */ +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_initIDs(JNIEnv* env, jclass this) +{ + jclass clazz; + + clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes"); + if (clazz == NULL) { + return; + } + attrs_st_mode = (*env)->GetFieldID(env, clazz, "st_mode", "I"); + attrs_st_ino = (*env)->GetFieldID(env, clazz, "st_ino", "J"); + attrs_st_dev = (*env)->GetFieldID(env, clazz, "st_dev", "J"); + attrs_st_rdev = (*env)->GetFieldID(env, clazz, "st_rdev", "J"); + attrs_st_nlink = (*env)->GetFieldID(env, clazz, "st_nlink", "I"); + attrs_st_uid = (*env)->GetFieldID(env, clazz, "st_uid", "I"); + attrs_st_gid = (*env)->GetFieldID(env, clazz, "st_gid", "I"); + attrs_st_size = (*env)->GetFieldID(env, clazz, "st_size", "J"); + attrs_st_atime = (*env)->GetFieldID(env, clazz, "st_atime", "J"); + attrs_st_mtime = (*env)->GetFieldID(env, clazz, "st_mtime", "J"); + attrs_st_ctime = (*env)->GetFieldID(env, clazz, "st_ctime", "J"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes"); + if (clazz == NULL) { + return; + } + attrs_f_frsize = (*env)->GetFieldID(env, clazz, "f_frsize", "J"); + attrs_f_blocks = (*env)->GetFieldID(env, clazz, "f_blocks", "J"); + attrs_f_bfree = (*env)->GetFieldID(env, clazz, "f_bfree", "J"); + attrs_f_bavail = (*env)->GetFieldID(env, clazz, "f_bavail", "J"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); + if (clazz == NULL) { + return; + } + entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); + entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); + entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); + entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); + entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J"); + + /* system calls that might not be available at build time */ + +#if defined(__solaris__) && defined(_LP64) + /* Solaris 64-bit does not have openat64/fstatat64 */ + my_openat64_func = (openat64_func*)dlsym(RTLD_DEFAULT, "openat"); + my_fstatat64_func = (fstatat64_func*)dlsym(RTLD_DEFAULT, "fstatat"); +#else + my_openat64_func = (openat64_func*) dlsym(RTLD_DEFAULT, "openat64"); + my_fstatat64_func = (fstatat64_func*) dlsym(RTLD_DEFAULT, "fstatat64"); +#endif + my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat"); + my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat"); + my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat"); + my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir"); + +#if defined(FSTATAT64_SYSCALL_AVAILABLE) + /* fstatat64 missing from glibc */ + if (my_fstatat64_func == NULL) + my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper; +#endif +} + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_getcwd(JNIEnv* env, jclass this) { + jbyteArray result = NULL; + char buf[PATH_MAX+1]; + + /* EINTR not listed as a possible error */ + char* cwd = getcwd(buf, sizeof(buf)); + if (cwd == NULL) { + throwUnixException(env, errno); + } else { + jsize len = (jsize)strlen(buf); + result = (*env)->NewByteArray(env, len); + if (result != NULL) { + (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf); + } + } + return result; +} + +JNIEXPORT jbyteArray +Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error) +{ + char* msg; + jsize len; + jbyteArray bytes; + + msg = strerror((int)error); + len = strlen(msg); + bytes = (*env)->NewByteArray(env, len); + if (bytes != NULL) { + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)msg); + } + return bytes; +} + +JNIEXPORT jint +Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) { + + int res = -1; + + RESTARTABLE(dup((int)fd), res); + if (fd == -1) { + throwUnixException(env, errno); + } + return (jint)res; +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fopen0(JNIEnv* env, jclass this, + jlong pathAddress, jlong modeAddress) +{ + FILE* fp = NULL; + const char* path = (const char*)jlong_to_ptr(pathAddress); + const char* mode = (const char*)jlong_to_ptr(modeAddress); + + do { + fp = fopen(path, mode); + } while (fp == NULL && errno == EINTR); + + if (fp == NULL) { + throwUnixException(env, errno); + } + + return ptr_to_jlong(fp); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stream) +{ + int res; + FILE* fp = jlong_to_ptr(stream); + + do { + res = fclose(fp); + } while (res == EOF && errno == EINTR); + if (res == EOF) { + throwUnixException(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this, + jlong pathAddress, jint oflags, jint mode) +{ + jint fd; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd); + if (fd == -1) { + throwUnixException(env, errno); + } + return fd; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd, + jlong pathAddress, jint oflags, jint mode) +{ + jint fd; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + if (my_openat64_func == NULL) { + JNU_ThrowInternalError(env, "should not reach here"); + return -1; + } + + RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd); + if (fd == -1) { + throwUnixException(env, errno); + } + return fd; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_close(JNIEnv* env, jclass this, jint fd) { + int err; + /* TDB - need to decide if EIO and other errors should cause exception */ + RESTARTABLE(close((int)fd), err); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd, + jlong address, jint nbytes) +{ + ssize_t n; + void* bufp = jlong_to_ptr(address); + RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n); + if (n == -1) { + throwUnixException(env, errno); + } + return (jint)n; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd, + jlong address, jint nbytes) +{ + ssize_t n; + void* bufp = jlong_to_ptr(address); + RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n); + if (n == -1) { + throwUnixException(env, errno); + } + return (jint)n; +} + +/** + * Copy stat64 members into sun.nio.fs.UnixFileAttributes + */ +static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { + (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode); + (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino); + (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev); + (*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev); + (*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink); + (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid); + (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid); + (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size); + (*env)->SetLongField(env, attrs, attrs_st_atime, (jlong)buf->st_atime * 1000); + (*env)->SetLongField(env, attrs, attrs_st_mtime, (jlong)buf->st_mtime * 1000); + (*env)->SetLongField(env, attrs, attrs_st_ctime, (jlong)buf->st_ctime * 1000); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, + jlong pathAddress, jobject attrs) +{ + int err; + struct stat64 buf; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + RESTARTABLE(stat64(path, &buf), err); + if (err == -1) { + throwUnixException(env, errno); + } else { + prepAttributes(env, &buf, attrs); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, + jlong pathAddress, jobject attrs) +{ + int err; + struct stat64 buf; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + RESTARTABLE(lstat64(path, &buf), err); + if (err == -1) { + throwUnixException(env, errno); + } else { + prepAttributes(env, &buf, attrs); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd, + jobject attrs) +{ + int err; + struct stat64 buf; + + RESTARTABLE(fstat64((int)fd, &buf), err); + if (err == -1) { + throwUnixException(env, errno); + } else { + prepAttributes(env, &buf, attrs); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd, + jlong pathAddress, jint flag, jobject attrs) +{ + int err; + struct stat64 buf; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + if (my_fstatat64_func == NULL) { + JNU_ThrowInternalError(env, "should not reach here"); + return; + } + RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err); + if (err == -1) { + throwUnixException(env, errno); + } else { + prepAttributes(env, &buf, attrs); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this, + jlong pathAddress, jint mode) +{ + int err; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + RESTARTABLE(chmod(path, (mode_t)mode), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes, + jint mode) +{ + int err; + + RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this, + jlong pathAddress, jint uid, jint gid) +{ + int err; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid) +{ + int err; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid) +{ + int err; + + RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this, + jlong pathAddress, jlong accessTime, jlong modificationTime) +{ + int err; + struct timeval times[2]; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + times[0].tv_sec = accessTime / 1000; + times[0].tv_usec = (accessTime % 1000) * 1000; + + times[1].tv_sec = modificationTime / 1000; + times[1].tv_usec = (modificationTime % 1000) * 1000; + + RESTARTABLE(utimes(path, ×[0]), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes, + jlong accessTime, jlong modificationTime) +{ + struct timeval times[2]; + int err = 0; + + times[0].tv_sec = accessTime / 1000; + times[0].tv_usec = (accessTime % 1000) * 1000; + + times[1].tv_sec = modificationTime / 1000; + times[1].tv_usec = (modificationTime % 1000) * 1000; + + if (my_futimesat_func != NULL) { + RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err); + if (err == -1) { + throwUnixException(env, errno); + } + } +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this, + jlong pathAddress) +{ + DIR* dir; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + /* EINTR not listed as a possible error */ + dir = opendir(path); + if (dir == NULL) { + throwUnixException(env, errno); + } + return ptr_to_jlong(dir); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) { + DIR* dir; + + if (my_fdopendir_func == NULL) { + JNU_ThrowInternalError(env, "should not reach here"); + return (jlong)-1; + } + + /* EINTR not listed as a possible error */ + dir = (*my_fdopendir_func)((int)dfd); + if (dir == NULL) { + throwUnixException(env, errno); + } + return ptr_to_jlong(dir); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) { + int err; + DIR* dirp = jlong_to_ptr(dir); + + RESTARTABLE(closedir(dirp), err); + if (errno == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) { + char entry[sizeof(struct dirent64) + PATH_MAX + 1]; + struct dirent64* ptr = (struct dirent64*)&entry; + struct dirent64* result; + int res; + DIR* dirp = jlong_to_ptr(value); + + /* EINTR not listed as a possible error */ + /* TDB: reentrant version probably not required here */ + res = readdir64_r(dirp, ptr, &result); + if (res != 0) { + throwUnixException(env, res); + return NULL; + } else { + if (result == NULL) { + return NULL; + } else { + jsize len = strlen(ptr->d_name); + jbyteArray bytes = (*env)->NewByteArray(env, len); + if (bytes != NULL) { + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name)); + } + return bytes; + } + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this, + jlong pathAddress, jint mode) +{ + const char* path = (const char*)jlong_to_ptr(pathAddress); + + /* EINTR not listed as a possible error */ + if (mkdir(path, (mode_t)mode) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this, + jlong pathAddress) +{ + const char* path = (const char*)jlong_to_ptr(pathAddress); + + /* EINTR not listed as a possible error */ + if (rmdir(path) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this, + jlong existingAddress, jlong newAddress) +{ + int err; + const char* existing = (const char*)jlong_to_ptr(existingAddress); + const char* newname = (const char*)jlong_to_ptr(newAddress); + + RESTARTABLE(link(existing, newname), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this, + jlong pathAddress) +{ + const char* path = (const char*)jlong_to_ptr(pathAddress); + + /* EINTR not listed as a possible error */ + if (unlink(path) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd, + jlong pathAddress, jint flags) +{ + const char* path = (const char*)jlong_to_ptr(pathAddress); + + if (my_unlinkat_func == NULL) { + JNU_ThrowInternalError(env, "should not reach here"); + return; + } + + /* EINTR not listed as a possible error */ + if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this, + jlong fromAddress, jlong toAddress) +{ + const char* from = (const char*)jlong_to_ptr(fromAddress); + const char* to = (const char*)jlong_to_ptr(toAddress); + + /* EINTR not listed as a possible error */ + if (rename(from, to) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this, + jint fromfd, jlong fromAddress, jint tofd, jlong toAddress) +{ + const char* from = (const char*)jlong_to_ptr(fromAddress); + const char* to = (const char*)jlong_to_ptr(toAddress); + + if (my_renameat_func == NULL) { + JNU_ThrowInternalError(env, "should not reach here"); + return; + } + + /* EINTR not listed as a possible error */ + if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this, + jlong targetAddress, jlong linkAddress) +{ + const char* target = (const char*)jlong_to_ptr(targetAddress); + const char* link = (const char*)jlong_to_ptr(linkAddress); + + /* EINTR not listed as a possible error */ + if (symlink(target, link) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this, + jlong pathAddress) +{ + jbyteArray result = NULL; + char target[PATH_MAX+1]; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + /* EINTR not listed as a possible error */ + int n = readlink(path, target, sizeof(target)); + if (n == -1) { + throwUnixException(env, errno); + } else { + jsize len; + if (n == sizeof(target)) { + n--; + } + target[n] = '\0'; + len = (jsize)strlen(target); + result = (*env)->NewByteArray(env, len); + if (result != NULL) { + (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target); + } + } + return result; +} + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this, + jlong pathAddress) +{ + jbyteArray result = NULL; + char resolved[PATH_MAX+1]; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + /* EINTR not listed as a possible error */ + if (realpath(path, resolved) == NULL) { + throwUnixException(env, errno); + } else { + jsize len = (jsize)strlen(resolved); + result = (*env)->NewByteArray(env, len); + if (result != NULL) { + (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved); + } + } + return result; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this, + jlong pathAddress, jint amode) +{ + int err; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + RESTARTABLE(access(path, (int)amode), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this, + jlong pathAddress, jobject attrs) +{ + int err; + struct statvfs64 buf; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + + RESTARTABLE(statvfs64(path, &buf), err); + if (err == -1) { + throwUnixException(env, errno); + } else { + (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize)); + (*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks)); + (*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree)); + (*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail)); + } +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_pathconf0(JNIEnv* env, jclass this, + jlong pathAddress, jint name) +{ + long err; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + err = pathconf(path, (int)name); + if (err == -1) { + throwUnixException(env, errno); + } + return (jlong)err; +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this, + jint fd, jint name) +{ + long err; + + err = fpathconf((int)fd, (int)name); + if (err == -1) { + throwUnixException(env, errno); + } + return (jlong)err; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this, + jlong pathAddress, jint mode, jlong dev) +{ + int err; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid) +{ + jbyteArray result = NULL; + int buflen; + + buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); + if (buflen == -1) { + throwUnixException(env, errno); + } else { + char* pwbuf = (char*)malloc(buflen); + if (pwbuf == NULL) { + JNU_ThrowOutOfMemoryError(env, "native heap"); + } else { + struct passwd pwent; + struct passwd* p; + int res = 0; + +#ifdef __solaris__ + p = getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen); +#else + res = getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p); +#endif + + if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { + throwUnixException(env, errno); + } else { + jsize len = strlen(p->pw_name); + result = (*env)->NewByteArray(env, len); + if (result != NULL) { + (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name)); + } + } + free(pwbuf); + } + } + return result; +} + + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid) +{ + jbyteArray result = NULL; + int buflen; + + buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); + if (buflen == -1) { + throwUnixException(env, errno); + } else { + char* grbuf = (char*)malloc(buflen); + if (grbuf == NULL) { + JNU_ThrowOutOfMemoryError(env, "native heap"); + } else { + struct group grent; + struct group* g; + int res = 0; + +#ifdef __solaris__ + g = getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen); +#else + res = getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g); +#endif + if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { + throwUnixException(env, errno); + } else { + jsize len = strlen(g->gr_name); + result = (*env)->NewByteArray(env, len); + if (result != NULL) { + (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name)); + } + } + free(grbuf); + } + } + return result; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this, + jlong nameAddress) +{ + jint uid = -1; + int buflen; + char* pwbuf; + struct passwd pwent; + struct passwd* p; + int res = 0; + const char* name = (const char*)jlong_to_ptr(nameAddress); + + buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); + if (buflen == -1) { + throwUnixException(env, errno); + return -1; + } + pwbuf = (char*)malloc(buflen); + if (pwbuf == NULL) { + JNU_ThrowOutOfMemoryError(env, "native heap"); + return -1; + } + +#ifdef __solaris__ + p = getpwnam_r(name, &pwent, pwbuf, (size_t)buflen); +#else + res = getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p); +#endif + + if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { + /* not found or error */ + } else { + uid = p->pw_uid; + } + + free(pwbuf); + + return uid; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, + jlong nameAddress) +{ + jint gid = -1; + int buflen; + char* grbuf; + struct group grent; + struct group* g; + int res = 0; + const char* name = (const char*)jlong_to_ptr(nameAddress); + + buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); + if (buflen == -1) { + throwUnixException(env, errno); + return -1; + } + grbuf = (char*)malloc(buflen); + if (grbuf == NULL) { + JNU_ThrowOutOfMemoryError(env, "native heap"); + return -1; + } + +#ifdef __solaris__ + g = getgrnam_r(name, &grent, grbuf, (size_t)buflen); +#else + res = getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g); +#endif + + if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { + /* not found or error */ + } else { + gid = g->gr_gid; + } + free(grbuf); + + return gid; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_getextmntent(JNIEnv* env, jclass this, + jlong value, jobject entry) +{ +#ifdef __solaris__ + struct extmnttab ent; +#else + struct mntent ent; + char buf[1024]; + int buflen = sizeof(buf); + struct mntent* m; +#endif + FILE* fp = jlong_to_ptr(value); + jsize len; + jbyteArray bytes; + char* name; + char* dir; + char* fstype; + char* options; + dev_t dev; + +#ifdef __solaris__ + if (getextmntent(fp, &ent, 0)) + return -1; + name = ent.mnt_special; + dir = ent.mnt_mountp; + fstype = ent.mnt_fstype; + options = ent.mnt_mntopts; + dev = makedev(ent.mnt_major, ent.mnt_minor); + if (dev == NODEV) { + /* possible bug on Solaris 8 and 9 */ + throwUnixException(env, errno); + return -1; + } +#else + m = getmntent_r(fp, &ent, (char*)&buf, buflen); + if (m == NULL) + return -1; + name = m->mnt_fsname; + dir = m->mnt_dir; + fstype = m->mnt_type; + options = m->mnt_opts; + dev = 0; +#endif + + len = strlen(name); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name); + (*env)->SetObjectField(env, entry, entry_name, bytes); + + len = strlen(dir); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir); + (*env)->SetObjectField(env, entry, entry_dir, bytes); + + len = strlen(fstype); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype); + (*env)->SetObjectField(env, entry, entry_fstype, bytes); + + len = strlen(options); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options); + (*env)->SetObjectField(env, entry, entry_options, bytes); + + if (dev != 0) + (*env)->SetLongField(env, entry, entry_dev, (jlong)dev); + + return 0; +} diff --git a/jdk/src/solaris/native/sun/nio/fs/genSolarisConstants.c b/jdk/src/solaris/native/sun/nio/fs/genSolarisConstants.c new file mode 100644 index 00000000000..182449e4ab5 --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/fs/genSolarisConstants.c @@ -0,0 +1,105 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <sys/acl.h> +#include <sys/fcntl.h> +#include <sys/stat.h> + +/** + * Generates sun.nio.fs.SolarisConstants + */ + +static void out(char* s) { + printf("%s\n", s); +} + +static void emit(char* name, int value) { + printf(" static final int %s = %d;\n", name, value); +} + +static void emitX(char* name, int value) { + printf(" static final int %s = 0x%x;\n", name, value); +} + +#define DEF(X) emit(#X, X); +#define DEFX(X) emitX(#X, X); + +int main(int argc, const char* argv[]) { + out("// AUTOMATICALLY GENERATED FILE - DO NOT EDIT "); + out("package sun.nio.fs; "); + out("class SolarisConstants { "); + out(" private SolarisConstants() { } "); + + // extended attributes + DEFX(O_XATTR); + DEF(_PC_XATTR_ENABLED); + + // ACL configuration + DEF(_PC_ACL_ENABLED); + DEFX(_ACL_ACE_ENABLED); + + // ACL commands + DEFX(ACE_GETACL); + DEFX(ACE_SETACL); + + // ACL mask/flags/types + emitX("ACE_ACCESS_ALLOWED_ACE_TYPE", 0x0000); + emitX("ACE_ACCESS_DENIED_ACE_TYPE", 0x0001); + emitX("ACE_SYSTEM_AUDIT_ACE_TYPE", 0x0002); + emitX("ACE_SYSTEM_ALARM_ACE_TYPE", 0x0003); + emitX("ACE_READ_DATA", 0x00000001); + emitX("ACE_LIST_DIRECTORY", 0x00000001); + emitX("ACE_WRITE_DATA", 0x00000002); + emitX("ACE_ADD_FILE", 0x00000002); + emitX("ACE_APPEND_DATA", 0x00000004); + emitX("ACE_ADD_SUBDIRECTORY", 0x00000004); + emitX("ACE_READ_NAMED_ATTRS", 0x00000008); + emitX("ACE_WRITE_NAMED_ATTRS", 0x00000010); + emitX("ACE_EXECUTE", 0x00000020); + emitX("ACE_DELETE_CHILD", 0x00000040); + emitX("ACE_READ_ATTRIBUTES", 0x00000080); + emitX("ACE_WRITE_ATTRIBUTES", 0x00000100); + emitX("ACE_DELETE", 0x00010000); + emitX("ACE_READ_ACL", 0x00020000); + emitX("ACE_WRITE_ACL", 0x00040000); + emitX("ACE_WRITE_OWNER", 0x00080000); + emitX("ACE_SYNCHRONIZE", 0x00100000); + emitX("ACE_FILE_INHERIT_ACE", 0x0001); + emitX("ACE_DIRECTORY_INHERIT_ACE", 0x0002); + emitX("ACE_NO_PROPAGATE_INHERIT_ACE", 0x0004); + emitX("ACE_INHERIT_ONLY_ACE", 0x0008); + emitX("ACE_SUCCESSFUL_ACCESS_ACE_FLAG", 0x0010); + emitX("ACE_FAILED_ACCESS_ACE_FLAG", 0x0020); + emitX("ACE_IDENTIFIER_GROUP", 0x0040); + emitX("ACE_OWNER", 0x1000); + emitX("ACE_GROUP", 0x2000); + emitX("ACE_EVERYONE", 0x4000); + + out("} "); + return 0; +} diff --git a/jdk/src/solaris/native/sun/nio/fs/genUnixConstants.c b/jdk/src/solaris/native/sun/nio/fs/genUnixConstants.c new file mode 100644 index 00000000000..c01f641a690 --- /dev/null +++ b/jdk/src/solaris/native/sun/nio/fs/genUnixConstants.c @@ -0,0 +1,125 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <sys/fcntl.h> +#include <sys/stat.h> + +/** + * Generates sun.nio.fs.UnixConstants + */ + +static void out(char* s) { + printf("%s\n", s); +} + +static void emit(char* name, int value) { + printf(" static final int %s = %d;\n", name, value); +} + +static void emitX(char* name, int value) { + printf(" static final int %s = 0x%x;\n", name, value); +} + +#define DEF(X) emit(#X, X); +#define DEFX(X) emitX(#X, X); + +int main(int argc, const char* argv[]) { + out("// AUTOMATICALLY GENERATED FILE - DO NOT EDIT "); + out("package sun.nio.fs; "); + out("class UnixConstants { "); + out(" private UnixConstants() { } "); + + // open flags + DEF(O_RDONLY); + DEF(O_WRONLY); + DEF(O_RDWR); + DEFX(O_APPEND); + DEFX(O_CREAT); + DEFX(O_EXCL); + DEFX(O_TRUNC); + DEFX(O_SYNC); + DEFX(O_DSYNC); + DEFX(O_NOFOLLOW); + + // flags used with openat/unlinkat/etc. +#ifdef __solaris__ + DEFX(AT_SYMLINK_NOFOLLOW); + DEFX(AT_REMOVEDIR); +#endif +#ifdef __linux__ + emitX("AT_SYMLINK_NOFOLLOW", 0x100); // since 2.6.16 + emitX("AT_REMOVEDIR", 0x200); +#endif + + // mode masks + emitX("S_IAMB", + (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)); + DEF(S_IRUSR); + DEF(S_IWUSR); + DEF(S_IXUSR); + DEF(S_IRGRP); + DEF(S_IWGRP); + DEF(S_IXGRP); + DEF(S_IROTH); + DEF(S_IWOTH); + DEF(S_IXOTH); + DEFX(S_IFMT); + DEFX(S_IFREG); + DEFX(S_IFDIR); + DEFX(S_IFLNK); + DEFX(S_IFCHR); + DEFX(S_IFBLK); + DEFX(S_IFIFO); + + // access modes + DEF(R_OK); + DEF(W_OK); + DEF(X_OK); + DEF(F_OK); + + // errors + DEF(ENOENT); + DEF(EACCES); + DEF(EEXIST); + DEF(ENOTDIR); + DEF(EINVAL); + DEF(EXDEV); + DEF(EISDIR); + DEF(ENOTEMPTY); + DEF(ENOSPC); + DEF(EAGAIN); + DEF(ENOSYS); + DEF(ELOOP); + DEF(EROFS); + DEF(ENODATA); + DEF(ERANGE); + + out("} "); + + return 0; +} diff --git a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java index 418dc8f59db..bc81b80e793 100644 --- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java +++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java @@ -32,6 +32,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.*; +import java.util.concurrent.*; import javax.swing.SwingConstants; // NOTE: This class supersedes Win32ShellFolder, which was removed from @@ -184,15 +185,20 @@ final class Win32ShellFolder2 extends ShellFolder { boolean disposed; public void dispose() { if (disposed) return; - if (relativePIDL != 0) { - releasePIDL(relativePIDL); - } - if (absolutePIDL != 0) { - releasePIDL(absolutePIDL); - } - if (pIShellFolder != 0) { - releaseIShellFolder(pIShellFolder); - } + ShellFolder.getInvoker().invoke(new Callable<Void>() { + public Void call() throws Exception { + if (relativePIDL != 0) { + releasePIDL(relativePIDL); + } + if (absolutePIDL != 0) { + releasePIDL(absolutePIDL); + } + if (pIShellFolder != 0) { + releaseIShellFolder(pIShellFolder); + } + return null; + } + }); disposed = true; } } @@ -218,50 +224,59 @@ final class Win32ShellFolder2 extends ShellFolder { */ private boolean isPersonal; + private static String composePathForCsidl(int csidl) throws IOException { + String path = getFileSystemPath(csidl); + return path == null + ? ("ShellFolder: 0x" + Integer.toHexString(csidl)) + : path; + } /** * Create a system special shell folder, such as the * desktop or Network Neighborhood. */ - Win32ShellFolder2(int csidl) throws IOException { + Win32ShellFolder2(final int csidl) throws IOException { // Desktop is parent of DRIVES and NETWORK, not necessarily // other special shell folders. - super(null, - (getFileSystemPath(csidl) == null) - ? ("ShellFolder: 0x"+Integer.toHexString(csidl)) : getFileSystemPath(csidl)); - if (csidl == DESKTOP) { - initDesktop(); - } else { - initSpecial(getDesktop().getIShellFolder(), csidl); - // At this point, the native method initSpecial() has set our relativePIDL - // relative to the Desktop, which may not be our immediate parent. We need - // to traverse this ID list and break it into a chain of shell folders from - // the top, with each one having an immediate parent and a relativePIDL - // relative to that parent. - long pIDL = disposer.relativePIDL; - parent = getDesktop(); - while (pIDL != 0) { - // Get a child pidl relative to 'parent' - long childPIDL = copyFirstPIDLEntry(pIDL); - if (childPIDL != 0) { - // Get a handle to the the rest of the ID list - // i,e, parent's grandchilren and down - pIDL = getNextPIDLEntry(pIDL); - if (pIDL != 0) { - // Now we know that parent isn't immediate to 'this' because it - // has a continued ID list. Create a shell folder for this child - // pidl and make it the new 'parent'. - parent = new Win32ShellFolder2((Win32ShellFolder2)parent, childPIDL); - } else { - // No grandchildren means we have arrived at the parent of 'this', - // and childPIDL is directly relative to parent. - disposer.relativePIDL = childPIDL; - } + super(null, composePathForCsidl(csidl)); + ShellFolder.getInvoker().invoke(new Callable<Void>() { + public Void call() throws Exception { + if (csidl == DESKTOP) { + initDesktop(); } else { - break; + initSpecial(getDesktop().getIShellFolder(), csidl); + // At this point, the native method initSpecial() has set our relativePIDL + // relative to the Desktop, which may not be our immediate parent. We need + // to traverse this ID list and break it into a chain of shell folders from + // the top, with each one having an immediate parent and a relativePIDL + // relative to that parent. + long pIDL = disposer.relativePIDL; + parent = getDesktop(); + while (pIDL != 0) { + // Get a child pidl relative to 'parent' + long childPIDL = copyFirstPIDLEntry(pIDL); + if (childPIDL != 0) { + // Get a handle to the the rest of the ID list + // i,e, parent's grandchilren and down + pIDL = getNextPIDLEntry(pIDL); + if (pIDL != 0) { + // Now we know that parent isn't immediate to 'this' because it + // has a continued ID list. Create a shell folder for this child + // pidl and make it the new 'parent'. + parent = new Win32ShellFolder2((Win32ShellFolder2) parent, childPIDL); + } else { + // No grandchildren means we have arrived at the parent of 'this', + // and childPIDL is directly relative to parent. + disposer.relativePIDL = childPIDL; + } + } else { + break; + } + } } + return null; } - } + }); sun.java2d.Disposer.addRecord(this, disposer); } @@ -281,17 +296,26 @@ final class Win32ShellFolder2 extends ShellFolder { /** * Creates a shell folder with a parent and relative PIDL */ - Win32ShellFolder2(Win32ShellFolder2 parent, long relativePIDL) { - super(parent, getFileSystemPath(parent.getIShellFolder(), relativePIDL)); + Win32ShellFolder2(final Win32ShellFolder2 parent, final long relativePIDL) { + super(parent, + ShellFolder.getInvoker().invoke(new Callable<String>() { + public String call() throws Exception { + return getFileSystemPath(parent.getIShellFolder(), relativePIDL); + } + }) + ); this.disposer.relativePIDL = relativePIDL; getAbsolutePath(); sun.java2d.Disposer.addRecord(this, disposer); } // Initializes the desktop shell folder + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native void initDesktop(); + // Initializes a special, non-file system shell folder // from one of the above constants + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native void initSpecial(long desktopIShellFolder, int csidl); /** Marks this folder as being the My Documents (Personal) folder */ @@ -311,26 +335,30 @@ final class Win32ShellFolder2 extends ShellFolder { * drive (normally "C:\"). */ protected Object writeReplace() throws java.io.ObjectStreamException { - if (isFileSystem()) { - return new File(getPath()); - } else { - Win32ShellFolder2 drives = Win32ShellFolderManager2.getDrives(); - if (drives != null) { - File[] driveRoots = drives.listFiles(); - if (driveRoots != null) { - for (int i = 0; i < driveRoots.length; i++) { - if (driveRoots[i] instanceof Win32ShellFolder2) { - Win32ShellFolder2 sf = (Win32ShellFolder2)driveRoots[i]; - if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) { - return new File(sf.getPath()); + return ShellFolder.getInvoker().invoke(new Callable<File>() { + public File call() throws Exception { + if (isFileSystem()) { + return new File(getPath()); + } else { + Win32ShellFolder2 drives = Win32ShellFolderManager2.getDrives(); + if (drives != null) { + File[] driveRoots = drives.listFiles(); + if (driveRoots != null) { + for (int i = 0; i < driveRoots.length; i++) { + if (driveRoots[i] instanceof Win32ShellFolder2) { + Win32ShellFolder2 sf = (Win32ShellFolder2) driveRoots[i]; + if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) { + return new File(sf.getPath()); + } + } } } } + // Ouch, we have no hard drives. Return something "valid" anyway. + return new File("C:\\"); } } - // Ouch, we have no hard drives. Return something "valid" anyway. - return new File("C:\\"); - } + }); } @@ -364,6 +392,7 @@ final class Win32ShellFolder2 extends ShellFolder { static native void releasePIDL(long pIDL); // Release an IShellFolder object + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native void releaseIShellFolder(long pIShellFolder); /** @@ -371,18 +400,28 @@ final class Win32ShellFolder2 extends ShellFolder { */ public long getIShellFolder() { if (disposer.pIShellFolder == 0) { - assert(isDirectory()); - assert(parent != null); - long parentIShellFolder = getParentIShellFolder(); - if (parentIShellFolder == 0) { - throw new InternalError("Parent IShellFolder was null for " + getAbsolutePath()); - } - // We are a directory with a parent and a relative PIDL. - // We want to bind to the parent so we get an IShellFolder instance associated with us. - disposer.pIShellFolder = bindToObject(parentIShellFolder, disposer.relativePIDL); - if (disposer.pIShellFolder == 0) { - throw new InternalError("Unable to bind " + getAbsolutePath() + " to parent"); - } + disposer.pIShellFolder = + ShellFolder.getInvoker().invoke(new Callable<Long>() { + public Long call() throws Exception { + assert(isDirectory()); + assert(parent != null); + long parentIShellFolder = getParentIShellFolder(); + if (parentIShellFolder == 0) { + throw new InternalError("Parent IShellFolder was null for " + + getAbsolutePath()); + } + // We are a directory with a parent and a relative PIDL. + // We want to bind to the parent so we get an + // IShellFolder instance associated with us. + long pIShellFolder = bindToObject(parentIShellFolder, + disposer.relativePIDL); + if (pIShellFolder == 0) { + throw new InternalError("Unable to bind " + + getAbsolutePath() + " to parent"); + } + return pIShellFolder; + } + }); } return disposer.pIShellFolder; } @@ -472,24 +511,42 @@ final class Win32ShellFolder2 extends ShellFolder { return false; } - private static boolean pidlsEqual(long pIShellFolder, long pidl1, long pidl2) { - return (compareIDs(pIShellFolder, pidl1, pidl2) == 0); + private static boolean pidlsEqual(final long pIShellFolder, final long pidl1, final long pidl2) { + return ShellFolder.getInvoker().invoke(new Callable<Boolean>() { + public Boolean call() throws Exception { + return (compareIDs(pIShellFolder, pidl1, pidl2) == 0); + } + }); } + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native int compareIDs(long pParentIShellFolder, long pidl1, long pidl2); + private Boolean cachedIsFileSystem; + /** * @return Whether this is a file system shell folder */ - public boolean isFileSystem() { - return hasAttribute(ATTRIB_FILESYSTEM); + public synchronized boolean isFileSystem() { + if (cachedIsFileSystem == null) { + cachedIsFileSystem = hasAttribute(ATTRIB_FILESYSTEM); + } + + return cachedIsFileSystem; } /** * Return whether the given attribute flag is set for this object */ - public boolean hasAttribute(int attribute) { - // Caching at this point doesn't seem to be cost efficient - return (getAttributes0(getParentIShellFolder(), getRelativePIDL(), attribute) & attribute) != 0; + public boolean hasAttribute(final int attribute) { + return ShellFolder.getInvoker().invoke(new Callable<Boolean>() { + public Boolean call() throws Exception { + // Caching at this point doesn't seem to be cost efficient + return (getAttributes0(getParentIShellFolder(), + getRelativePIDL(), attribute) + & attribute) != 0; + } + }); } /** @@ -498,26 +555,42 @@ final class Win32ShellFolder2 extends ShellFolder { * Could plausibly be used for attribute caching but have to be * very careful not to touch network drives and file system roots * with a full attrsMask + * NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details */ + private static native int getAttributes0(long pParentIShellFolder, long pIDL, int attrsMask); // Return the path to the underlying file system object - private static String getFileSystemPath(long parentIShellFolder, long relativePIDL) { - int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER; - if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() && - getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) { + private static String getFileSystemPath(final long parentIShellFolder, final long relativePIDL) { + return ShellFolder.getInvoker().invoke(new Callable<String>() { + public String call() throws Exception { + int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER; + if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() && + getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) { - String s = - getFileSystemPath(Win32ShellFolderManager2.getDesktop().getIShellFolder(), - getLinkLocation(parentIShellFolder, relativePIDL, false)); - if (s != null && s.startsWith("\\\\")) { - return s; + String s = + getFileSystemPath(Win32ShellFolderManager2.getDesktop().getIShellFolder(), + getLinkLocation(parentIShellFolder, relativePIDL, false)); + if (s != null && s.startsWith("\\\\")) { + return s; + } + } + return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_FORPARSING); } - } - return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_NORMAL | SHGDN_FORPARSING); + }); } + // Needs to be accessible to Win32ShellFolderManager2 - static native String getFileSystemPath(int csidl) throws IOException; + static String getFileSystemPath(final int csidl) throws IOException { + return ShellFolder.getInvoker().invoke(new Callable<String>() { + public String call() throws Exception { + return getFileSystemPath0(csidl); + } + }); + } + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details + private static native String getFileSystemPath0(int csidl) throws IOException; // Return whether the path is a network root. // Path is assumed to be non-null @@ -557,24 +630,33 @@ final class Win32ShellFolder2 extends ShellFolder { */ // Returns an IEnumIDList interface for an IShellFolder. The value // returned must be released using releaseEnumObjects(). - private long getEnumObjects(long pIShellFolder, boolean includeHiddenFiles) { - boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder()); - return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles); + private long getEnumObjects(long pIShellFolder, final boolean includeHiddenFiles) { + final boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder()); + return ShellFolder.getInvoker().invoke(new Callable<Long>() { + public Long call() throws Exception { + return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles); + } + }); } + // Returns an IEnumIDList interface for an IShellFolder. The value // returned must be released using releaseEnumObjects(). + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native long getEnumObjects(long pIShellFolder, boolean isDesktop, boolean includeHiddenFiles); // Returns the next sequential child as a relative PIDL // from an IEnumIDList interface. The value returned must // be released using releasePIDL(). + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native long getNextChild(long pEnumObjects); // Releases the IEnumIDList interface + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native void releaseEnumObjects(long pEnumObjects); // Returns the IShellFolder of a child from a parent IShellFolder // and a relative PIDL. The value returned must be released // using releaseIShellFolder(). + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native long bindToObject(long parentIShellFolder, long pIDL); /** @@ -582,60 +664,64 @@ final class Win32ShellFolder2 extends ShellFolder { * object. The array will be empty if the folder is empty. Returns * <code>null</code> if this shellfolder does not denote a directory. */ - public File[] listFiles(boolean includeHiddenFiles) { + public File[] listFiles(final boolean includeHiddenFiles) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(getPath()); } - if (!isDirectory()) { - return null; - } - // Links to directories are not directories and cannot be parents. - // This does not apply to folders in My Network Places (NetHood) - // because they are both links and real directories! - if (isLink() && !hasAttribute(ATTRIB_FOLDER)) { - return new File[0]; - } - Win32ShellFolder2 desktop = Win32ShellFolderManager2.getDesktop(); - Win32ShellFolder2 personal = Win32ShellFolderManager2.getPersonal(); - - // If we are a directory, we have a parent and (at least) a - // relative PIDL. We must first ensure we are bound to the - // parent so we have an IShellFolder to query. - long pIShellFolder = getIShellFolder(); - // Now we can enumerate the objects in this folder. - ArrayList<Win32ShellFolder2> list = new ArrayList<Win32ShellFolder2>(); - long pEnumObjects = getEnumObjects(pIShellFolder, includeHiddenFiles); - if (pEnumObjects != 0) { - long childPIDL; - int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR; - do { - if (Thread.currentThread().isInterrupted()) { + return ShellFolder.getInvoker().invoke(new Callable<File[]>() { + public File[] call() throws Exception { + if (!isDirectory()) { + return null; + } + // Links to directories are not directories and cannot be parents. + // This does not apply to folders in My Network Places (NetHood) + // because they are both links and real directories! + if (isLink() && !hasAttribute(ATTRIB_FOLDER)) { return new File[0]; } - childPIDL = getNextChild(pEnumObjects); - boolean releasePIDL = true; - if (childPIDL != 0 && - (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) { - Win32ShellFolder2 childFolder = null; - if (this.equals(desktop) - && personal != null - && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) { - childFolder = personal; - } else { - childFolder = new Win32ShellFolder2(this, childPIDL); - releasePIDL = false; - } - list.add(childFolder); + + Win32ShellFolder2 desktop = Win32ShellFolderManager2.getDesktop(); + Win32ShellFolder2 personal = Win32ShellFolderManager2.getPersonal(); + + // If we are a directory, we have a parent and (at least) a + // relative PIDL. We must first ensure we are bound to the + // parent so we have an IShellFolder to query. + long pIShellFolder = getIShellFolder(); + // Now we can enumerate the objects in this folder. + ArrayList<Win32ShellFolder2> list = new ArrayList<Win32ShellFolder2>(); + long pEnumObjects = getEnumObjects(pIShellFolder, includeHiddenFiles); + if (pEnumObjects != 0) { + long childPIDL; + int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR; + do { + childPIDL = getNextChild(pEnumObjects); + boolean releasePIDL = true; + if (childPIDL != 0 && + (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) { + Win32ShellFolder2 childFolder; + if (Win32ShellFolder2.this.equals(desktop) + && personal != null + && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) { + childFolder = personal; + } else { + childFolder = new Win32ShellFolder2(Win32ShellFolder2.this, childPIDL); + releasePIDL = false; + } + list.add(childFolder); + } + if (releasePIDL) { + releasePIDL(childPIDL); + } + } while (childPIDL != 0 && !Thread.currentThread().isInterrupted()); + releaseEnumObjects(pEnumObjects); } - if (releasePIDL) { - releasePIDL(childPIDL); - } - } while (childPIDL != 0); - releaseEnumObjects(pEnumObjects); - } - return list.toArray(new ShellFolder[list.size()]); + return Thread.currentThread().isInterrupted() + ? new File[0] + : list.toArray(new ShellFolder[list.size()]); + } + }); } @@ -644,33 +730,43 @@ final class Win32ShellFolder2 extends ShellFolder { * * @return The child shellfolder, or null if not found. */ - Win32ShellFolder2 getChildByPath(String filePath) { - long pIShellFolder = getIShellFolder(); - long pEnumObjects = getEnumObjects(pIShellFolder, true); - Win32ShellFolder2 child = null; - long childPIDL; + Win32ShellFolder2 getChildByPath(final String filePath) { + return ShellFolder.getInvoker().invoke(new Callable<Win32ShellFolder2>() { + public Win32ShellFolder2 call() throws Exception { + long pIShellFolder = getIShellFolder(); + long pEnumObjects = getEnumObjects(pIShellFolder, true); + Win32ShellFolder2 child = null; + long childPIDL = 0; - while ((childPIDL = getNextChild(pEnumObjects)) != 0) { - if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) { - String path = getFileSystemPath(pIShellFolder, childPIDL); - if (path != null && path.equalsIgnoreCase(filePath)) { - long childIShellFolder = bindToObject(pIShellFolder, childPIDL); - child = new Win32ShellFolder2(this, childIShellFolder, childPIDL, path); - break; + while ((childPIDL = getNextChild(pEnumObjects)) != 0) { + if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) { + String path = getFileSystemPath(pIShellFolder, childPIDL); + if (path != null && path.equalsIgnoreCase(filePath)) { + long childIShellFolder = bindToObject(pIShellFolder, childPIDL); + child = new Win32ShellFolder2(Win32ShellFolder2.this, + childIShellFolder, childPIDL, path); + break; + } + } + releasePIDL(childPIDL); } + releaseEnumObjects(pEnumObjects); + return child; } - releasePIDL(childPIDL); - } - releaseEnumObjects(pEnumObjects); - return child; + }); } + private Boolean cachedIsLink; /** * @return Whether this shell folder is a link */ - public boolean isLink() { - return hasAttribute(ATTRIB_LINK); + public synchronized boolean isLink() { + if (cachedIsLink == null) { + cachedIsLink = hasAttribute(ATTRIB_LINK); + } + + return cachedIsLink; } /** @@ -682,6 +778,7 @@ final class Win32ShellFolder2 extends ShellFolder { // Return the link location of a shell folder + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native long getLinkLocation(long parentIShellFolder, long relativePIDL, boolean resolve); @@ -693,38 +790,52 @@ final class Win32ShellFolder2 extends ShellFolder { return getLinkLocation(true); } - private ShellFolder getLinkLocation(boolean resolve) { - if (!isLink()) { - return null; - } + private ShellFolder getLinkLocation(final boolean resolve) { + return ShellFolder.getInvoker().invoke(new Callable<ShellFolder>() { + public ShellFolder call() throws Exception { + if (!isLink()) { + return null; + } - ShellFolder location = null; - long linkLocationPIDL = getLinkLocation(getParentIShellFolder(), - getRelativePIDL(), resolve); - if (linkLocationPIDL != 0) { - try { - location = - Win32ShellFolderManager2.createShellFolderFromRelativePIDL(getDesktop(), - linkLocationPIDL); - } catch (InternalError e) { - // Could be a link to a non-bindable object, such as a network connection - // TODO: getIShellFolder() should throw FileNotFoundException instead + ShellFolder location = null; + long linkLocationPIDL = getLinkLocation(getParentIShellFolder(), + getRelativePIDL(), resolve); + if (linkLocationPIDL != 0) { + try { + location = + Win32ShellFolderManager2.createShellFolderFromRelativePIDL(getDesktop(), + linkLocationPIDL); + } catch (InternalError e) { + // Could be a link to a non-bindable object, such as a network connection + // TODO: getIShellFolder() should throw FileNotFoundException instead + } + } + return location; } - } - return location; + }); } // Parse a display name into a PIDL relative to the current IShellFolder. - long parseDisplayName(String name) throws FileNotFoundException { + long parseDisplayName(final String name) throws FileNotFoundException { try { - return parseDisplayName0(getIShellFolder(), name); - } catch (IOException e) { - throw new FileNotFoundException("Could not find file " + name); + return ShellFolder.getInvoker().invoke(new Callable<Long>() { + public Long call() throws Exception { + return parseDisplayName0(getIShellFolder(), name); + } + }); + } catch (RuntimeException e) { + if (e.getCause() instanceof IOException) { + throw new FileNotFoundException("Could not find file " + name); + } + throw e; } } + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native long parseDisplayName0(long pIShellFolder, String name) throws IOException; // Return the display name of a shell folder + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native String getDisplayNameOf(long parentIShellFolder, long relativePIDL, int attrs); @@ -734,12 +845,19 @@ final class Win32ShellFolder2 extends ShellFolder { */ public String getDisplayName() { if (displayName == null) { - displayName = getDisplayNameOf(getParentIShellFolder(), getRelativePIDL(), SHGDN_NORMAL); + displayName = + ShellFolder.getInvoker().invoke(new Callable<String>() { + public String call() throws Exception { + return getDisplayNameOf(getParentIShellFolder(), + getRelativePIDL(), SHGDN_NORMAL); + } + }); } return displayName; } // Return the folder type of a shell folder + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native String getFolderType(long pIDL); /** @@ -747,7 +865,13 @@ final class Win32ShellFolder2 extends ShellFolder { */ public String getFolderType() { if (folderType == null) { - folderType = getFolderType(getAbsolutePIDL()); + final long absolutePIDL = getAbsolutePIDL(); + folderType = + ShellFolder.getInvoker().invoke(new Callable<String>() { + public String call() throws Exception { + return getFolderType(absolutePIDL); + } + }); } return folderType; } @@ -774,11 +898,16 @@ final class Win32ShellFolder2 extends ShellFolder { private static Map smallLinkedSystemImages = new HashMap(); private static Map largeLinkedSystemImages = new HashMap(); + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native long getIShellIcon(long pIShellFolder); + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native int getIconIndex(long parentIShellIcon, long relativePIDL); // Return the icon of a file system shell folder in the form of an HICON private static native long getIcon(String absolutePath, boolean getLargeIcon); + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native long extractIcon(long parentIShellFolder, long relativePIDL, boolean getLargeIcon); @@ -799,7 +928,12 @@ final class Win32ShellFolder2 extends ShellFolder { private long getIShellIcon() { if (pIShellIcon == -1L) { - pIShellIcon = getIShellIcon(getIShellFolder()); + pIShellIcon = + ShellFolder.getInvoker().invoke(new Callable<Long>() { + public Long call() throws Exception { + return getIShellIcon(getIShellFolder()); + } + }); } return pIShellIcon; } @@ -850,50 +984,60 @@ final class Win32ShellFolder2 extends ShellFolder { /** * @return The icon image used to display this shell folder */ - public Image getIcon(boolean getLargeIcon) { + public Image getIcon(final boolean getLargeIcon) { Image icon = getLargeIcon ? largeIcon : smallIcon; if (icon == null) { - long parentIShellIcon = (parent != null) ? ((Win32ShellFolder2)parent).getIShellIcon() : 0L; - long relativePIDL = getRelativePIDL(); + icon = + ShellFolder.getInvoker().invoke(new Callable<Image>() { + public Image call() throws Exception { + Image newIcon = null; + if (isFileSystem()) { + long parentIShellIcon = (parent != null) + ? ((Win32ShellFolder2) parent).getIShellIcon() + : 0L; + long relativePIDL = getRelativePIDL(); - if (isFileSystem()) { - // These are cached per type (using the index in the system image list) - int index = getIconIndex(parentIShellIcon, relativePIDL); - if (index > 0) { - Map imageCache; - if (isLink()) { - imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages; - } else { - imageCache = getLargeIcon ? largeSystemImages : smallSystemImages; - } - icon = (Image)imageCache.get(Integer.valueOf(index)); - if (icon == null) { - long hIcon = getIcon(getAbsolutePath(), getLargeIcon); - icon = makeIcon(hIcon, getLargeIcon); - disposeIcon(hIcon); - if (icon != null) { - imageCache.put(Integer.valueOf(index), icon); + // These are cached per type (using the index in the system image list) + int index = getIconIndex(parentIShellIcon, relativePIDL); + if (index > 0) { + Map imageCache; + if (isLink()) { + imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages; + } else { + imageCache = getLargeIcon ? largeSystemImages : smallSystemImages; + } + newIcon = (Image) imageCache.get(Integer.valueOf(index)); + if (newIcon == null) { + long hIcon = getIcon(getAbsolutePath(), getLargeIcon); + newIcon = makeIcon(hIcon, getLargeIcon); + disposeIcon(hIcon); + if (newIcon != null) { + imageCache.put(Integer.valueOf(index), newIcon); + } + } + } } + + if (newIcon == null) { + // These are only cached per object + long hIcon = extractIcon(getParentIShellFolder(), + getRelativePIDL(), getLargeIcon); + newIcon = makeIcon(hIcon, getLargeIcon); + disposeIcon(hIcon); + } + + if (newIcon == null) { + newIcon = Win32ShellFolder2.super.getIcon(getLargeIcon); + } + return newIcon; } - } - } - - if (icon == null) { - // These are only cached per object - long hIcon = extractIcon(getParentIShellFolder(), getRelativePIDL(), getLargeIcon); - icon = makeIcon(hIcon, getLargeIcon); - disposeIcon(hIcon); - } - + }); if (getLargeIcon) { largeIcon = icon; } else { smallIcon = icon; } } - if (icon == null) { - icon = super.getIcon(getLargeIcon); - } return icon; } @@ -969,39 +1113,50 @@ final class Win32ShellFolder2 extends ShellFolder { private static final int LVCFMT_CENTER = 2; public ShellFolderColumnInfo[] getFolderColumns() { - ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder()); + return ShellFolder.getInvoker().invoke(new Callable<ShellFolderColumnInfo[]>() { + public ShellFolderColumnInfo[] call() throws Exception { + ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder()); - if (columns != null) { - List<ShellFolderColumnInfo> notNullColumns = - new ArrayList<ShellFolderColumnInfo>(); - for (int i = 0; i < columns.length; i++) { - ShellFolderColumnInfo column = columns[i]; - if (column != null) { - column.setAlignment(column.getAlignment() == LVCFMT_RIGHT - ? SwingConstants.RIGHT - : column.getAlignment() == LVCFMT_CENTER - ? SwingConstants.CENTER - : SwingConstants.LEADING); + if (columns != null) { + List<ShellFolderColumnInfo> notNullColumns = + new ArrayList<ShellFolderColumnInfo>(); + for (int i = 0; i < columns.length; i++) { + ShellFolderColumnInfo column = columns[i]; + if (column != null) { + column.setAlignment(column.getAlignment() == LVCFMT_RIGHT + ? SwingConstants.RIGHT + : column.getAlignment() == LVCFMT_CENTER + ? SwingConstants.CENTER + : SwingConstants.LEADING); - column.setComparator(new ColumnComparator(getIShellFolder(), i)); + column.setComparator(new ColumnComparator(getIShellFolder(), i)); - notNullColumns.add(column); + notNullColumns.add(column); + } + } + columns = new ShellFolderColumnInfo[notNullColumns.size()]; + notNullColumns.toArray(columns); } + return columns; } - columns = new ShellFolderColumnInfo[notNullColumns.size()]; - notNullColumns.toArray(columns); - } - return columns; + }); } - public Object getFolderColumnValue(int column) { - return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column); + public Object getFolderColumnValue(final int column) { + return ShellFolder.getInvoker().invoke(new Callable<Object>() { + public Object call() throws Exception { + return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column); + } + }); } + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native ShellFolderColumnInfo[] doGetColumnInfo(long iShellFolder2); + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native Object doGetColumnValue(long parentIShellFolder2, long childPIDL, int columnIdx); + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native int compareIDsByColumn(long pParentIShellFolder, long pidl1, long pidl2, int columnIdx); @@ -1020,17 +1175,20 @@ final class Win32ShellFolder2 extends ShellFolder { } // compares 2 objects within this folder by the specified column - public int compare(File o, File o1) { - if (o instanceof Win32ShellFolder2 - && o1 instanceof Win32ShellFolder2) { - // delegates comparison to native method - return compareIDsByColumn(parentIShellFolder, - ((Win32ShellFolder2) o).getRelativePIDL(), - ((Win32ShellFolder2) o1).getRelativePIDL(), - columnIdx); - } - return 0; + public int compare(final File o, final File o1) { + return ShellFolder.getInvoker().invoke(new Callable<Integer>() { + public Integer call() throws Exception { + if (o instanceof Win32ShellFolder2 + && o1 instanceof Win32ShellFolder2) { + // delegates comparison to native method + return compareIDsByColumn(parentIShellFolder, + ((Win32ShellFolder2) o).getRelativePIDL(), + ((Win32ShellFolder2) o1).getRelativePIDL(), + columnIdx); + } + return 0; + } + }); } } - } diff --git a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index 0259e5533cd..563f474e2f2 100644 --- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -31,7 +31,10 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.*; +import java.util.concurrent.*; + import sun.security.action.LoadLibraryAction; import static sun.awt.shell.Win32ShellFolder2.*; @@ -408,4 +411,102 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { return name1.compareTo(name2); } } + + @Override + protected Invoker createInvoker() { + return new ComInvoker(); + } + + private static class ComInvoker extends ThreadPoolExecutor implements ThreadFactory, ShellFolder.Invoker { + private static Thread comThread; + + private ComInvoker() { + super(1, 1, 0, TimeUnit.DAYS, new LinkedBlockingQueue<Runnable>()); + allowCoreThreadTimeOut(false); + setThreadFactory(this); + final Runnable shutdownHook = new Runnable() { + public void run() { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + shutdownNow(); + return null; + } + }); + } + }; + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + Runtime.getRuntime().addShutdownHook( + new Thread(shutdownHook) + ); + return null; + } + }); + } + + public synchronized Thread newThread(final Runnable task) { + final Runnable comRun = new Runnable() { + public void run() { + try { + initializeCom(); + task.run(); + } finally { + uninitializeCom(); + } + } + }; + comThread = + AccessController.doPrivileged( + new PrivilegedAction<Thread>() { + public Thread run() { + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + ThreadGroup tg = Thread.currentThread().getThreadGroup(); + for (ThreadGroup tgn = tg; + tgn != null; + tg = tgn, tgn = tg.getParent()); + Thread thread = new Thread(tg, comRun, "Swing-Shell"); + thread.setDaemon(true); + return thread; + } + } + ); + return comThread; + } + + public <T> T invoke(Callable<T> task) { + try { + T result; + if (Thread.currentThread() == comThread) { + // if it's already called from the COM + // thread, we don't need to delegate the task + result = task.call(); + } else { + Future<T> future = submit(task); + try { + result = future.get(); + } catch (InterruptedException e) { + result = null; + future.cancel(true); + } + } + return result; + } catch (Exception e) { + Throwable cause = (e instanceof ExecutionException) ? e.getCause() : e; + if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } + if (cause instanceof Error) { + throw (Error) cause; + } + throw new RuntimeException(cause); + } + } + } + + static native void initializeCom(); + + static native void uninitializeCom(); } diff --git a/jdk/src/windows/classes/sun/awt/windows/WFontConfiguration.java b/jdk/src/windows/classes/sun/awt/windows/WFontConfiguration.java index 4f2f8324ae4..2c7b00124a7 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WFontConfiguration.java +++ b/jdk/src/windows/classes/sun/awt/windows/WFontConfiguration.java @@ -61,18 +61,10 @@ public class WFontConfiguration extends FontConfiguration { * been opened and its fonts loaded. * Also note this usage is only enabled if a private flag is set. */ - if ("98".equals(osName) || "Me".equals(osName)) { - localeMap.put("dialoginput.plain.japanese", "\uff2d\uff33 \u660e\u671d"); - localeMap.put("dialoginput.bold.japanese", "\uff2d\uff33 \u660e\u671d"); - localeMap.put("dialoginput.italic.japanese", "\uff2d\uff33 \u660e\u671d"); - localeMap.put("dialoginput.bolditalic.japanese", "\uff2d\uff33 \u660e\u671d"); - } else { - - localeMap.put("dialoginput.plain.japanese", "MS Mincho"); - localeMap.put("dialoginput.bold.japanese", "MS Mincho"); - localeMap.put("dialoginput.italic.japanese", "MS Mincho"); - localeMap.put("dialoginput.bolditalic.japanese", "MS Mincho"); - } + localeMap.put("dialoginput.plain.japanese", "MS Mincho"); + localeMap.put("dialoginput.bold.japanese", "MS Mincho"); + localeMap.put("dialoginput.italic.japanese", "MS Mincho"); + localeMap.put("dialoginput.bolditalic.japanese", "MS Mincho"); } reorderMap = new HashMap(); reorderMap.put("UTF-8.hi", "devanagari"); diff --git a/jdk/src/windows/classes/sun/awt/windows/fontconfig.98.properties b/jdk/src/windows/classes/sun/awt/windows/fontconfig.98.properties deleted file mode 100644 index 8d69d410e25..00000000000 --- a/jdk/src/windows/classes/sun/awt/windows/fontconfig.98.properties +++ /dev/null @@ -1,241 +0,0 @@ -# -# -# Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# - -# Version - -version=1 - -# Component Font Mappings - -allfonts.chinese-ms936=SimSun -allfonts.dingbats=Wingdings -allfonts.lucida=Lucida Sans Regular -allfonts.symbol=Symbol -allfonts.thai=Lucida Sans Regular - -serif.plain.alphabetic=Times New Roman -serif.plain.chinese-ms950=MingLiU -serif.plain.hebrew=David -serif.plain.japanese=\uff2d\uff33 \u660e\u671d -serif.plain.korean=Batang - -serif.bold.alphabetic=Times New Roman Bold -serif.bold.chinese-ms950=PMingLiU -serif.bold.hebrew=David Bold -serif.bold.japanese=\uff2d\uff33 \u660e\u671d -serif.bold.korean=Batang - -serif.italic.alphabetic=Times New Roman Italic -serif.italic.chinese-ms950=PMingLiU -serif.italic.hebrew=David -serif.italic.japanese=\uff2d\uff33 \u660e\u671d -serif.italic.korean=Batang - -serif.bolditalic.alphabetic=Times New Roman Bold Italic -serif.bolditalic.chinese-ms950=PMingLiU -serif.bolditalic.hebrew=David Bold -serif.bolditalic.japanese=\uff2d\uff33 \u660e\u671d -serif.bolditalic.korean=Batang - -sansserif.plain.alphabetic=Arial -sansserif.plain.chinese-ms950=MingLiU -sansserif.plain.hebrew=David -sansserif.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.plain.korean=Gulim - -sansserif.bold.alphabetic=Arial Bold -sansserif.bold.chinese-ms950=PMingLiU -sansserif.bold.hebrew=David Bold -sansserif.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.bold.korean=Gulim - -sansserif.italic.alphabetic=Arial Italic -sansserif.italic.chinese-ms950=PMingLiU -sansserif.italic.hebrew=David -sansserif.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.italic.korean=Gulim - -sansserif.bolditalic.alphabetic=Arial Bold Italic -sansserif.bolditalic.chinese-ms950=PMingLiU -sansserif.bolditalic.hebrew=David Bold -sansserif.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.bolditalic.korean=Gulim - -monospaced.plain.alphabetic=Courier New -monospaced.plain.chinese-ms950=MingLiU -monospaced.plain.hebrew=David -monospaced.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.plain.korean=GulimChe - -monospaced.bold.alphabetic=Courier New Bold -monospaced.bold.chinese-ms950=PMingLiU -monospaced.bold.hebrew=David Bold -monospaced.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.bold.korean=GulimChe - -monospaced.italic.alphabetic=Courier New Italic -monospaced.italic.chinese-ms950=PMingLiU -monospaced.italic.hebrew=David -monospaced.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.italic.korean=GulimChe - -monospaced.bolditalic.alphabetic=Courier New Bold Italic -monospaced.bolditalic.chinese-ms950=PMingLiU -monospaced.bolditalic.hebrew=David Bold -monospaced.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.bolditalic.korean=GulimChe - -dialog.plain.alphabetic=Arial -dialog.plain.chinese-ms950=MingLiU -dialog.plain.hebrew=David -dialog.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.plain.korean=Gulim - -dialog.bold.alphabetic=Arial Bold -dialog.bold.chinese-ms950=PMingLiU -dialog.bold.hebrew=David Bold -dialog.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.bold.korean=Gulim - -dialog.italic.alphabetic=Arial Italic -dialog.italic.chinese-ms950=PMingLiU -dialog.italic.hebrew=David -dialog.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.italic.korean=Gulim - -dialog.bolditalic.alphabetic=Arial Bold Italic -dialog.bolditalic.chinese-ms950=PMingLiU -dialog.bolditalic.hebrew=David Bold -dialog.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.bolditalic.korean=Gulim - -dialoginput.plain.alphabetic=Courier New -dialoginput.plain.chinese-ms950=MingLiU -dialoginput.plain.hebrew=David -dialoginput.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.plain.korean=Gulim - -dialoginput.bold.alphabetic=Courier New Bold -dialoginput.bold.chinese-ms950=PMingLiU -dialoginput.bold.hebrew=David Bold -dialoginput.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.bold.korean=Gulim - -dialoginput.italic.alphabetic=Courier New Italic -dialoginput.italic.chinese-ms950=PMingLiU -dialoginput.italic.hebrew=David -dialoginput.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.italic.korean=Gulim - -dialoginput.bolditalic.alphabetic=Courier New Bold Italic -dialoginput.bolditalic.chinese-ms950=PMingLiU -dialoginput.bolditalic.hebrew=David Bold -dialoginput.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.bolditalic.korean=Gulim - -# Search Sequences - -sequence.allfonts=alphabetic/default,dingbats,symbol - -sequence.serif.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.sansserif.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.monospaced.GBK=chinese-ms936,alphabetic/1252,dingbats,symbol -sequence.dialog.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.dialoginput.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol - -sequence.serif.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.sansserif.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.monospaced.x-windows-950=chinese-ms950,alphabetic/1252,dingbats,symbol -sequence.dialog.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.dialoginput.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol - -sequence.allfonts.windows-1255=hebrew,alphabetic/1252,dingbats,symbol - -sequence.serif.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.sansserif.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.monospaced.windows-31j=japanese,alphabetic/1252,dingbats,symbol -sequence.dialog.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.dialoginput.windows-31j=alphabetic/1252,japanese,dingbats,symbol - -sequence.serif.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.sansserif.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.monospaced.x-windows-949=korean,alphabetic/1252,dingbats,symbol -sequence.dialog.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.dialoginput.x-windows-949=alphabetic/1252,korean,dingbats,symbol - -sequence.allfonts.x-windows-874=alphabetic/1252,thai,dingbats,symbol - -sequence.fallback=lucida - -# Exclusion Ranges - -exclusion.alphabetic=0700-1e9f,1f00-20ab,20ad-f8ff -exclusion.hebrew=0041-005a,0060-007a,007f-00ff,20ac-20ac - -# Monospaced to Proportional width variant mapping -# (Experimental private syntax) -proportional.\uff2d\uff33_\u30b4\u30b7\u30c3\u30af=\uff2d\uff33 \uff30\u30b4\u30b7\u30c3\u30af -proportional.\uff2d\uff33_\u660e\u671d=\uff2d\uff33 \uff30\u660e\u671d -proportional.MingLiU=PMingLiU - -# Font File Names - -filename.Arial=ARIAL.TTF -filename.Arial_Bold=ARIALBD.TTF -filename.Arial_Italic=ARIALI.TTF -filename.Arial_Bold_Italic=ARIALBI.TTF - -filename.Courier_New=COUR.TTF -filename.Courier_New_Bold=COURBD.TTF -filename.Courier_New_Italic=COURI.TTF -filename.Courier_New_Bold_Italic=COURBI.TTF - -filename.Times_New_Roman=TIMES.TTF -filename.Times_New_Roman_Bold=TIMESBD.TTF -filename.Times_New_Roman_Italic=TIMESI.TTF -filename.Times_New_Roman_Bold_Italic=TIMESBI.TTF - -filename.SimSun=SIMSUN.TTF - -filename.MingLiU=MINGLIU.TTC -filename.PMingLiU=MINGLIU.TTC - -filename.David=DAVID.TTF -filename.David_Bold=DAVIDBD.TTF - -filename.\uff2d\uff33_\u660e\u671d=MSMINCHO.TTC -filename.\uff2d\uff33_\uff30\u660e\u671d=MSMINCHO.TTC -filename.\uff2d\uff33_\u30b4\u30b7\u30c3\u30af=MSGOTHIC.TTC -filename.\uff2d\uff33_\uff30\u30b4\u30b7\u30c3\u30af=MSGOTHIC.TTC - -filename.Gulim=gulim.TTC -filename.Batang=batang.TTC -filename.GulimChe=gulim.TTC - -filename.Lucida_Sans_Regular=LucidaSansRegular.ttf -filename.Symbol=SYMBOL.TTF -filename.Wingdings=WINGDING.TTF - diff --git a/jdk/src/windows/classes/sun/awt/windows/fontconfig.Me.properties b/jdk/src/windows/classes/sun/awt/windows/fontconfig.Me.properties deleted file mode 100644 index 8d69d410e25..00000000000 --- a/jdk/src/windows/classes/sun/awt/windows/fontconfig.Me.properties +++ /dev/null @@ -1,241 +0,0 @@ -# -# -# Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# - -# Version - -version=1 - -# Component Font Mappings - -allfonts.chinese-ms936=SimSun -allfonts.dingbats=Wingdings -allfonts.lucida=Lucida Sans Regular -allfonts.symbol=Symbol -allfonts.thai=Lucida Sans Regular - -serif.plain.alphabetic=Times New Roman -serif.plain.chinese-ms950=MingLiU -serif.plain.hebrew=David -serif.plain.japanese=\uff2d\uff33 \u660e\u671d -serif.plain.korean=Batang - -serif.bold.alphabetic=Times New Roman Bold -serif.bold.chinese-ms950=PMingLiU -serif.bold.hebrew=David Bold -serif.bold.japanese=\uff2d\uff33 \u660e\u671d -serif.bold.korean=Batang - -serif.italic.alphabetic=Times New Roman Italic -serif.italic.chinese-ms950=PMingLiU -serif.italic.hebrew=David -serif.italic.japanese=\uff2d\uff33 \u660e\u671d -serif.italic.korean=Batang - -serif.bolditalic.alphabetic=Times New Roman Bold Italic -serif.bolditalic.chinese-ms950=PMingLiU -serif.bolditalic.hebrew=David Bold -serif.bolditalic.japanese=\uff2d\uff33 \u660e\u671d -serif.bolditalic.korean=Batang - -sansserif.plain.alphabetic=Arial -sansserif.plain.chinese-ms950=MingLiU -sansserif.plain.hebrew=David -sansserif.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.plain.korean=Gulim - -sansserif.bold.alphabetic=Arial Bold -sansserif.bold.chinese-ms950=PMingLiU -sansserif.bold.hebrew=David Bold -sansserif.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.bold.korean=Gulim - -sansserif.italic.alphabetic=Arial Italic -sansserif.italic.chinese-ms950=PMingLiU -sansserif.italic.hebrew=David -sansserif.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.italic.korean=Gulim - -sansserif.bolditalic.alphabetic=Arial Bold Italic -sansserif.bolditalic.chinese-ms950=PMingLiU -sansserif.bolditalic.hebrew=David Bold -sansserif.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.bolditalic.korean=Gulim - -monospaced.plain.alphabetic=Courier New -monospaced.plain.chinese-ms950=MingLiU -monospaced.plain.hebrew=David -monospaced.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.plain.korean=GulimChe - -monospaced.bold.alphabetic=Courier New Bold -monospaced.bold.chinese-ms950=PMingLiU -monospaced.bold.hebrew=David Bold -monospaced.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.bold.korean=GulimChe - -monospaced.italic.alphabetic=Courier New Italic -monospaced.italic.chinese-ms950=PMingLiU -monospaced.italic.hebrew=David -monospaced.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.italic.korean=GulimChe - -monospaced.bolditalic.alphabetic=Courier New Bold Italic -monospaced.bolditalic.chinese-ms950=PMingLiU -monospaced.bolditalic.hebrew=David Bold -monospaced.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.bolditalic.korean=GulimChe - -dialog.plain.alphabetic=Arial -dialog.plain.chinese-ms950=MingLiU -dialog.plain.hebrew=David -dialog.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.plain.korean=Gulim - -dialog.bold.alphabetic=Arial Bold -dialog.bold.chinese-ms950=PMingLiU -dialog.bold.hebrew=David Bold -dialog.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.bold.korean=Gulim - -dialog.italic.alphabetic=Arial Italic -dialog.italic.chinese-ms950=PMingLiU -dialog.italic.hebrew=David -dialog.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.italic.korean=Gulim - -dialog.bolditalic.alphabetic=Arial Bold Italic -dialog.bolditalic.chinese-ms950=PMingLiU -dialog.bolditalic.hebrew=David Bold -dialog.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.bolditalic.korean=Gulim - -dialoginput.plain.alphabetic=Courier New -dialoginput.plain.chinese-ms950=MingLiU -dialoginput.plain.hebrew=David -dialoginput.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.plain.korean=Gulim - -dialoginput.bold.alphabetic=Courier New Bold -dialoginput.bold.chinese-ms950=PMingLiU -dialoginput.bold.hebrew=David Bold -dialoginput.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.bold.korean=Gulim - -dialoginput.italic.alphabetic=Courier New Italic -dialoginput.italic.chinese-ms950=PMingLiU -dialoginput.italic.hebrew=David -dialoginput.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.italic.korean=Gulim - -dialoginput.bolditalic.alphabetic=Courier New Bold Italic -dialoginput.bolditalic.chinese-ms950=PMingLiU -dialoginput.bolditalic.hebrew=David Bold -dialoginput.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.bolditalic.korean=Gulim - -# Search Sequences - -sequence.allfonts=alphabetic/default,dingbats,symbol - -sequence.serif.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.sansserif.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.monospaced.GBK=chinese-ms936,alphabetic/1252,dingbats,symbol -sequence.dialog.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.dialoginput.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol - -sequence.serif.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.sansserif.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.monospaced.x-windows-950=chinese-ms950,alphabetic/1252,dingbats,symbol -sequence.dialog.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.dialoginput.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol - -sequence.allfonts.windows-1255=hebrew,alphabetic/1252,dingbats,symbol - -sequence.serif.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.sansserif.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.monospaced.windows-31j=japanese,alphabetic/1252,dingbats,symbol -sequence.dialog.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.dialoginput.windows-31j=alphabetic/1252,japanese,dingbats,symbol - -sequence.serif.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.sansserif.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.monospaced.x-windows-949=korean,alphabetic/1252,dingbats,symbol -sequence.dialog.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.dialoginput.x-windows-949=alphabetic/1252,korean,dingbats,symbol - -sequence.allfonts.x-windows-874=alphabetic/1252,thai,dingbats,symbol - -sequence.fallback=lucida - -# Exclusion Ranges - -exclusion.alphabetic=0700-1e9f,1f00-20ab,20ad-f8ff -exclusion.hebrew=0041-005a,0060-007a,007f-00ff,20ac-20ac - -# Monospaced to Proportional width variant mapping -# (Experimental private syntax) -proportional.\uff2d\uff33_\u30b4\u30b7\u30c3\u30af=\uff2d\uff33 \uff30\u30b4\u30b7\u30c3\u30af -proportional.\uff2d\uff33_\u660e\u671d=\uff2d\uff33 \uff30\u660e\u671d -proportional.MingLiU=PMingLiU - -# Font File Names - -filename.Arial=ARIAL.TTF -filename.Arial_Bold=ARIALBD.TTF -filename.Arial_Italic=ARIALI.TTF -filename.Arial_Bold_Italic=ARIALBI.TTF - -filename.Courier_New=COUR.TTF -filename.Courier_New_Bold=COURBD.TTF -filename.Courier_New_Italic=COURI.TTF -filename.Courier_New_Bold_Italic=COURBI.TTF - -filename.Times_New_Roman=TIMES.TTF -filename.Times_New_Roman_Bold=TIMESBD.TTF -filename.Times_New_Roman_Italic=TIMESI.TTF -filename.Times_New_Roman_Bold_Italic=TIMESBI.TTF - -filename.SimSun=SIMSUN.TTF - -filename.MingLiU=MINGLIU.TTC -filename.PMingLiU=MINGLIU.TTC - -filename.David=DAVID.TTF -filename.David_Bold=DAVIDBD.TTF - -filename.\uff2d\uff33_\u660e\u671d=MSMINCHO.TTC -filename.\uff2d\uff33_\uff30\u660e\u671d=MSMINCHO.TTC -filename.\uff2d\uff33_\u30b4\u30b7\u30c3\u30af=MSGOTHIC.TTC -filename.\uff2d\uff33_\uff30\u30b4\u30b7\u30c3\u30af=MSGOTHIC.TTC - -filename.Gulim=gulim.TTC -filename.Batang=batang.TTC -filename.GulimChe=gulim.TTC - -filename.Lucida_Sans_Regular=LucidaSansRegular.ttf -filename.Symbol=SYMBOL.TTF -filename.Wingdings=WINGDING.TTF - diff --git a/jdk/src/windows/classes/sun/net/NetHooks.java b/jdk/src/windows/classes/sun/net/NetHooks.java new file mode 100644 index 00000000000..0d8f60b3a42 --- /dev/null +++ b/jdk/src/windows/classes/sun/net/NetHooks.java @@ -0,0 +1,59 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package sun.net; + +import java.net.InetAddress; +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * Defines static methods to ensure that any installed net hooks are invoked + * prior to binding or connecting TCP sockets. + */ + +public final class NetHooks { + + /** + * Invoke prior to binding a TCP socket. + */ + public static void beforeTcpBind(FileDescriptor fdObj, + InetAddress address, + int port) + throws IOException + { + // nothing to do + } + + /** + * Invoke prior to connecting an unbound TCP socket. + */ + public static void beforeTcpConnect(FileDescriptor fdObj, + InetAddress address, + int port) + throws IOException + { + // nothing to do + } +} diff --git a/jdk/src/windows/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/jdk/src/windows/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java new file mode 100644 index 00000000000..6187aa31878 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.spi.AsynchronousChannelProvider; + +/** + * Creates this platform's default asynchronous channel provider + */ + +public class DefaultAsynchronousChannelProvider { + private DefaultAsynchronousChannelProvider() { } + + /** + * Returns the default AsynchronousChannelProvider. + */ + public static AsynchronousChannelProvider create() { + return new WindowsAsynchronousChannelProvider(); + } +} diff --git a/jdk/src/windows/classes/sun/nio/ch/FileDispatcher.java b/jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java similarity index 71% rename from jdk/src/windows/classes/sun/nio/ch/FileDispatcher.java rename to jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java index 6928449664f..30390f7a61b 100644 --- a/jdk/src/windows/classes/sun/nio/ch/FileDispatcher.java +++ b/jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,7 @@ package sun.nio.ch; import java.io.*; - -/** - * Allows different platforms to call different native methods - * for read and write operations. - */ - -class FileDispatcher extends NativeDispatcher +class FileDispatcherImpl extends FileDispatcher { static { @@ -74,6 +68,28 @@ class FileDispatcher extends NativeDispatcher return writev0(fd, address, len); } + int force(FileDescriptor fd, boolean metaData) throws IOException { + return force0(fd, metaData); + } + + int truncate(FileDescriptor fd, long size) throws IOException { + return truncate0(fd, size); + } + + long size(FileDescriptor fd) throws IOException { + return size0(fd); + } + + int lock(FileDescriptor fd, boolean blocking, long pos, long size, + boolean shared) throws IOException + { + return lock0(fd, blocking, pos, size, shared); + } + + void release(FileDescriptor fd, long pos, long size) throws IOException { + release0(fd, pos, size); + } + void close(FileDescriptor fd) throws IOException { close0(fd); } @@ -98,6 +114,20 @@ class FileDispatcher extends NativeDispatcher static native long writev0(FileDescriptor fd, long address, int len) throws IOException; + static native int force0(FileDescriptor fd, boolean metaData) + throws IOException; + + static native int truncate0(FileDescriptor fd, long size) + throws IOException; + + static native long size0(FileDescriptor fd) throws IOException; + + static native int lock0(FileDescriptor fd, boolean blocking, long pos, + long size, boolean shared) throws IOException; + + static native void release0(FileDescriptor fd, long pos, long size) + throws IOException; + static native void close0(FileDescriptor fd) throws IOException; static native void closeByHandle(long fd) throws IOException; diff --git a/jdk/src/windows/classes/sun/nio/ch/Iocp.java b/jdk/src/windows/classes/sun/nio/ch/Iocp.java new file mode 100644 index 00000000000..b4c2cdef61e --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/ch/Iocp.java @@ -0,0 +1,437 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.io.Closeable; +import java.io.IOException; +import java.io.FileDescriptor; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import sun.misc.Unsafe; + +/** + * Windows implementation of AsynchronousChannelGroup encapsulating an I/O + * completion port. + */ + +class Iocp extends AsynchronousChannelGroupImpl { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long INVALID_HANDLE_VALUE = -1L; + + // maps completion key to channel + private final ReadWriteLock keyToChannelLock = new ReentrantReadWriteLock(); + private final Map<Integer,OverlappedChannel> keyToChannel = + new HashMap<Integer,OverlappedChannel>(); + private int nextCompletionKey; + + // handle to completion port + private final long port; + + // true if port has been closed + private boolean closed; + + // the set of "stale" OVERLAPPED structures. These OVERLAPPED structures + // relate to I/O operations where the completion notification was not + // received in a timely manner after the channel is closed. + private final Set<Long> staleIoSet = new HashSet<Long>(); + + Iocp(AsynchronousChannelProvider provider, ThreadPool pool) + throws IOException + { + super(provider, pool); + this.port = + createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, fixedThreadCount()); + this.nextCompletionKey = 1; + } + + Iocp start() { + startThreads(new EventHandlerTask()); + return this; + } + + /* + * Channels implements this interface support overlapped I/O and can be + * associated with a completion port. + */ + static interface OverlappedChannel extends Closeable { + /** + * Returns a reference to the pending I/O result. + */ + <V,A> PendingFuture<V,A> getByOverlapped(long overlapped); + } + + // release all resources + void implClose() { + synchronized (this) { + if (closed) + return; + closed = true; + } + close0(port); + synchronized (staleIoSet) { + for (Long ov: staleIoSet) { + unsafe.freeMemory(ov); + } + staleIoSet.clear(); + } + } + + @Override + boolean isEmpty() { + keyToChannelLock.writeLock().lock(); + try { + return keyToChannel.isEmpty(); + } finally { + keyToChannelLock.writeLock().unlock(); + } + } + + @Override + final Object attachForeignChannel(final Channel channel, FileDescriptor fdObj) + throws IOException + { + int key = associate(new OverlappedChannel() { + public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) { + return null; + } + public void close() throws IOException { + channel.close(); + } + }, 0L); + return Integer.valueOf(key); + } + + @Override + final void detachForeignChannel(Object key) { + disassociate((Integer)key); + } + + @Override + void closeAllChannels() { + /** + * On Windows the close operation will close the socket/file handle + * and then wait until all outstanding I/O operations have aborted. + * This is necessary as each channel's cache of OVERLAPPED structures + * can only be freed once all I/O operations have completed. As I/O + * completion requires a lookup of the keyToChannel then we must close + * the channels when not holding the write lock. + */ + final int MAX_BATCH_SIZE = 32; + OverlappedChannel channels[] = new OverlappedChannel[MAX_BATCH_SIZE]; + int count; + do { + // grab a batch of up to 32 channels + keyToChannelLock.writeLock().lock(); + count = 0; + try { + for (Integer key: keyToChannel.keySet()) { + channels[count++] = keyToChannel.get(key); + if (count >= MAX_BATCH_SIZE) + break; + } + } finally { + keyToChannelLock.writeLock().unlock(); + } + + // close them + for (int i=0; i<count; i++) { + try { + channels[i].close(); + } catch (IOException ignore) { } + } + } while (count > 0); + } + + private void wakeup() { + try { + postQueuedCompletionStatus(port, 0); + } catch (IOException e) { + // should not happen + throw new AssertionError(e); + } + } + + @Override + void executeOnHandlerTask(Runnable task) { + synchronized (this) { + if (closed) + throw new RejectedExecutionException(); + offerTask(task); + wakeup(); + } + + } + + @Override + void shutdownHandlerTasks() { + // shutdown all handler threads + int nThreads = threadCount(); + while (nThreads-- > 0) { + wakeup(); + } + } + + /** + * Associate the given handle with this group + */ + int associate(OverlappedChannel ch, long handle) throws IOException { + keyToChannelLock.writeLock().lock(); + + // generate a completion key (if not shutdown) + int key; + try { + if (isShutdown()) + throw new ShutdownChannelGroupException(); + + // generate unique key + do { + key = nextCompletionKey++; + } while ((key == 0) || keyToChannel.containsKey(key)); + + // associate with I/O completion port + if (handle != 0L) + createIoCompletionPort(handle, port, key, 0); + + // setup mapping + keyToChannel.put(key, ch); + } finally { + keyToChannelLock.writeLock().unlock(); + } + return key; + } + + /** + * Disassociate channel from the group. + */ + void disassociate(int key) { + boolean checkForShutdown = false; + + keyToChannelLock.writeLock().lock(); + try { + keyToChannel.remove(key); + + // last key to be removed so check if group is shutdown + if (keyToChannel.isEmpty()) + checkForShutdown = true; + + } finally { + keyToChannelLock.writeLock().unlock(); + } + + // continue shutdown + if (checkForShutdown && isShutdown()) { + try { + shutdownNow(); + } catch (IOException ignore) { } + } + } + + /** + * Invoked when a channel associated with this port is closed before + * notifications for all outstanding I/O operations have been received. + */ + void makeStale(Long overlapped) { + synchronized (staleIoSet) { + staleIoSet.add(overlapped); + } + } + + /** + * Checks if the given OVERLAPPED is stale and if so, releases it. + */ + private void checkIfStale(long ov) { + synchronized (staleIoSet) { + boolean removed = staleIoSet.remove(ov); + if (removed) { + unsafe.freeMemory(ov); + } + } + } + + /** + * The handler for consuming the result of an asynchronous I/O operation. + */ + static interface ResultHandler { + /** + * Invoked if the I/O operation completes successfully. + */ + public void completed(int bytesTransferred); + + /** + * Invoked if the I/O operation fails. + */ + public void failed(int error, IOException ioe); + } + + // Creates IOException for the given I/O error. + private static IOException translateErrorToIOException(int error) { + String msg = getErrorMessage(error); + if (msg == null) + msg = "Unknown error: 0x0" + Integer.toHexString(error); + return new IOException(msg); + } + + /** + * Long-running task servicing system-wide or per-file completion port + */ + private class EventHandlerTask implements Runnable { + public void run() { + Invoker.GroupAndInvokeCount myGroupAndInvokeCount = + Invoker.getGroupAndInvokeCount(); + CompletionStatus ioResult = new CompletionStatus(); + boolean replaceMe = false; + + try { + for (;;) { + // reset invoke count + if (myGroupAndInvokeCount != null) + myGroupAndInvokeCount.resetInvokeCount(); + + // wait for I/O completion event + // A error here is fatal (thread will not be replaced) + replaceMe = false; + try { + getQueuedCompletionStatus(port, ioResult); + } catch (IOException x) { + // should not happen + x.printStackTrace(); + return; + } + + // handle wakeup to execute task or shutdown + if (ioResult.completionKey() == 0 && + ioResult.overlapped() == 0L) + { + Runnable task = pollTask(); + if (task == null) { + // shutdown request + return; + } + + // run task + // (if error/exception then replace thread) + replaceMe = true; + task.run(); + continue; + } + + // map key to channel + OverlappedChannel ch = null; + keyToChannelLock.readLock().lock(); + try { + ch = keyToChannel.get(ioResult.completionKey()); + if (ch == null) { + checkIfStale(ioResult.overlapped()); + continue; + } + } finally { + keyToChannelLock.readLock().unlock(); + } + + // lookup I/O request + PendingFuture<?,?> result = ch.getByOverlapped(ioResult.overlapped()); + if (result == null) { + // we get here if the OVERLAPPED structure is associated + // with an I/O operation on a channel that was closed + // but the I/O operation event wasn't read in a timely + // manner. Alternatively, it may be related to a + // tryLock operation as the OVERLAPPED structures for + // these operations are not in the I/O cache. + checkIfStale(ioResult.overlapped()); + continue; + } + + // synchronize on result in case I/O completed immediately + // and was handled by initiator + synchronized (result) { + if (result.isDone()) { + continue; + } + // not handled by initiator + } + + // invoke I/O result handler + int error = ioResult.error(); + ResultHandler rh = (ResultHandler)result.getContext(); + replaceMe = true; // (if error/exception then replace thread) + if (error == 0) { + rh.completed(ioResult.bytesTransferred()); + } else { + rh.failed(error, translateErrorToIOException(error)); + } + } + } finally { + // last thread to exit when shutdown releases resources + int remaining = threadExit(this, replaceMe); + if (remaining == 0 && isShutdown()) { + implClose(); + } + } + } + } + + /** + * Container for data returned by GetQueuedCompletionStatus + */ + private static class CompletionStatus { + private int error; + private int bytesTransferred; + private int completionKey; + private long overlapped; + + private CompletionStatus() { } + int error() { return error; } + int bytesTransferred() { return bytesTransferred; } + int completionKey() { return completionKey; } + long overlapped() { return overlapped; } + } + + // -- native methods -- + + private static native void initIDs(); + + private static native long createIoCompletionPort(long handle, + long existingPort, int completionKey, int concurrency) throws IOException; + + private static native void close0(long handle); + + private static native void getQueuedCompletionStatus(long completionPort, + CompletionStatus status) throws IOException; + + private static native void postQueuedCompletionStatus(long completionPort, + int completionKey) throws IOException; + + private static native String getErrorMessage(int error); + + static { + Util.load(); + initIDs(); + } +} diff --git a/jdk/src/windows/classes/sun/nio/ch/PendingIoCache.java b/jdk/src/windows/classes/sun/nio/ch/PendingIoCache.java new file mode 100644 index 00000000000..2e3d50385fc --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/ch/PendingIoCache.java @@ -0,0 +1,161 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.util.*; +import sun.misc.Unsafe; + +/** + * Maintains a mapping of pending I/O requests (identified by the address of + * an OVERLAPPED structure) to Futures. + */ + +class PendingIoCache { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final int addressSize = unsafe.addressSize(); + + private static int dependsArch(int value32, int value64) { + return (addressSize == 4) ? value32 : value64; + } + + /* + * typedef struct _OVERLAPPED { + * DWORD Internal; + * DWORD InternalHigh; + * DWORD Offset; + * DWORD OffsetHigh; + * HANDLE hEvent; + * } OVERLAPPED; + */ + private static final int SIZEOF_OVERLAPPED = dependsArch(20, 32); + + // set to true when closed + private boolean closed; + + // set to true when thread is waiting for all I/O operations to complete + private boolean closePending; + + // maps OVERLAPPED to PendingFuture + private final Map<Long,PendingFuture> pendingIoMap = + new HashMap<Long,PendingFuture>(); + + // per-channel cache of OVERLAPPED structures + private long[] overlappedCache = new long[4]; + private int overlappedCacheCount = 0; + + PendingIoCache() { + } + + long add(PendingFuture<?,?> result) { + synchronized (this) { + if (closed) + throw new AssertionError("Should not get here"); + long ov; + if (overlappedCacheCount > 0) { + ov = overlappedCache[--overlappedCacheCount]; + } else { + ov = unsafe.allocateMemory(SIZEOF_OVERLAPPED); + } + pendingIoMap.put(ov, result); + return ov; + } + } + + @SuppressWarnings("unchecked") + <V,A> PendingFuture<V,A> remove(long overlapped) { + synchronized (this) { + PendingFuture<V,A> res = pendingIoMap.remove(overlapped); + if (res != null) { + if (overlappedCacheCount < overlappedCache.length) { + overlappedCache[overlappedCacheCount++] = overlapped; + } else { + // cache full or channel closing + unsafe.freeMemory(overlapped); + } + // notify closing thread. + if (closePending) { + this.notifyAll(); + } + } + return res; + } + } + + void close() { + synchronized (this) { + if (closed) + return; + + // handle the case that where there are I/O operations that have + // not completed. + if (!pendingIoMap.isEmpty()) + clearPendingIoMap(); + + // release memory for any cached OVERLAPPED structures + while (overlappedCacheCount > 0) { + unsafe.freeMemory( overlappedCache[--overlappedCacheCount] ); + } + + // done + closed = true; + } + } + + private void clearPendingIoMap() { + assert Thread.holdsLock(this); + + // wait up to 50ms for the I/O operations to complete + closePending = true; + try { + this.wait(50); + } catch (InterruptedException x) { } + closePending = false; + if (pendingIoMap.isEmpty()) + return; + + // cause all pending I/O operations to fail + // simulate the failure of all pending I/O operations. + for (Long ov: pendingIoMap.keySet()) { + PendingFuture<?,?> result = pendingIoMap.get(ov); + assert !result.isDone(); + + // make I/O port aware of the stale OVERLAPPED structure + Iocp iocp = (Iocp)((Groupable)result.channel()).group(); + iocp.makeStale(ov); + + // execute a task that invokes the result handler's failed method + final Iocp.ResultHandler rh = (Iocp.ResultHandler)result.getContext(); + Runnable task = new Runnable() { + public void run() { + rh.failed(-1, new AsynchronousCloseException()); + } + }; + iocp.executeOnPooledThread(task); + } + pendingIoMap.clear(); + } +} diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java new file mode 100644 index 00000000000..435b5297b2e --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java @@ -0,0 +1,101 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.net.ProtocolFamily; +import java.io.IOException; + +public class WindowsAsynchronousChannelProvider + extends AsynchronousChannelProvider +{ + private static volatile Iocp defaultIocp; + + public WindowsAsynchronousChannelProvider() { + // nothing to do + } + + private Iocp defaultIocp() throws IOException { + if (defaultIocp == null) { + synchronized (WindowsAsynchronousChannelProvider.class) { + if (defaultIocp == null) { + // default thread pool may be shared with AsynchronousFileChannels + defaultIocp = new Iocp(this, ThreadPool.getDefault()).start(); + } + } + } + return defaultIocp; + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory) + throws IOException + { + return new Iocp(this, ThreadPool.create(nThreads, factory)).start(); + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) + throws IOException + { + return new Iocp(this, ThreadPool.wrap(executor, initialSize)).start(); + } + + private Iocp toIocp(AsynchronousChannelGroup group) throws IOException { + if (group == null) { + return defaultIocp(); + } else { + if (!(group instanceof Iocp)) + throw new IllegalChannelGroupException(); + return (Iocp)group; + } + } + + @Override + public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new WindowsAsynchronousServerSocketChannelImpl(toIocp(group)); + } + + @Override + public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new WindowsAsynchronousSocketChannelImpl(toIocp(group)); + } + + @Override + public AsynchronousDatagramChannel openAsynchronousDatagramChannel(ProtocolFamily family, + AsynchronousChannelGroup group) + throws IOException + { + return new SimpleAsynchronousDatagramChannelImpl(family, toIocp(group)); + } +} diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java new file mode 100644 index 00000000000..ef668648d67 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java @@ -0,0 +1,741 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.util.concurrent.*; +import java.nio.ByteBuffer; +import java.nio.BufferOverflowException; +import java.io.IOException; +import java.io.FileDescriptor; +import sun.misc.SharedSecrets; +import sun.misc.JavaIOFileDescriptorAccess; + +/** + * Windows implementation of AsynchronousFileChannel using overlapped I/O. + */ + +public class WindowsAsynchronousFileChannelImpl + extends AsynchronousFileChannelImpl + implements Iocp.OverlappedChannel, Groupable +{ + private static final JavaIOFileDescriptorAccess fdAccess = + SharedSecrets.getJavaIOFileDescriptorAccess(); + + // error when EOF is detected asynchronously. + private static final int ERROR_HANDLE_EOF = 38; + + // Lazy initialization of default I/O completion port + private static class DefaultIocpHolder { + static final Iocp defaultIocp = defaultIocp(); + private static Iocp defaultIocp() { + try { + return new Iocp(null, ThreadPool.createDefault()).start(); + } catch (IOException ioe) { + InternalError e = new InternalError(); + e.initCause(ioe); + throw e; + } + } + } + + // Used for force/truncate/size methods + private static final FileDispatcher nd = new FileDispatcherImpl(); + + // The handle is extracted for use in native methods invoked from this class. + private final long handle; + + // The key that identifies the channel's association with the I/O port + private final int completionKey; + + // I/O completion port (group) + private final Iocp iocp; + + private final boolean isDefaultIocp; + + // Caches OVERLAPPED structure for each outstanding I/O operation + private final PendingIoCache ioCache; + + + private WindowsAsynchronousFileChannelImpl(FileDescriptor fdObj, + boolean reading, + boolean writing, + Iocp iocp, + boolean isDefaultIocp) + throws IOException + { + super(fdObj, reading, writing, iocp.executor()); + this.handle = fdAccess.getHandle(fdObj); + this.iocp = iocp; + this.isDefaultIocp = isDefaultIocp; + this.ioCache = new PendingIoCache(); + this.completionKey = iocp.associate(this, handle); + } + + public static AsynchronousFileChannel open(FileDescriptor fdo, + boolean reading, + boolean writing, + ThreadPool pool) + throws IOException + { + Iocp iocp; + boolean isDefaultIocp; + if (pool == null) { + iocp = DefaultIocpHolder.defaultIocp; + isDefaultIocp = true; + } else { + iocp = new Iocp(null, pool).start(); + isDefaultIocp = false; + } + try { + return new + WindowsAsynchronousFileChannelImpl(fdo, reading, writing, iocp, isDefaultIocp); + } catch (IOException x) { + // error binding to port so need to close it (if created for this channel) + if (!isDefaultIocp) + iocp.implClose(); + throw x; + } + } + + @Override + public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) { + return ioCache.remove(overlapped); + } + + @Override + public void close() throws IOException { + closeLock.writeLock().lock(); + try { + if (closed) + return; // already closed + closed = true; + } finally { + closeLock.writeLock().unlock(); + } + + // invalidate all locks held for this channel + invalidateAllLocks(); + + // close the file + close0(handle); + + // waits until all I/O operations have completed + ioCache.close(); + + // disassociate from port and shutdown thread pool if not default + iocp.disassociate(completionKey); + if (!isDefaultIocp) + iocp.shutdown(); + } + + @Override + public AsynchronousChannelGroupImpl group() { + return iocp; + } + + /** + * Translates Throwable to IOException + */ + private static IOException toIOException(Throwable x) { + if (x instanceof IOException) { + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + return (IOException)x; + } + return new IOException(x); + } + + @Override + public long size() throws IOException { + try { + begin(); + return nd.size(fdObj); + } finally { + end(); + } + } + + @Override + public AsynchronousFileChannel truncate(long size) throws IOException { + if (size < 0) + throw new IllegalArgumentException("Negative size"); + if (!writing) + throw new NonWritableChannelException(); + try { + begin(); + if (size > nd.size(fdObj)) + return this; + nd.truncate(fdObj, size); + } finally { + end(); + } + return this; + } + + @Override + public void force(boolean metaData) throws IOException { + try { + begin(); + nd.force(fdObj, metaData); + } finally { + end(); + } + } + + // -- file locking -- + + /** + * Task that initiates locking operation and handles completion result. + */ + private class LockTask<A> implements Runnable, Iocp.ResultHandler { + private final long position; + private final FileLockImpl fli; + private final PendingFuture<FileLock,A> result; + + LockTask(long position, + FileLockImpl fli, + PendingFuture<FileLock,A> result) + { + this.position = position; + this.fli = fli; + this.result = result; + } + + @Override + public void run() { + long overlapped = 0L; + try { + begin(); + + // allocate OVERLAPPED structure + overlapped = ioCache.add(result); + + // synchronize on result to avoid race with handler thread + // when lock is acquired immediately. + synchronized (result) { + int n = lockFile(handle, position, fli.size(), fli.isShared(), + overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + return; + } + // acquired lock immediately + result.setResult(fli); + } + + } catch (Throwable x) { + // lock failed or channel closed + removeFromFileLockTable(fli); + if (overlapped != 0L) + ioCache.remove(overlapped); + result.setFailure(toIOException(x)); + } finally { + end(); + } + + // invoke completion handler + Invoker.invoke(result.handler(), result); + } + + @Override + public void completed(int bytesTransferred) { + // release waiters and invoke completion handler + result.setResult(fli); + Invoker.invoke(result.handler(), result); + } + + @Override + public void failed(int error, IOException x) { + // lock not acquired so remove from lock table + removeFromFileLockTable(fli); + + // release waiters + if (isOpen()) { + result.setFailure(x); + } else { + result.setFailure(new AsynchronousCloseException()); + } + Invoker.invoke(result.handler(), result); + } + } + + @Override + public <A> Future<FileLock> lock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler<FileLock,? super A> handler) + { + if (shared && !reading) + throw new NonReadableChannelException(); + if (!shared && !writing) + throw new NonWritableChannelException(); + + // add to lock table + FileLockImpl fli = addToFileLockTable(position, size, shared); + if (fli == null) { + CompletedFuture<FileLock,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + // create Future and task that will be invoked to acquire lock + PendingFuture<FileLock,A> result = + new PendingFuture<FileLock,A>(this, handler, attachment); + LockTask lockTask = new LockTask<A>(position, fli, result); + result.setContext(lockTask); + + // initiate I/O (can only be done from thread in thread pool) + try { + Invoker.invokeOnThreadInThreadPool(this, lockTask); + } catch (ShutdownChannelGroupException e) { + // rollback + removeFromFileLockTable(fli); + throw e; + } + return result; + } + + static final int NO_LOCK = -1; // Failed to lock + static final int LOCKED = 0; // Obtained requested lock + + @Override + public FileLock tryLock(long position, long size, boolean shared) + throws IOException + { + if (shared && !reading) + throw new NonReadableChannelException(); + if (!shared && !writing) + throw new NonWritableChannelException(); + + // add to lock table + final FileLockImpl fli = addToFileLockTable(position, size, shared); + if (fli == null) + throw new ClosedChannelException(); + + boolean gotLock = false; + try { + begin(); + // try to acquire the lock + int res = nd.lock(fdObj, false, position, size, shared); + if (res == NO_LOCK) + return null; + gotLock = true; + return fli; + } finally { + if (!gotLock) + removeFromFileLockTable(fli); + end(); + } + } + + // invoke by FileFileImpl to release lock + @Override + void release(FileLockImpl fli) throws IOException { + try { + begin(); + nd.release(fdObj, fli.position(), fli.size()); + removeFromFileLockTable(fli); + } finally { + end(); + } + } + + /** + * Task that initiates read operation and handles completion result. + */ + private class ReadTask<A> implements Runnable, Iocp.ResultHandler { + private final ByteBuffer dst; + private final int pos, rem; // buffer position/remaining + private final long position; // file position + private final PendingFuture<Integer,A> result; + + // set to dst if direct; otherwise set to substituted direct buffer + private volatile ByteBuffer buf; + + ReadTask(ByteBuffer dst, + int pos, + int rem, + long position, + PendingFuture<Integer,A> result) + { + this.dst = dst; + this.pos = pos; + this.rem = rem; + this.position = position; + this.result = result; + } + + void releaseBufferIfSubstituted() { + if (buf != dst) + Util.releaseTemporaryDirectBuffer(buf); + } + + void updatePosition(int bytesTransferred) { + // if the I/O succeeded then adjust buffer position + if (bytesTransferred > 0) { + if (buf == dst) { + try { + dst.position(pos + bytesTransferred); + } catch (IllegalArgumentException x) { + // someone has changed the position; ignore + } + } else { + // had to substitute direct buffer + buf.position(bytesTransferred).flip(); + try { + dst.put(buf); + } catch (BufferOverflowException x) { + // someone has changed the position; ignore + } + } + } + } + + @Override + public void run() { + int n = -1; + long overlapped = 0L; + long address; + + // Substitute a native buffer if not direct + if (dst instanceof DirectBuffer) { + buf = dst; + address = ((DirectBuffer)dst).address() + pos; + } else { + buf = Util.getTemporaryDirectBuffer(rem); + address = ((DirectBuffer)buf).address(); + } + + try { + begin(); + + // allocate OVERLAPPED + overlapped = ioCache.add(result); + + // synchronize on result to allow this thread handle the case + // where the read completes immediately. + synchronized (result) { + n = readFile(handle, address, rem, position, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + return; + } + // read completed immediately: + // 1. update buffer position + // 2. release waiters + updatePosition(n); + result.setResult(n); + } + } catch (Throwable x) { + // failed to initiate read + result.setFailure(toIOException(x)); + } finally { + end(); + } + + // read failed or EOF so completion port will not be notified + if (n < 0 && overlapped != 0L) { + ioCache.remove(overlapped); + } + + // return direct buffer to cache if substituted + releaseBufferIfSubstituted(); + + // invoke completion handler + Invoker.invoke(result.handler(), result); + } + + /** + * Executed when the I/O has completed + */ + @Override + public void completed(int bytesTransferred) { + updatePosition(bytesTransferred); + + // return direct buffer to cache if substituted + releaseBufferIfSubstituted(); + + // release waiters and invoke completion handler + result.setResult(bytesTransferred); + Invoker.invoke(result.handler(), result); + } + + @Override + public void failed(int error, IOException x) { + // if EOF detected asynchronously then it is reported as error + if (error == ERROR_HANDLE_EOF) { + completed(-1); + } else { + // return direct buffer to cache if substituted + releaseBufferIfSubstituted(); + + // release waiters + if (isOpen()) { + result.setFailure(x); + } else { + result.setFailure(new AsynchronousCloseException()); + } + Invoker.invoke(result.handler(), result); + } + } + } + + @Override + public <A> Future<Integer> read(ByteBuffer dst, + long position, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + if (!reading) + throw new NonReadableChannelException(); + if (position < 0) + throw new IllegalArgumentException("Negative position"); + if (dst.isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + + // check if channel is closed + if (!isOpen()) { + CompletedFuture<Integer,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + int pos = dst.position(); + int lim = dst.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + // no space remaining + if (rem == 0) { + CompletedFuture<Integer,A> result = + CompletedFuture.withResult(this, 0, attachment); + Invoker.invoke(handler, result); + return result; + } + + // create Future and task that initiates read + PendingFuture<Integer,A> result = + new PendingFuture<Integer,A>(this, handler, attachment); + ReadTask readTask = new ReadTask<A>(dst, pos, rem, position, result); + result.setContext(readTask); + + // initiate I/O (can only be done from thread in thread pool) + Invoker.invokeOnThreadInThreadPool(this, readTask); + return result; + } + + /** + * Task that initiates write operation and handles completion result. + */ + private class WriteTask<A> implements Runnable, Iocp.ResultHandler { + private final ByteBuffer src; + private final int pos, rem; // buffer position/remaining + private final long position; // file position + private final PendingFuture<Integer,A> result; + + // set to src if direct; otherwise set to substituted direct buffer + private volatile ByteBuffer buf; + + WriteTask(ByteBuffer src, + int pos, + int rem, + long position, + PendingFuture<Integer,A> result) + { + this.src = src; + this.pos = pos; + this.rem = rem; + this.position = position; + this.result = result; + } + + void releaseBufferIfSubstituted() { + if (buf != src) + Util.releaseTemporaryDirectBuffer(buf); + } + + void updatePosition(int bytesTransferred) { + // if the I/O succeeded then adjust buffer position + if (bytesTransferred > 0) { + try { + src.position(pos + bytesTransferred); + } catch (IllegalArgumentException x) { + // someone has changed the position + } + } + } + + @Override + public void run() { + int n = -1; + long overlapped = 0L; + long address; + + // Substitute a native buffer if not direct + if (src instanceof DirectBuffer) { + buf = src; + address = ((DirectBuffer)src).address() + pos; + } else { + buf = Util.getTemporaryDirectBuffer(rem); + buf.put(src); + buf.flip(); + // temporarily restore position as we don't know how many bytes + // will be written + src.position(pos); + address = ((DirectBuffer)buf).address(); + } + + try { + begin(); + + // allocate an OVERLAPPED structure + overlapped = ioCache.add(result); + + // synchronize on result to allow this thread handle the case + // where the read completes immediately. + synchronized (result) { + n = writeFile(handle, address, rem, position, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + return; + } + // read completed immediately: + // 1. update buffer position + // 2. release waiters + updatePosition(n); + result.setResult(n); + } + } catch (Throwable x) { + // failed to initiate read: + result.setFailure(toIOException(x)); + + // release resources + if (overlapped != 0L) + ioCache.remove(overlapped); + releaseBufferIfSubstituted(); + + } finally { + end(); + } + + // invoke completion handler + Invoker.invoke(result.handler(), result); + } + + /** + * Executed when the I/O has completed + */ + @Override + public void completed(int bytesTransferred) { + updatePosition(bytesTransferred); + + // return direct buffer to cache if substituted + releaseBufferIfSubstituted(); + + // release waiters and invoke completion handler + result.setResult(bytesTransferred); + Invoker.invoke(result.handler(), result); + } + + @Override + public void failed(int error, IOException x) { + // return direct buffer to cache if substituted + releaseBufferIfSubstituted(); + + // release waiters and invoker completion handler + if (isOpen()) { + result.setFailure(x); + } else { + result.setFailure(new AsynchronousCloseException()); + } + Invoker.invoke(result.handler(), result); + } + } + + @Override + public <A> Future<Integer> write(ByteBuffer src, + long position, + A attachment, + CompletionHandler<Integer,? super A> handler) + { + if (!writing) + throw new NonWritableChannelException(); + if (position < 0) + throw new IllegalArgumentException("Negative position"); + + // check if channel is closed + if (!isOpen()) { + CompletedFuture<Integer,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + int pos = src.position(); + int lim = src.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + // nothing to write + if (rem == 0) { + CompletedFuture<Integer,A> result = + CompletedFuture.withResult(this, 0, attachment); + Invoker.invoke(handler, result); + return result; + } + + // create Future and task to initiate write + PendingFuture<Integer,A> result = + new PendingFuture<Integer,A>(this, handler, attachment); + WriteTask writeTask = new WriteTask<A>(src, pos, rem, position, result); + result.setContext(writeTask); + + // initiate I/O (can only be done from thread in thread pool) + Invoker.invokeOnThreadInThreadPool(this, writeTask); + return result; + } + + // -- Native methods -- + + private static native int readFile(long handle, long address, int len, + long offset, long overlapped) throws IOException; + + private static native int writeFile(long handle, long address, int len, + long offset, long overlapped) throws IOException; + + private static native int lockFile(long handle, long position, long size, + boolean shared, long overlapped) throws IOException; + + private static native void close0(long handle); + + static { + Util.load(); + } +} diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java new file mode 100644 index 00000000000..8efb10d75e6 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java @@ -0,0 +1,367 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.net.InetSocketAddress; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import java.io.IOException; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.misc.Unsafe; + +/** + * Windows implementation of AsynchronousServerSocketChannel using overlapped I/O. + */ + +class WindowsAsynchronousServerSocketChannelImpl + extends AsynchronousServerSocketChannelImpl implements Iocp.OverlappedChannel +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // 2 * (sizeof(SOCKET_ADDRESS) + 16) + private static final int DATA_BUFFER_SIZE = 88; + + private final long handle; + private final int completionKey; + private final Iocp iocp; + + // typically there will be zero, or one I/O operations pending. In rare + // cases there may be more. These rare cases arise when a sequence of accept + // operations complete immediately and handled by the initiating thread. + // The corresponding OVERLAPPED cannot be reused/released until the completion + // event has been posted. + private final PendingIoCache ioCache; + + // the data buffer to receive the local/remote socket address + private final long dataBuffer; + + // flag to indicate that an accept operation is outstanding + private AtomicBoolean accepting = new AtomicBoolean(); + + + WindowsAsynchronousServerSocketChannelImpl(Iocp iocp) throws IOException { + super(iocp); + + // associate socket with given completion port + long h = IOUtil.fdVal(fd); + int key; + try { + key = iocp.associate(this, h); + } catch (IOException x) { + closesocket0(h); // prevent leak + throw x; + } + + this.handle = h; + this.completionKey = key; + this.iocp = iocp; + this.ioCache = new PendingIoCache(); + this.dataBuffer = unsafe.allocateMemory(DATA_BUFFER_SIZE); + } + + @Override + public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) { + return ioCache.remove(overlapped); + } + + @Override + void implClose() throws IOException { + // close socket (which may cause outstanding accept to be aborted). + closesocket0(handle); + + // waits until the accept operations have completed + ioCache.close(); + + // finally disassociate from the completion port + iocp.disassociate(completionKey); + + // release other resources + unsafe.freeMemory(dataBuffer); + } + + @Override + public AsynchronousChannelGroupImpl group() { + return iocp; + } + + /** + * Task to initiate accept operation and to handle result. + */ + private class AcceptTask<A> implements Runnable, Iocp.ResultHandler { + private final WindowsAsynchronousSocketChannelImpl channel; + private final AccessControlContext acc; + private final PendingFuture<AsynchronousSocketChannel,A> result; + + AcceptTask(WindowsAsynchronousSocketChannelImpl channel, + AccessControlContext acc, + PendingFuture<AsynchronousSocketChannel,A> result) + { + this.channel = channel; + this.acc = acc; + this.result = result; + } + + void enableAccept() { + accepting.set(false); + } + + void closeChildChannel() { + try { + channel.close(); + } catch (IOException ignore) { } + } + + // caller must have acquired read lock for the listener and child channel. + void finishAccept() throws IOException { + /** + * Set local/remote addresses. This is currently very inefficient + * in that it requires 2 calls to getsockname and 2 calls to getpeername. + * (should change this to use GetAcceptExSockaddrs) + */ + updateAcceptContext(handle, channel.handle()); + + InetSocketAddress local = Net.localAddress(channel.fd); + final InetSocketAddress remote = Net.remoteAddress(channel.fd); + channel.setConnected(local, remote); + + // permission check (in context of initiating thread) + if (acc != null) { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + SecurityManager sm = System.getSecurityManager(); + sm.checkAccept(remote.getAddress().getHostAddress(), + remote.getPort()); + return null; + } + }, acc); + } + } + + /** + * Initiates the accept operation. + */ + @Override + public void run() { + long overlapped = 0L; + + try { + // begin usage of listener socket + begin(); + try { + // begin usage of child socket (as it is registered with + // completion port and so may be closed in the event that + // the group is forcefully closed). + channel.begin(); + + synchronized (result) { + overlapped = ioCache.add(result); + + int n = accept0(handle, channel.handle(), overlapped, dataBuffer); + if (n == IOStatus.UNAVAILABLE) { + return; + } + + // connection accepted immediately + finishAccept(); + + // allow another accept before the result is set + enableAccept(); + result.setResult(channel); + } + } finally { + // end usage on child socket + channel.end(); + } + } catch (Throwable x) { + // failed to initiate accept so release resources + if (overlapped != 0L) + ioCache.remove(overlapped); + closeChildChannel(); + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + if (!(x instanceof IOException) && !(x instanceof SecurityException)) + x = new IOException(x); + enableAccept(); + result.setFailure(x); + } finally { + // end of usage of listener socket + end(); + } + + // accept completed immediately but may not have executed on + // initiating thread in which case the operation may have been + // cancelled. + if (result.isCancelled()) { + closeChildChannel(); + } + + // invoke completion handler + Invoker.invokeIndirectly(result.handler(), result); + } + + /** + * Executed when the I/O has completed + */ + @Override + public void completed(int bytesTransferred) { + try { + // connection accept after group has shutdown + if (iocp.isShutdown()) { + throw new IOException(new ShutdownChannelGroupException()); + } + + // finish the accept + try { + begin(); + try { + channel.begin(); + finishAccept(); + } finally { + channel.end(); + } + } finally { + end(); + } + + // allow another accept before the result is set + enableAccept(); + result.setResult(channel); + } catch (Throwable x) { + enableAccept(); + closeChildChannel(); + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + if (!(x instanceof IOException) && !(x instanceof SecurityException)) + x = new IOException(x); + result.setFailure(x); + } + + // if an async cancel has already cancelled the operation then + // close the new channel so as to free resources + if (result.isCancelled()) { + closeChildChannel(); + } + + // invoke handler (but not directly) + Invoker.invokeIndirectly(result.handler(), result); + } + + @Override + public void failed(int error, IOException x) { + enableAccept(); + closeChildChannel(); + + // release waiters + if (isOpen()) { + result.setFailure(x); + } else { + result.setFailure(new AsynchronousCloseException()); + } + Invoker.invokeIndirectly(result.handler(), result); + } + } + + @Override + public <A> Future<AsynchronousSocketChannel> accept(A attachment, + final CompletionHandler<AsynchronousSocketChannel,? super A> handler) + { + if (!isOpen()) { + CompletedFuture<AsynchronousSocketChannel,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invokeIndirectly(handler, result); + return result; + } + if (isAcceptKilled()) + throw new RuntimeException("Accept not allowed due to cancellation"); + + // ensure channel is bound to local address + if (localAddress == null) + throw new NotYetBoundException(); + + // create the socket that will be accepted. The creation of the socket + // is enclosed by a begin/end for the listener socket to ensure that + // we check that the listener is open and also to prevent the I/O + // port from being closed as the new socket is registered. + WindowsAsynchronousSocketChannelImpl ch = null; + IOException ioe = null; + try { + begin(); + ch = new WindowsAsynchronousSocketChannelImpl(iocp, false); + } catch (IOException x) { + ioe = x; + } finally { + end(); + } + if (ioe != null) { + CompletedFuture<AsynchronousSocketChannel,A> result = + CompletedFuture.withFailure(this, ioe, attachment); + Invoker.invokeIndirectly(handler, result); + return result; + } + + // need calling context when there is security manager as + // permission check may be done in a different thread without + // any application call frames on the stack + AccessControlContext acc = (System.getSecurityManager() == null) ? + null : AccessController.getContext(); + + PendingFuture<AsynchronousSocketChannel,A> result = + new PendingFuture<AsynchronousSocketChannel,A>(this, handler, attachment); + AcceptTask task = new AcceptTask<A>(ch, acc, result); + result.setContext(task); + + // check and set flag to prevent concurrent accepting + if (!accepting.compareAndSet(false, true)) + throw new AcceptPendingException(); + + // initiate accept. As I/O operations are tied to the initiating thread + // then it will only be invoked direcly if this thread is in the thread + // pool. If this thread is not in the thread pool when a task is + // submitted to initiate the accept. + Invoker.invokeOnThreadInThreadPool(this, task); + return result; + } + + // -- Native methods -- + + private static native void initIDs(); + + private static native int accept0(long listenSocket, long acceptSocket, + long overlapped, long dataBuffer) throws IOException; + + private static native void updateAcceptContext(long listenSocket, + long acceptSocket) throws IOException; + + private static native void closesocket0(long socket) throws IOException; + + static { + Util.load(); + initIDs(); + } +} diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java new file mode 100644 index 00000000000..d1f8c9307d5 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -0,0 +1,911 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.nio.ByteBuffer; +import java.nio.BufferOverflowException; +import java.net.*; +import java.util.concurrent.*; +import java.io.IOException; +import sun.misc.Unsafe; + +/** + * Windows implementation of AsynchronousSocketChannel using overlapped I/O. + */ + +class WindowsAsynchronousSocketChannelImpl + extends AsynchronousSocketChannelImpl implements Iocp.OverlappedChannel +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static int addressSize = unsafe.addressSize(); + + private static int dependsArch(int value32, int value64) { + return (addressSize == 4) ? value32 : value64; + } + + /* + * typedef struct _WSABUF { + * u_long len; + * char FAR * buf; + * } WSABUF; + */ + private static final int SIZEOF_WSABUF = dependsArch(8, 16); + private static final int OFFSETOF_LEN = 0; + private static final int OFFSETOF_BUF = dependsArch(4, 8); + + // maximum vector size for scatter/gather I/O + private static final int MAX_WSABUF = 16; + + private static final int SIZEOF_WSABUFARRAY = MAX_WSABUF * SIZEOF_WSABUF; + + + // socket handle. Use begin()/end() around each usage of this handle. + final long handle; + + // I/O completion port that the socket is associated with + private final Iocp iocp; + + // completion key to identify channel when I/O completes + private final int completionKey; + + // Pending I/O operations are tied to an OVERLAPPED structure that can only + // be released when the I/O completion event is posted to the completion + // port. Where I/O operations complete immediately then it is possible + // there may be more than two OVERLAPPED structures in use. + private final PendingIoCache ioCache; + + // per-channel arrays of WSABUF structures + private final long readBufferArray; + private final long writeBufferArray; + + + WindowsAsynchronousSocketChannelImpl(Iocp iocp, boolean failIfGroupShutdown) + throws IOException + { + super(iocp); + + // associate socket with default completion port + long h = IOUtil.fdVal(fd); + int key = 0; + try { + key = iocp.associate(this, h); + } catch (ShutdownChannelGroupException x) { + if (failIfGroupShutdown) { + closesocket0(h); + throw x; + } + } catch (IOException x) { + closesocket0(h); + throw x; + } + + this.handle = h; + this.iocp = iocp; + this.completionKey = key; + this.ioCache = new PendingIoCache(); + + // allocate WSABUF arrays + this.readBufferArray = unsafe.allocateMemory(SIZEOF_WSABUFARRAY); + this.writeBufferArray = unsafe.allocateMemory(SIZEOF_WSABUFARRAY); + } + + WindowsAsynchronousSocketChannelImpl(Iocp iocp) throws IOException { + this(iocp, true); + } + + @Override + public AsynchronousChannelGroupImpl group() { + return iocp; + } + + /** + * Invoked by Iocp when an I/O operation competes. + */ + @Override + public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) { + return ioCache.remove(overlapped); + } + + // invoked by WindowsAsynchronousServerSocketChannelImpl + long handle() { + return handle; + } + + // invoked by WindowsAsynchronousServerSocketChannelImpl when new connection + // accept + void setConnected(SocketAddress localAddress, SocketAddress remoteAddress) { + synchronized (stateLock) { + state = ST_CONNECTED; + this.localAddress = localAddress; + this.remoteAddress = remoteAddress; + } + } + + @Override + void implClose() throws IOException { + // close socket (may cause outstanding async I/O operations to fail). + closesocket0(handle); + + // waits until all I/O operations have completed + ioCache.close(); + + // release arrays of WSABUF structures + unsafe.freeMemory(readBufferArray); + unsafe.freeMemory(writeBufferArray); + + // finally disassociate from the completion port (key can be 0 if + // channel created when group is shutdown) + if (completionKey != 0) + iocp.disassociate(completionKey); + } + + @Override + public void onCancel(PendingFuture<?,?> task) { + if (task.getContext() instanceof ConnectTask) + killConnect(); + if (task.getContext() instanceof ReadTask) + killReading(); + if (task.getContext() instanceof WriteTask) + killWriting(); + } + + /** + * Implements the task to initiate a connection and the handler to + * consume the result when the connection is established (or fails). + */ + private class ConnectTask<A> implements Runnable, Iocp.ResultHandler { + private final InetSocketAddress remote; + private final PendingFuture<Void,A> result; + + ConnectTask(InetSocketAddress remote, PendingFuture<Void,A> result) { + this.remote = remote; + this.result = result; + } + + private void closeChannel() { + try { + close(); + } catch (IOException ignore) { } + } + + private IOException toIOException(Throwable x) { + if (x instanceof IOException) { + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + return (IOException)x; + } + return new IOException(x); + } + + /** + * Invoke after a connection is successfully established. + */ + private void afterConnect() throws IOException { + updateConnectContext(handle); + synchronized (stateLock) { + state = ST_CONNECTED; + remoteAddress = remote; + } + } + + /** + * Task to initiate a connection. + */ + @Override + public void run() { + long overlapped = 0L; + Throwable exc = null; + try { + begin(); + + // synchronize on result to allow this thread handle the case + // where the connection is established immediately. + synchronized (result) { + overlapped = ioCache.add(result); + // initiate the connection + int n = connect0(handle, Net.isIPv6Available(), remote.getAddress(), + remote.getPort(), overlapped); + if (n == IOStatus.UNAVAILABLE) { + // connection is pending + return; + } + + // connection established immediately + afterConnect(); + result.setResult(null); + } + } catch (Throwable x) { + exc = x; + } finally { + end(); + } + + if (exc != null) { + if (overlapped != 0L) + ioCache.remove(overlapped); + closeChannel(); + result.setFailure(toIOException(exc)); + } + Invoker.invoke(result.handler(), result); + } + + /** + * Invoked by handler thread when connection established. + */ + @Override + public void completed(int bytesTransferred) { + Throwable exc = null; + try { + begin(); + afterConnect(); + result.setResult(null); + } catch (Throwable x) { + // channel is closed or unable to finish connect + exc = x; + } finally { + end(); + } + + // can't close channel while in begin/end block + if (exc != null) { + closeChannel(); + result.setFailure(toIOException(exc)); + } + + Invoker.invoke(result.handler(), result); + } + + /** + * Invoked by handler thread when failed to establish connection. + */ + @Override + public void failed(int error, IOException x) { + if (isOpen()) { + closeChannel(); + result.setFailure(x); + } else { + result.setFailure(new AsynchronousCloseException()); + } + Invoker.invoke(result.handler(), result); + } + } + + @Override + public <A> Future<Void> connect(SocketAddress remote, + A attachment, + CompletionHandler<Void,? super A> handler) + { + if (!isOpen()) { + CompletedFuture<Void,A> result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + InetSocketAddress isa = Net.checkAddress(remote); + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); + + // check and update state + // ConnectEx requires the socket to be bound to a local address + IOException bindException = null; + synchronized (stateLock) { + if (state == ST_CONNECTED) + throw new AlreadyConnectedException(); + if (state == ST_PENDING) + throw new ConnectionPendingException(); + if (localAddress == null) { + try { + bind(new InetSocketAddress(0)); + } catch (IOException x) { + bindException = x; + } + } + if (bindException == null) + state = ST_PENDING; + } + + // handle bind failure + if (bindException != null) { + try { + close(); + } catch (IOException ignore) { } + CompletedFuture<Void,A> result = CompletedFuture + .withFailure(this, bindException, attachment); + Invoker.invoke(handler, result); + return result; + } + + // setup task + PendingFuture<Void,A> result = + new PendingFuture<Void,A>(this, handler, attachment); + ConnectTask task = new ConnectTask<A>(isa, result); + result.setContext(task); + + // initiate I/O (can only be done from thread in thread pool) + Invoker.invokeOnThreadInThreadPool(this, task); + return result; + } + + /** + * Implements the task to initiate a read and the handler to consume the + * result when the read completes. + */ + private class ReadTask<V,A> implements Runnable, Iocp.ResultHandler { + private final ByteBuffer[] bufs; + private final int numBufs; + private final boolean scatteringRead; + private final PendingFuture<V,A> result; + + // set by run method + private ByteBuffer[] shadow; + + ReadTask(ByteBuffer[] bufs, + boolean scatteringRead, + PendingFuture<V,A> result) + { + this.bufs = bufs; + this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length; + this.scatteringRead = scatteringRead; + this.result = result; + } + + /** + * Invoked prior to read to prepare the WSABUF array. Where necessary, + * it substitutes non-direct buffers with direct buffers. + */ + void prepareBuffers() { + shadow = new ByteBuffer[numBufs]; + long address = readBufferArray; + for (int i=0; i<numBufs; i++) { + ByteBuffer dst = bufs[i]; + int pos = dst.position(); + int lim = dst.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + long a; + if (!(dst instanceof DirectBuffer)) { + // substitute with direct buffer + ByteBuffer bb = Util.getTemporaryDirectBuffer(rem); + shadow[i] = bb; + a = ((DirectBuffer)bb).address(); + } else { + shadow[i] = dst; + a = ((DirectBuffer)dst).address() + pos; + } + unsafe.putAddress(address + OFFSETOF_BUF, a); + unsafe.putInt(address + OFFSETOF_LEN, rem); + address += SIZEOF_WSABUF; + } + } + + /** + * Invoked after a read has completed to update the buffer positions + * and release any substituted buffers. + */ + void updateBuffers(int bytesRead) { + for (int i=0; i<numBufs; i++) { + ByteBuffer nextBuffer = shadow[i]; + int pos = nextBuffer.position(); + int len = nextBuffer.remaining(); + if (bytesRead >= len) { + bytesRead -= len; + int newPosition = pos + len; + try { + nextBuffer.position(newPosition); + } catch (IllegalArgumentException x) { + // position changed by another + } + } else { // Buffers not completely filled + if (bytesRead > 0) { + assert(pos + bytesRead < (long)Integer.MAX_VALUE); + int newPosition = pos + bytesRead; + try { + nextBuffer.position(newPosition); + } catch (IllegalArgumentException x) { + // position changed by another + } + } + break; + } + } + + // Put results from shadow into the slow buffers + for (int i=0; i<numBufs; i++) { + if (!(bufs[i] instanceof DirectBuffer)) { + shadow[i].flip(); + try { + bufs[i].put(shadow[i]); + } catch (BufferOverflowException x) { + // position changed by another + } + } + } + } + + void releaseBuffers() { + for (int i=0; i<numBufs; i++) { + if (!(bufs[i] instanceof DirectBuffer)) { + Util.releaseTemporaryDirectBuffer(shadow[i]); + } + } + } + + @Override + @SuppressWarnings("unchecked") + public void run() { + long overlapped = 0L; + boolean prepared = false; + boolean pending = false; + + try { + begin(); + + // substitute non-direct buffers + prepareBuffers(); + prepared = true; + + // get an OVERLAPPED structure (from the cache or allocate) + overlapped = ioCache.add(result); + + // synchronize on result to allow this thread handle the case + // where the read completes immediately. + synchronized (result) { + int n = read0(handle, numBufs, readBufferArray, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + pending = true; + return; + } + // read completed immediately: + // 1. update buffer position + // 2. reset read flag + // 3. release waiters + if (n == 0) { + n = -1; + } else { + updateBuffers(n); + } + enableReading(); + + if (scatteringRead) { + result.setResult((V)Long.valueOf(n)); + } else { + result.setResult((V)Integer.valueOf(n)); + } + } + } catch (Throwable x) { + // failed to initiate read: + // 1. reset read flag + // 2. free resources + // 3. release waiters + enableReading(); + if (overlapped != 0L) + ioCache.remove(overlapped); + if (x instanceof ClosedChannelException) + x = new AsynchronousCloseException(); + if (!(x instanceof IOException)) + x = new IOException(x); + result.setFailure(x); + } finally { + if (prepared && !pending) { + // return direct buffer(s) to cache if substituted + releaseBuffers(); + } + end(); + } + + // invoke completion handler + Invoker.invoke(result.handler(), result); + } + + /** + * Executed when the I/O has completed + */ + @Override + @SuppressWarnings("unchecked") + public void completed(int bytesTransferred) { + if (bytesTransferred == 0) { + bytesTransferred = -1; // EOF + } else { + updateBuffers(bytesTransferred); + } + + // return direct buffer to cache if substituted + releaseBuffers(); + + // release waiters if not already released by timeout + synchronized (result) { + if (result.isDone()) + return; + enableReading(); + if (scatteringRead) { + result.setResult((V)Long.valueOf(bytesTransferred)); + } else { + result.setResult((V)Integer.valueOf(bytesTransferred)); + } + } + Invoker.invoke(result.handler(), result); + } + + @Override + public void failed(int error, IOException x) { + // return direct buffer to cache if substituted + releaseBuffers(); + + // release waiters if not already released by timeout + if (!isOpen()) + x = new AsynchronousCloseException(); + + synchronized (result) { + if (result.isDone()) + return; + enableReading(); + result.setFailure(x); + } + Invoker.invoke(result.handler(), result); + } + + /** + * Invoked if timeout expires before it is cancelled + */ + void timeout() { + // synchronize on result as the I/O could complete/fail + synchronized (result) { + if (result.isDone()) + return; + + // kill further reading before releasing waiters + enableReading(true); + result.setFailure(new InterruptedByTimeoutException()); + } + + // invoke handler without any locks + Invoker.invoke(result.handler(), result); + } + } + + @Override + <V extends Number,A> Future<V> readImpl(ByteBuffer[] bufs, + boolean scatteringRead, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<V,? super A> handler) + { + // setup task + PendingFuture<V,A> result = + new PendingFuture<V,A>(this, handler, attachment); + final ReadTask readTask = new ReadTask<V,A>(bufs, scatteringRead, result); + result.setContext(readTask); + + // schedule timeout + if (timeout > 0L) { + Future<?> timeoutTask = iocp.schedule(new Runnable() { + public void run() { + readTask.timeout(); + } + }, timeout, unit); + result.setTimeoutTask(timeoutTask); + } + + // initiate I/O (can only be done from thread in thread pool) + Invoker.invokeOnThreadInThreadPool(this, readTask); + return result; + } + + /** + * Implements the task to initiate a write and the handler to consume the + * result when the write completes. + */ + private class WriteTask<V,A> implements Runnable, Iocp.ResultHandler { + private final ByteBuffer[] bufs; + private final int numBufs; + private final boolean gatheringWrite; + private final PendingFuture<V,A> result; + + // set by run method + private ByteBuffer[] shadow; + + WriteTask(ByteBuffer[] bufs, + boolean gatheringWrite, + PendingFuture<V,A> result) + { + this.bufs = bufs; + this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length; + this.gatheringWrite = gatheringWrite; + this.result = result; + } + + /** + * Invoked prior to write to prepare the WSABUF array. Where necessary, + * it substitutes non-direct buffers with direct buffers. + */ + void prepareBuffers() { + shadow = new ByteBuffer[numBufs]; + long address = writeBufferArray; + for (int i=0; i<numBufs; i++) { + ByteBuffer src = bufs[i]; + int pos = src.position(); + int lim = src.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + long a; + if (!(src instanceof DirectBuffer)) { + // substitute with direct buffer + ByteBuffer bb = Util.getTemporaryDirectBuffer(rem); + bb.put(src); + bb.flip(); + src.position(pos); // leave heap buffer untouched for now + shadow[i] = bb; + a = ((DirectBuffer)bb).address(); + } else { + shadow[i] = src; + a = ((DirectBuffer)src).address() + pos; + } + unsafe.putAddress(address + OFFSETOF_BUF, a); + unsafe.putInt(address + OFFSETOF_LEN, rem); + address += SIZEOF_WSABUF; + } + } + + /** + * Invoked after a write has completed to update the buffer positions + * and release any substituted buffers. + */ + void updateBuffers(int bytesWritten) { + // Notify the buffers how many bytes were taken + for (int i=0; i<numBufs; i++) { + ByteBuffer nextBuffer = bufs[i]; + int pos = nextBuffer.position(); + int lim = nextBuffer.limit(); + int len = (pos <= lim ? lim - pos : lim); + if (bytesWritten >= len) { + bytesWritten -= len; + int newPosition = pos + len; + try { + nextBuffer.position(newPosition); + } catch (IllegalArgumentException x) { + // position changed by someone else + } + } else { // Buffers not completely filled + if (bytesWritten > 0) { + assert(pos + bytesWritten < (long)Integer.MAX_VALUE); + int newPosition = pos + bytesWritten; + try { + nextBuffer.position(newPosition); + } catch (IllegalArgumentException x) { + // position changed by someone else + } + } + break; + } + } + } + + void releaseBuffers() { + for (int i=0; i<numBufs; i++) { + if (!(bufs[i] instanceof DirectBuffer)) { + Util.releaseTemporaryDirectBuffer(shadow[i]); + } + } + } + + @Override + @SuppressWarnings("unchecked") + public void run() { + int n = -1; + long overlapped = 0L; + boolean prepared = false; + boolean pending = false; + boolean shutdown = false; + + try { + begin(); + + // substitute non-direct buffers + prepareBuffers(); + prepared = true; + + // get an OVERLAPPED structure (from the cache or allocate) + overlapped = ioCache.add(result); + + // synchronize on result to allow this thread handle the case + // where the read completes immediately. + synchronized (result) { + n = write0(handle, numBufs, writeBufferArray, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + pending = true; + return; + } + + enableWriting(); + + if (n == IOStatus.EOF) { + // special case for shutdown output + shutdown = true; + throw new ClosedChannelException(); + } + + // write completed immediately: + // 1. enable writing + // 2. update buffer position + // 3. release waiters + updateBuffers(n); + + // result is a Long or Integer + if (gatheringWrite) { + result.setResult((V)Long.valueOf(n)); + } else { + result.setResult((V)Integer.valueOf(n)); + } + } + } catch (Throwable x) { + enableWriting(); + + // failed to initiate read: + if (!shutdown && (x instanceof ClosedChannelException)) + x = new AsynchronousCloseException(); + if (!(x instanceof IOException)) + x = new IOException(x); + result.setFailure(x); + + // release resources + if (overlapped != 0L) + ioCache.remove(overlapped); + + } finally { + if (prepared && !pending) { + // return direct buffer(s) to cache if substituted + releaseBuffers(); + } + end(); + } + + // invoke completion handler + Invoker.invoke(result.handler(), result); + } + + /** + * Executed when the I/O has completed + */ + @Override + @SuppressWarnings("unchecked") + public void completed(int bytesTransferred) { + updateBuffers(bytesTransferred); + + // return direct buffer to cache if substituted + releaseBuffers(); + + // release waiters if not already released by timeout + synchronized (result) { + if (result.isDone()) + return; + enableWriting(); + if (gatheringWrite) { + result.setResult((V)Long.valueOf(bytesTransferred)); + } else { + result.setResult((V)Integer.valueOf(bytesTransferred)); + } + } + Invoker.invoke(result.handler(), result); + } + + @Override + public void failed(int error, IOException x) { + // return direct buffer to cache if substituted + releaseBuffers(); + + // release waiters if not already released by timeout + if (!isOpen()) + x = new AsynchronousCloseException(); + + synchronized (result) { + if (result.isDone()) + return; + enableWriting(); + result.setFailure(x); + } + Invoker.invoke(result.handler(), result); + } + + /** + * Invoked if timeout expires before it is cancelled + */ + void timeout() { + // synchronize on result as the I/O could complete/fail + synchronized (result) { + if (result.isDone()) + return; + + // kill further writing before releasing waiters + enableWriting(true); + result.setFailure(new InterruptedByTimeoutException()); + } + + // invoke handler without any locks + Invoker.invoke(result.handler(), result); + } + } + + @Override + <V extends Number,A> Future<V> writeImpl(ByteBuffer[] bufs, + boolean gatheringWrite, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler<V,? super A> handler) + { + // setup task + PendingFuture<V,A> result = + new PendingFuture<V,A>(this, handler, attachment); + final WriteTask writeTask = new WriteTask<V,A>(bufs, gatheringWrite, result); + result.setContext(writeTask); + + // schedule timeout + if (timeout > 0L) { + Future<?> timeoutTask = iocp.schedule(new Runnable() { + public void run() { + writeTask.timeout(); + } + }, timeout, unit); + result.setTimeoutTask(timeoutTask); + } + + // initiate I/O (can only be done from thread in thread pool) + Invoker.invokeOnThreadInThreadPool(this, writeTask); + return result; + } + + // -- Native methods -- + + private static native void initIDs(); + + private static native int connect0(long socket, boolean preferIPv6, + InetAddress remote, int remotePort, long overlapped) throws IOException; + + private static native void updateConnectContext(long socket) throws IOException; + + private static native int read0(long socket, int count, long addres, long overlapped) + throws IOException; + + private static native int write0(long socket, int count, long address, + long overlapped) throws IOException; + + private static native void shutdown0(long socket, int how) throws IOException; + + private static native void closesocket0(long socket) throws IOException; + + static { + Util.load(); + initIDs(); + } +} diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java index 5457a2cfb2c..5df8c8cd6c0 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java @@ -34,7 +34,6 @@ import java.nio.channels.Selector; import java.nio.channels.ClosedSelectorException; import java.nio.channels.Pipe; import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; import java.io.IOException; import java.util.List; import java.util.ArrayList; @@ -72,7 +71,7 @@ final class WindowsSelectorImpl extends SelectorImpl { private int threadsCount = 0; // A list of helper threads for select. - private final List<Thread> threads = new ArrayList<Thread>(); + private final List<SelectThread> threads = new ArrayList<SelectThread>(); //Pipe used as a wakeup object. private final Pipe wakeupPipe; @@ -201,7 +200,7 @@ final class WindowsSelectorImpl extends SelectorImpl { Thread.currentThread().interrupt(); } } - if (thread.index >= threads.size()) { // redundant thread + if (thread.isZombie()) { // redundant thread return true; // will cause run() to exit. } else { thread.lastRun = runsCounter; // update lastRun @@ -388,9 +387,10 @@ final class WindowsSelectorImpl extends SelectorImpl { // Represents a helper thread used for select. private final class SelectThread extends Thread { - private int index; // index of this thread - SubSelector subSelector; + private final int index; // index of this thread + final SubSelector subSelector; private long lastRun = 0; // last run number + private volatile boolean zombie; // Creates a new thread private SelectThread(int i) { this.index = i; @@ -398,6 +398,12 @@ final class WindowsSelectorImpl extends SelectorImpl { //make sure we wait for next round of poll this.lastRun = startLock.runsCounter; } + void makeZombie() { + zombie = true; + } + boolean isZombie() { + return zombie; + } public void run() { while (true) { // poll loop // wait for the start of poll. If this thread has become @@ -432,7 +438,7 @@ final class WindowsSelectorImpl extends SelectorImpl { } else if (threadsCount < threads.size()) { // Some threads become redundant. Remove them from the threads List. for (int i = threads.size() - 1 ; i >= threadsCount; i--) - threads.remove(i); + threads.remove(i).makeZombie(); } } @@ -468,10 +474,9 @@ final class WindowsSelectorImpl extends SelectorImpl { updateCount++; int numKeysUpdated = 0; numKeysUpdated += subSelector.processSelectedKeys(updateCount); - Iterator it = threads.iterator(); - while (it.hasNext()) - numKeysUpdated += ((SelectThread)it.next()).subSelector. - processSelectedKeys(updateCount); + for (SelectThread t: threads) { + numKeysUpdated += t.subSelector.processSelectedKeys(updateCount); + } return numKeysUpdated; } @@ -495,13 +500,13 @@ final class WindowsSelectorImpl extends SelectorImpl { } pollWrapper.free(); pollWrapper = null; - selectedKeys = null; - channelArray = null; - threads.clear(); - // Call startThreads. All remaining helper threads now exit, - // since threads.size() = 0; - startLock.startThreads(); - } + selectedKeys = null; + channelArray = null; + // Make all remaining helper threads exit + for (SelectThread t: threads) + t.makeZombie(); + startLock.startThreads(); + } } } } diff --git a/jdk/src/windows/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/windows/classes/sun/nio/fs/DefaultFileSystemProvider.java new file mode 100644 index 00000000000..93923103e5f --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.spi.FileSystemProvider; + +/** + * Creates default provider on Windows + */ +public class DefaultFileSystemProvider { + private DefaultFileSystemProvider() { } + public static FileSystemProvider create() { + return new WindowsFileSystemProvider(); + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/DefaultFileTypeDetector.java b/jdk/src/windows/classes/sun/nio/fs/DefaultFileTypeDetector.java new file mode 100644 index 00000000000..1e775aee81c --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/DefaultFileTypeDetector.java @@ -0,0 +1,36 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.spi.FileTypeDetector; + +public class DefaultFileTypeDetector { + private DefaultFileTypeDetector() { } + + public static FileTypeDetector create() { + return new RegistryFileTypeDetector(); + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java b/jdk/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java new file mode 100644 index 00000000000..dc4b9c0e2ef --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java @@ -0,0 +1,82 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * File type detector that does lookup of file extension using Windows Registry. + */ + +public class RegistryFileTypeDetector + extends AbstractFileTypeDetector +{ + public RegistryFileTypeDetector() { + super(); + } + + @Override + public String implProbeContentType(FileRef file) throws IOException { + if (!(file instanceof Path)) + return null; + + // get file extension + Path name = ((Path)file).getName(); + if (name == null) + return null; + String filename = name.toString(); + int dot = filename.lastIndexOf('.'); + if ((dot < 0) || (dot == (filename.length()-1))) + return null; + + // query HKEY_CLASSES_ROOT\<ext> + String key = filename.substring(dot); + NativeBuffer keyBuffer = WindowsNativeDispatcher.asNativeBuffer(key); + NativeBuffer nameBuffer = WindowsNativeDispatcher.asNativeBuffer("Content Type"); + try { + return queryStringValue(keyBuffer.address(), nameBuffer.address()); + } finally { + nameBuffer.release(); + keyBuffer.release(); + } + } + + private static native String queryStringValue(long subKey, long name); + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + @Override + public Void run() { + // nio.dll has dependency on net.dll + System.loadLibrary("net"); + System.loadLibrary("nio"); + return null; + }}); + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java b/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java new file mode 100644 index 00000000000..937aedd85a0 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java @@ -0,0 +1,226 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.ProviderMismatchException; +import java.nio.file.attribute.*; +import java.util.*; +import java.io.IOException; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * Windows implementation of AclFileAttributeView. + */ + +class WindowsAclFileAttributeView + extends AbstractAclFileAttributeView +{ + /** + * typedef struct _SECURITY_DESCRIPTOR { + * BYTE Revision; + * BYTE Sbz1; + * SECURITY_DESCRIPTOR_CONTROL Control; + * PSID Owner; + * PSID Group; + * PACL Sacl; + * PACL Dacl; + * } SECURITY_DESCRIPTOR; + */ + private static final short SIZEOF_SECURITY_DESCRIPTOR = 20; + + private final WindowsPath file; + private final boolean followLinks; + + WindowsAclFileAttributeView(WindowsPath file, boolean followLinks) { + this.file = file; + this.followLinks = followLinks; + } + + // permision check + private void checkAccess(WindowsPath file, + boolean checkRead, + boolean checkWrite) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (checkRead) + sm.checkRead(file.getPathForPermissionCheck()); + if (checkWrite) + sm.checkWrite(file.getPathForPermissionCheck()); + sm.checkPermission(new RuntimePermission("accessUserInformation")); + } + } + + // invokes GetFileSecurity to get requested security information + static NativeBuffer getFileSecurity(String path, int request) + throws IOException + { + // invoke get to buffer size + int size = 0; + try { + size = GetFileSecurity(path, request, 0L, 0); + } catch (WindowsException x) { + x.rethrowAsIOException(path); + } + assert size > 0; + + // allocate buffer and re-invoke to get security information + NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); + try { + for (;;) { + int newSize = GetFileSecurity(path, request, buffer.address(), size); + if (newSize <= size) + return buffer; + + // buffer was insufficient + buffer.release(); + buffer = NativeBuffers.getNativeBuffer(newSize); + size = newSize; + } + } catch (WindowsException x) { + buffer.release(); + x.rethrowAsIOException(path); + return null; + } + } + + @Override + public UserPrincipal getOwner() + throws IOException + { + checkAccess(file, true, false); + + // GetFileSecurity does not follow links so when following links we + // need the final target + String path = WindowsLinkSupport.getFinalPath(file, followLinks); + NativeBuffer buffer = getFileSecurity(path, OWNER_SECURITY_INFORMATION); + try { + // get the address of the SID + long sidAddress = GetSecurityDescriptorOwner(buffer.address()); + if (sidAddress == 0L) + throw new IOException("no owner"); + return WindowsUserPrincipals.fromSid(sidAddress); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + return null; + } finally { + buffer.release(); + } + } + + @Override + public List<AclEntry> getAcl() + throws IOException + { + checkAccess(file, true, false); + + // GetFileSecurity does not follow links so when following links we + // need the final target + String path = WindowsLinkSupport.getFinalPath(file, followLinks); + + // ALLOW and DENY entries in DACL; + // AUDIT entries in SACL (ignore for now as it requires privileges) + NativeBuffer buffer = getFileSecurity(path, DACL_SECURITY_INFORMATION); + try { + return WindowsSecurityDescriptor.getAcl(buffer.address()); + } finally { + buffer.release(); + } + } + + @Override + public void setOwner(UserPrincipal obj) + throws IOException + { + if (obj == null) + throw new NullPointerException("'owner' is null"); + if (!(obj instanceof WindowsUserPrincipals.User)) + throw new ProviderMismatchException(); + WindowsUserPrincipals.User owner = (WindowsUserPrincipals.User)obj; + + // permission check + checkAccess(file, false, true); + + // SetFileSecurity does not follow links so when following links we + // need the final target + String path = WindowsLinkSupport.getFinalPath(file, followLinks); + + // ConvertStringSidToSid allocates memory for SID so must invoke + // LocalFree to free it when we are done + long pOwner = 0L; + try { + pOwner = ConvertStringSidToSid(owner.sidString()); + } catch (WindowsException x) { + throw new IOException("Failed to get SID for " + owner.getName() + + ": " + x.errorString()); + } + + // Allocate buffer for security descriptor, initialize it, set + // owner information and update the file. + try { + NativeBuffer buffer = NativeBuffers.getNativeBuffer(SIZEOF_SECURITY_DESCRIPTOR); + try { + InitializeSecurityDescriptor(buffer.address()); + SetSecurityDescriptorOwner(buffer.address(), pOwner); + // may need SeRestorePrivilege to set the owner + WindowsSecurity.Privilege priv = + WindowsSecurity.enablePrivilege("SeRestorePrivilege"); + try { + SetFileSecurity(path, + OWNER_SECURITY_INFORMATION, + buffer.address()); + } finally { + priv.drop(); + } + } catch (WindowsException x) { + x.rethrowAsIOException(file); + } finally { + buffer.release(); + } + } finally { + LocalFree(pOwner); + } + } + + @Override + public void setAcl(List<AclEntry> acl) throws IOException { + checkAccess(file, false, true); + + // SetFileSecurity does not follow links so when following links we + // need the final target + String path = WindowsLinkSupport.getFinalPath(file, followLinks); + WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.create(acl); + try { + SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd.address()); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + } finally { + sd.release(); + } + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java b/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java new file mode 100644 index 00000000000..f559166bb6b --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java @@ -0,0 +1,341 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.channels.*; +import java.io.FileDescriptor; +import java.io.IOException; +import java.util.*; + +import com.sun.nio.file.ExtendedOpenOption; + +import sun.nio.ch.FileChannelImpl; +import sun.nio.ch.ThreadPool; +import sun.nio.ch.WindowsAsynchronousFileChannelImpl; +import sun.misc.SharedSecrets; +import sun.misc.JavaIOFileDescriptorAccess; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * Factory to create FileChannels and AsynchronousFileChannels. + */ + +class WindowsChannelFactory { + private static final JavaIOFileDescriptorAccess fdAccess = + SharedSecrets.getJavaIOFileDescriptorAccess(); + + private WindowsChannelFactory() { } + + /** + * Do not follow reparse points when opening an existing file. Do not fail + * if the file is a reparse point. + */ + static final OpenOption OPEN_REPARSE_POINT = new OpenOption() { }; + + /** + * Represents the flags from a user-supplied set of open options. + */ + private static class Flags { + boolean read; + boolean write; + boolean append; + boolean truncateExisting; + boolean create; + boolean createNew; + boolean deleteOnClose; + boolean sparse; + boolean overlapped; + boolean sync; + boolean dsync; + + // non-standard + boolean shareRead = true; + boolean shareWrite = true; + boolean shareDelete = true; + boolean noFollowLinks; + boolean openReparsePoint; + + static Flags toFlags(Set<? extends OpenOption> options) { + Flags flags = new Flags(); + for (OpenOption option: options) { + if (option instanceof StandardOpenOption) { + switch ((StandardOpenOption)option) { + case READ : flags.read = true; break; + case WRITE : flags.write = true; break; + case APPEND : flags.append = true; break; + case TRUNCATE_EXISTING : flags.truncateExisting = true; break; + case CREATE : flags.create = true; break; + case CREATE_NEW : flags.createNew = true; break; + case DELETE_ON_CLOSE : flags.deleteOnClose = true; break; + case SPARSE : flags.sparse = true; break; + case SYNC : flags.sync = true; break; + case DSYNC : flags.dsync = true; break; + default: throw new UnsupportedOperationException(); + } + continue; + } + if (option instanceof ExtendedOpenOption) { + switch ((ExtendedOpenOption)option) { + case NOSHARE_READ : flags.shareRead = false; break; + case NOSHARE_WRITE : flags.shareWrite = false; break; + case NOSHARE_DELETE : flags.shareDelete = false; break; + default: throw new UnsupportedOperationException(); + } + continue; + } + if (option == LinkOption.NOFOLLOW_LINKS) { + flags.noFollowLinks = true; + continue; + } + if (option == OPEN_REPARSE_POINT) { + flags.openReparsePoint = true; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new UnsupportedOperationException(); + } + return flags; + } + } + + /** + * Open/creates file, returning FileChannel to access the file + * + * @param pathForWindows + * The path of the file to open/create + * @param pathToCheck + * The path used for permission checks (if security manager) + */ + static FileChannel newFileChannel(String pathForWindows, + String pathToCheck, + Set<? extends OpenOption> options, + long pSecurityDescriptor) + throws WindowsException + { + Flags flags = Flags.toFlags(options); + + // default is reading; append => writing + if (!flags.read && !flags.write) { + if (flags.append) { + flags.write = true; + } else { + flags.read = true; + } + } + + // validation + if (flags.read && flags.append) + throw new IllegalArgumentException("READ + APPEND not allowed"); + if (flags.append && flags.truncateExisting) + throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed"); + + FileDescriptor fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor); + return FileChannelImpl.open(fdObj, flags.read, flags.write, null); + } + + /** + * Open/creates file, returning AsynchronousFileChannel to access the file + * + * @param pathForWindows + * The path of the file to open/create + * @param pathToCheck + * The path used for permission checks (if security manager) + * @param pool + * The thread pool that the channel is associated with + */ + static AsynchronousFileChannel newAsynchronousFileChannel(String pathForWindows, + String pathToCheck, + Set<? extends OpenOption> options, + long pSecurityDescriptor, + ThreadPool pool) + throws IOException + { + Flags flags = Flags.toFlags(options); + + // Overlapped I/O required + flags.overlapped = true; + + // default is reading + if (!flags.read && !flags.write) { + flags.read = true; + } + + // validation + if (flags.append) + throw new UnsupportedOperationException("APPEND not allowed"); + + // open file for overlapped I/O + FileDescriptor fdObj; + try { + fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor); + } catch (WindowsException x) { + x.rethrowAsIOException(pathForWindows); + return null; + } + + // create the AsynchronousFileChannel + try { + return WindowsAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool); + } catch (IOException x) { + // IOException is thrown if the file handle cannot be associated + // with the completion port. All we can do is close the file. + long handle = fdAccess.getHandle(fdObj); + CloseHandle(handle); + throw x; + } + } + + /** + * Opens file based on parameters and options, returning a FileDescriptor + * encapsulating the handle to the open file. + */ + private static FileDescriptor open(String pathForWindows, + String pathToCheck, + Flags flags, + long pSecurityDescriptor) + throws WindowsException + { + // set to true if file must be truncated after open + boolean truncateAfterOpen = false; + + // map options + int dwDesiredAccess = 0; + if (flags.read) + dwDesiredAccess |= GENERIC_READ; + if (flags.write) + dwDesiredAccess |= (flags.append) ? FILE_APPEND_DATA : GENERIC_WRITE; + + int dwShareMode = 0; + if (flags.shareRead) + dwShareMode |= FILE_SHARE_READ; + if (flags.shareWrite) + dwShareMode |= FILE_SHARE_WRITE; + if (flags.shareDelete) + dwShareMode |= FILE_SHARE_DELETE; + + int dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; + int dwCreationDisposition = OPEN_EXISTING; + if (flags.write) { + if (flags.createNew) { + dwCreationDisposition = CREATE_NEW; + // force create to fail if file is orphaned reparse point + dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT; + } else { + if (flags.create) + dwCreationDisposition = OPEN_ALWAYS; + if (flags.truncateExisting) { + // Windows doesn't have a creation disposition that exactly + // corresponds to CREATE + TRUNCATE_EXISTING so we use + // the OPEN_ALWAYS mode and then truncate the file. + if (dwCreationDisposition == OPEN_ALWAYS) { + truncateAfterOpen = true; + } else { + dwCreationDisposition = TRUNCATE_EXISTING; + } + } + } + } + + if (flags.dsync || flags.sync) + dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH; + if (flags.overlapped) + dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED; + if (flags.deleteOnClose) + dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE; + + // NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT mean open reparse point + boolean okayToFollowLinks = true; + if (dwCreationDisposition != CREATE_NEW && + (flags.noFollowLinks || + flags.openReparsePoint || + flags.deleteOnClose)) + { + if (flags.noFollowLinks || flags.deleteOnClose) + okayToFollowLinks = false; + dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT; + } + + // permission check + if (pathToCheck != null) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (flags.read) + sm.checkRead(pathToCheck); + if (flags.write) + sm.checkWrite(pathToCheck); + if (flags.deleteOnClose) + sm.checkDelete(pathToCheck); + } + } + + // open file + long handle = CreateFile(pathForWindows, + dwDesiredAccess, + dwShareMode, + pSecurityDescriptor, + dwCreationDisposition, + dwFlagsAndAttributes); + + // make sure this isn't a symbolic link. + if (!okayToFollowLinks) { + try { + if (WindowsFileAttributes.readAttributes(handle).isSymbolicLink()) + throw new WindowsException("File is symbolic link"); + } catch (WindowsException x) { + CloseHandle(handle); + throw x; + } + } + + // truncate file (for CREATE + TRUNCATE_EXISTING case) + if (truncateAfterOpen) { + try { + SetEndOfFile(handle); + } catch (WindowsException x) { + CloseHandle(handle); + throw x; + } + } + + // make the file sparse if needed + if (dwCreationDisposition == CREATE_NEW && flags.sparse) { + try { + DeviceIoControlSetSparse(handle); + } catch (WindowsException x) { + // ignore as sparse option is hint + } + } + + // create FileDescriptor and return + FileDescriptor fdObj = new FileDescriptor(); + fdAccess.setHandle(fdObj, handle); + return fdObj; + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java b/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java new file mode 100644 index 00000000000..f2619ac8060 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java @@ -0,0 +1,192 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +/** + * Win32 APIs constants. + */ + +class WindowsConstants { + private WindowsConstants() { } + + // general + public static final long INVALID_HANDLE_VALUE = -1L; + + // generic rights + public static final int GENERIC_READ = 0x80000000; + public static final int GENERIC_WRITE = 0x40000000; + + // share modes + public static final int FILE_SHARE_READ = 0x00000001; + public static final int FILE_SHARE_WRITE = 0x00000002; + public static final int FILE_SHARE_DELETE = 0x00000004; + + // creation modes + public static final int CREATE_NEW = 1; + public static final int CREATE_ALWAYS = 2; + public static final int OPEN_EXISTING = 3; + public static final int OPEN_ALWAYS = 4; + public static final int TRUNCATE_EXISTING = 5; + + // attributes and flags + public static final int FILE_ATTRIBUTE_READONLY = 0x00000001; + public static final int FILE_ATTRIBUTE_HIDDEN = 0x00000002; + public static final int FILE_ATTRIBUTE_SYSTEM = 0x00000004; + public static final int FILE_ATTRIBUTE_DIRECTORY = 0x00000010; + public static final int FILE_ATTRIBUTE_ARCHIVE = 0x00000020; + public static final int FILE_ATTRIBUTE_DEVICE = 0x00000040; + public static final int FILE_ATTRIBUTE_NORMAL = 0x00000080; + public static final int FILE_ATTRIBUTE_REPARSE_POINT = 0x400; + public static final int FILE_FLAG_NO_BUFFERING = 0x20000000; + public static final int FILE_FLAG_OVERLAPPED = 0x40000000; + public static final int FILE_FLAG_WRITE_THROUGH = 0x80000000; + public static final int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; + public static final int FILE_FLAG_DELETE_ON_CLOSE = 0x04000000; + public static final int FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000; + + // stream ids + public static final int BACKUP_ALTERNATE_DATA = 0x00000004; + public static final int BACKUP_SPARSE_BLOCK = 0x00000009; + + // reparse point/symbolic link related constants + public static final int IO_REPARSE_TAG_SYMLINK = 0xA000000C; + public static final int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024; + public static final int SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1; + + // volume flags + public static final int FILE_CASE_SENSITIVE_SEARCH = 0x00000001; + public static final int FILE_CASE_PRESERVED_NAMES = 0x00000002; + public static final int FILE_PERSISTENT_ACLS = 0x00000008; + public static final int FILE_VOLUME_IS_COMPRESSED = 0x00008000; + public static final int FILE_NAMED_STREAMS = 0x00040000; + public static final int FILE_READ_ONLY_VOLUME = 0x00080000; + + // error codes + public static final int ERROR_FILE_NOT_FOUND = 2; + public static final int ERROR_PATH_NOT_FOUND = 3; + public static final int ERROR_ACCESS_DENIED = 5; + public static final int ERROR_INVALID_HANDLE = 6; + public static final int ERROR_INVALID_DATA = 13; + public static final int ERROR_NOT_SAME_DEVICE = 17; + public static final int ERROR_NOT_READY = 21; + public static final int ERROR_FILE_EXISTS = 80; + public static final int ERROR_DISK_FULL = 112; + public static final int ERROR_INSUFFICIENT_BUFFER = 122; + public static final int ERROR_INVALID_LEVEL = 124; + public static final int ERROR_DIR_NOT_EMPTY = 145; + public static final int ERROR_ALREADY_EXISTS = 183; + public static final int ERROR_DIRECTORY = 267; + public static final int ERROR_NOTIFY_ENUM_DIR = 1022; + public static final int ERROR_NONE_MAPPED = 1332; + public static final int ERROR_NOT_A_REPARSE_POINT = 4390; + public static final int ERROR_INVALID_REPARSE_DATA = 4392; + + // notify filters + public static final int FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001; + public static final int FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002; + public static final int FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004; + public static final int FILE_NOTIFY_CHANGE_SIZE = 0x00000008; + public static final int FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010; + public static final int FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020; + public static final int FILE_NOTIFY_CHANGE_CREATION = 0x00000040; + public static final int FILE_NOTIFY_CHANGE_SECURITY = 0x00000100; + + // notify actions + public final static int FILE_ACTION_ADDED = 0x00000001; + public final static int FILE_ACTION_REMOVED = 0x00000002; + public final static int FILE_ACTION_MODIFIED = 0x00000003; + public final static int FILE_ACTION_RENAMED_OLD_NAME = 0x00000004; + public final static int FILE_ACTION_RENAMED_NEW_NAME = 0x00000005; + + // copy flags + public static final int COPY_FILE_FAIL_IF_EXISTS = 0x00000001; + public static final int COPY_FILE_COPY_SYMLINK = 0x00000800; + + // move flags + public static final int MOVEFILE_REPLACE_EXISTING = 0x00000001; + public static final int MOVEFILE_COPY_ALLOWED = 0x00000002; + + // drive types + public static final int DRIVE_UNKNOWN = 0; + public static final int DRIVE_NO_ROOT_DIR = 1; + public static final int DRIVE_REMOVABLE = 2; + public static final int DRIVE_FIXED = 3; + public static final int DRIVE_REMOTE = 4; + public static final int DRIVE_CDROM = 5; + public static final int DRIVE_RAMDISK = 6; + + // file security + public static final int OWNER_SECURITY_INFORMATION = 0x00000001; + public static final int GROUP_SECURITY_INFORMATION = 0x00000002; + public static final int DACL_SECURITY_INFORMATION = 0x00000004; + public static final int SACL_SECURITY_INFORMATION = 0x00000008; + + public static final int SidTypeUser = 1; + public static final int SidTypeGroup = 2; + public static final int SidTypeDomain = 3; + public static final int SidTypeAlias = 4; + public static final int SidTypeWellKnownGroup = 5; + public static final int SidTypeDeletedAccount = 6; + public static final int SidTypeInvalid = 7; + public static final int SidTypeUnknown = 8; + public static final int SidTypeComputer= 9; + + public static final byte ACCESS_ALLOWED_ACE_TYPE = 0x0; + public static final byte ACCESS_DENIED_ACE_TYPE = 0x1; + + public static final byte OBJECT_INHERIT_ACE = 0x1; + public static final byte CONTAINER_INHERIT_ACE = 0x2; + public static final byte NO_PROPAGATE_INHERIT_ACE = 0x4; + public static final byte INHERIT_ONLY_ACE = 0x8; + + public static final int DELETE = 0x00010000; + public static final int READ_CONTROL = 0x00020000; + public static final int WRITE_DAC = 0x00040000; + public static final int WRITE_OWNER = 0x00080000; + public static final int SYNCHRONIZE = 0x00100000; + + public static final int FILE_LIST_DIRECTORY = 0x0001; + public static final int FILE_READ_DATA = 0x0001; + public static final int FILE_WRITE_DATA = 0x0002; + public static final int FILE_APPEND_DATA = 0x0004; + public static final int FILE_READ_EA = 0x0008; + public static final int FILE_WRITE_EA = 0x0010; + public static final int FILE_EXECUTE = 0x0020; + public static final int FILE_DELETE_CHILD = 0x0040; + public static final int FILE_READ_ATTRIBUTES = 0x0080; + public static final int FILE_WRITE_ATTRIBUTES = 0x0100; + + // operating system security + public static final int TOKEN_DUPLICATE = 0x0002; + public static final int TOKEN_IMPERSONATE = 0x0004; + public static final int TOKEN_QUERY = 0x0008; + public static final int TOKEN_ADJUST_PRIVILEGES = 0x0020; + + public static final int SE_PRIVILEGE_ENABLED = 0x00000002; + + public static final int TokenUser = 1; + public static final int PROCESS_QUERY_INFORMATION = 0x0400; +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java b/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java new file mode 100644 index 00000000000..fa0b148346c --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java @@ -0,0 +1,255 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Iterator; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.io.IOException; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * Windows implementation of DirectoryStream + */ + +class WindowsDirectoryStream + implements DirectoryStream<Path> +{ + private final WindowsPath dir; + private final DirectoryStream.Filter<? super Path> filter; + + // handle to directory + private final long handle; + // first entry in the directory + private final String firstName; + + // buffer for WIN32_FIND_DATA structure that receives information about file + private final NativeBuffer findDataBuffer; + + private final Object closeLock = new Object(); + + // need closeLock to access these + private boolean isOpen = true; + private Iterator<Path> iterator; + + + WindowsDirectoryStream(WindowsPath dir, DirectoryStream.Filter<? super Path> filter) + throws IOException + { + this.dir = dir; + this.filter = filter; + + try { + // Need to append * or \* to match entries in directory. + String search = dir.getPathForWin32Calls(); + char last = search.charAt(search.length() -1); + if (last == ':' || last == '\\') { + search += "*"; + } else { + search += "\\*"; + } + + FirstFile first = FindFirstFile(search); + this.handle = first.handle(); + this.firstName = first.name(); + this.findDataBuffer = WindowsFileAttributes.getBufferForFindData(); + } catch (WindowsException x) { + if (x.lastError() == ERROR_DIRECTORY) { + throw new NotDirectoryException(dir.getPathForExceptionMessage()); + } + x.rethrowAsIOException(dir); + + // keep compiler happy + throw new AssertionError(); + } + } + + @Override + public void close() + throws IOException + { + synchronized (closeLock) { + if (!isOpen) + return; + isOpen = false; + } + findDataBuffer.release(); + try { + FindClose(handle); + } catch (WindowsException x) { + x.rethrowAsIOException(dir); + } + } + + @Override + public Iterator<Path> iterator() { + if (!isOpen) { + throw new IllegalStateException("Directory stream is closed"); + } + synchronized (this) { + if (iterator != null) + throw new IllegalStateException("Iterator already obtained"); + iterator = new WindowsDirectoryIterator(firstName); + return iterator; + } + } + + private static void throwAsConcurrentModificationException(Throwable t) { + ConcurrentModificationException cme = new ConcurrentModificationException(); + cme.initCause(t); + throw cme; + } + + private class WindowsDirectoryIterator implements Iterator<Path> { + private boolean atEof; + private String first; + private Path nextEntry; + private Path prevEntry; + + WindowsDirectoryIterator(String first) { + atEof = false; + this.first = first; + } + + // applies filter and also ignores "." and ".." + private Path acceptEntry(String s, BasicFileAttributes attrs) { + if (s.equals(".") || s.equals("..")) + return null; + if (dir.needsSlashWhenResolving()) { + StringBuilder sb = new StringBuilder(dir.toString()); + sb.append('\\'); + sb.append(s); + s = sb.toString(); + } else { + s = dir + s; + } + Path entry = WindowsPath + .createFromNormalizedPath(dir.getFileSystem(), s, attrs); + if (filter.accept(entry)) { + return entry; + } else { + return null; + } + } + + // reads next directory entry + private Path readNextEntry() { + // handle first element returned by search + if (first != null) { + nextEntry = acceptEntry(first, null); + first = null; + if (nextEntry != null) + return nextEntry; + } + + for (;;) { + String name = null; + WindowsFileAttributes attrs; + + // synchronize on closeLock to prevent close while reading + synchronized (closeLock) { + if (!isOpen) + throwAsConcurrentModificationException(new + IllegalStateException("Directory stream is closed")); + try { + name = FindNextFile(handle, findDataBuffer.address()); + if (name == null) { + // NO_MORE_FILES + return null; + } + } catch (WindowsException x) { + try { + x.rethrowAsIOException(dir); + } catch (IOException ioe) { + throwAsConcurrentModificationException(ioe); + } + } + + // grab the attributes from the WIN32_FIND_DATA structure + // (needs to be done while holding closeLock because close + // will release the buffer) + attrs = WindowsFileAttributes + .fromFindData(findDataBuffer.address()); + } + + // return entry if accepted by filter + Path entry = acceptEntry(name, attrs); + if (entry != null) + return entry; + } + } + + @Override + public synchronized boolean hasNext() { + if (nextEntry == null && !atEof) { + nextEntry = readNextEntry(); + atEof = (nextEntry == null); + } + return nextEntry != null; + } + + @Override + public synchronized Path next() { + if (nextEntry == null) { + if (!atEof) { + nextEntry = readNextEntry(); + } + if (nextEntry == null) { + atEof = true; + throw new NoSuchElementException(); + } + } + prevEntry = nextEntry; + nextEntry = null; + return prevEntry; + } + + @Override + public void remove() { + if (!isOpen) { + throw new IllegalStateException("Directory stream is closed"); + } + Path entry; + synchronized (this) { + if (prevEntry == null) + throw new IllegalStateException("no last element"); + entry = prevEntry; + prevEntry = null; + } + try { + entry.delete(true); + } catch (IOException ioe) { + throwAsConcurrentModificationException(ioe); + } catch (SecurityException se) { + throwAsConcurrentModificationException(se); + } + } + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsException.java b/jdk/src/windows/classes/sun/nio/fs/WindowsException.java new file mode 100644 index 00000000000..7da722076f3 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsException.java @@ -0,0 +1,109 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.io.IOException; + +import static sun.nio.fs.WindowsConstants.*; + +/** + * Internal exception thrown when a Win32 calls fails. + */ + +class WindowsException extends Exception { + static final long serialVersionUID = 2765039493083748820L; + + private int lastError; + private String msg; + + WindowsException(int lastError) { + this.lastError = lastError; + this.msg = null; + } + + WindowsException(String msg) { + this.lastError = 0; + this.msg = msg; + } + + int lastError() { + return lastError; + } + + String errorString() { + if (msg == null) { + msg = WindowsNativeDispatcher.FormatMessage(lastError); + if (msg == null) { + msg = "Unknown error: 0x" + Integer.toHexString(lastError); + } + } + return msg; + } + + @Override + public String getMessage() { + return errorString(); + } + + private IOException translateToIOException(String file, String other) { + // not created with last error + if (lastError() == 0) + return new IOException(errorString()); + + // handle specific cases + if (lastError() == ERROR_FILE_NOT_FOUND || lastError() == ERROR_PATH_NOT_FOUND) + return new NoSuchFileException(file, other, null); + if (lastError() == ERROR_FILE_EXISTS || lastError() == ERROR_ALREADY_EXISTS) + return new FileAlreadyExistsException(file, other, null); + if (lastError() == ERROR_ACCESS_DENIED) + return new AccessDeniedException(file, other, null); + + // fallback to the more general exception + return new FileSystemException(file, other, errorString()); + } + + void rethrowAsIOException(String file) throws IOException { + IOException x = translateToIOException(file, null); + throw x; + } + + void rethrowAsIOException(WindowsPath file, WindowsPath other) throws IOException { + String a = (file == null) ? null : file.getPathForExceptionMessage(); + String b = (other == null) ? null : other.getPathForExceptionMessage(); + IOException x = translateToIOException(a, b); + throw x; + } + + void rethrowAsIOException(WindowsPath file) throws IOException { + rethrowAsIOException(file, null); + } + + IOException asIOException(WindowsPath file) { + return translateToIOException(file.getPathForExceptionMessage(), null); + } + +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java new file mode 100644 index 00000000000..39c34a10ea9 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java @@ -0,0 +1,296 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + + +import java.nio.file.attribute.*; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.io.IOException; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +class WindowsFileAttributeViews { + + private static class Basic extends AbstractBasicFileAttributeView { + final WindowsPath file; + final boolean followLinks; + + Basic(WindowsPath file, boolean followLinks) { + this.file = file; + this.followLinks = followLinks; + } + + @Override + public WindowsFileAttributes readAttributes() throws IOException { + try { + return WindowsFileAttributes.get(file, followLinks); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } + } + + /** + * Parameter values in Windows times. + */ + void setFileTimes(long createTime, long lastAccessTime, long lastWriteTime) + throws IOException + { + long handle = -1L; + try { + int flags = FILE_FLAG_BACKUP_SEMANTICS; + if (!followLinks && file.getFileSystem().supportsLinks()) + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + + handle = CreateFile(file.getPathForWin32Calls(), + FILE_WRITE_ATTRIBUTES, + (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), + OPEN_EXISTING, + flags); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + } + + // update attributes + try { + SetFileTime(handle, createTime, lastAccessTime, lastWriteTime); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + } finally { + CloseHandle(handle); + } + } + + @Override + public void setTimes(Long lastModifiedTime, + Long lastAccessTime, + Long createTime, + TimeUnit unit) throws IOException + { + file.checkWrite(); + + // if all null then do nothing + if (lastModifiedTime == null && lastAccessTime == null && + createTime == null) + { + // no effect + return; + } + + // null => no change + // -1 => change to current time + long now = System.currentTimeMillis(); + long modTime = 0L, accTime = 0L, crTime = 0L; + if (lastModifiedTime != null) { + if (lastModifiedTime < 0L) { + if (lastModifiedTime != -1L) + throw new IllegalArgumentException(); + modTime = now; + } else { + modTime = TimeUnit.MILLISECONDS.convert(lastModifiedTime, unit); + } + modTime = WindowsFileAttributes.toWindowsTime(modTime); + } + if (lastAccessTime != null) { + if (lastAccessTime < 0L) { + if (lastAccessTime != -1L) + throw new IllegalArgumentException(); + accTime = now; + } else { + accTime = TimeUnit.MILLISECONDS.convert(lastAccessTime, unit); + } + accTime = WindowsFileAttributes.toWindowsTime(accTime); + } + if (createTime != null) { + if (createTime < 0L) { + if (createTime != -1L) + throw new IllegalArgumentException(); + crTime = now; + } else { + crTime = TimeUnit.MILLISECONDS.convert(createTime, unit); + } + crTime = WindowsFileAttributes.toWindowsTime(crTime); + } + + setFileTimes(crTime, accTime, modTime); + } + } + + static class Dos extends Basic implements DosFileAttributeView { + private static final String READONLY_NAME = "readonly"; + private static final String ARCHIVE_NAME = "archive"; + private static final String SYSTEM_NAME = "system"; + private static final String HIDDEN_NAME = "hidden"; + private static final String ATTRIBUTES_NAME = "attributes"; + + Dos(WindowsPath file, boolean followLinks) { + super(file, followLinks); + } + + @Override + public String name() { + return "dos"; + } + + @Override + public Object getAttribute(String attribute) throws IOException { + if (attribute.equals(READONLY_NAME)) + return readAttributes().isReadOnly(); + if (attribute.equals(ARCHIVE_NAME)) + return readAttributes().isArchive(); + if (attribute.equals(SYSTEM_NAME)) + return readAttributes().isSystem(); + if (attribute.equals(HIDDEN_NAME)) + return readAttributes().isHidden(); + // implementation specific + if (attribute.equals(ATTRIBUTES_NAME)) + return readAttributes().attributes(); + return super.getAttribute(attribute); + } + + @Override + public void setAttribute(String attribute, Object value) + throws IOException + { + if (attribute.equals(READONLY_NAME)) { + setReadOnly((Boolean)value); + return; + } + if (attribute.equals(ARCHIVE_NAME)) { + setArchive((Boolean)value); + return; + } + if (attribute.equals(SYSTEM_NAME)) { + setSystem((Boolean)value); + return; + } + if (attribute.equals(HIDDEN_NAME)) { + setHidden((Boolean)value); + return; + } + super.setAttribute(attribute, value); + } + + @Override + public Map<String,?> readAttributes(String first, String[] rest) + throws IOException + { + AttributesBuilder builder = AttributesBuilder.create(first, rest); + WindowsFileAttributes attrs = readAttributes(); + addBasicAttributesToBuilder(attrs, builder); + if (builder.match(READONLY_NAME)) + builder.add(READONLY_NAME, attrs.isReadOnly()); + if (builder.match(ARCHIVE_NAME)) + builder.add(ARCHIVE_NAME, attrs.isArchive()); + if (builder.match(SYSTEM_NAME)) + builder.add(SYSTEM_NAME, attrs.isSystem()); + if (builder.match(HIDDEN_NAME)) + builder.add(HIDDEN_NAME, attrs.isHidden()); + if (builder.match(ATTRIBUTES_NAME)) + builder.add(ATTRIBUTES_NAME, attrs.attributes()); + return builder.unmodifiableMap(); + } + + /** + * Update DOS attributes + */ + private void updateAttributes(int flag, boolean enable) + throws IOException + { + file.checkWrite(); + + // GetFileAttribtues & SetFileAttributes do not follow links so when + // following links we need the final target + String path = WindowsLinkSupport.getFinalPath(file, followLinks); + try { + int oldValue = GetFileAttributes(path); + int newValue = oldValue; + if (enable) { + newValue |= flag; + } else { + newValue &= ~flag; + } + if (newValue != oldValue) { + SetFileAttributes(path, newValue); + } + } catch (WindowsException x) { + // don't reveal target in exception + x.rethrowAsIOException(file); + } + } + + @Override + public void setReadOnly(boolean value) throws IOException { + updateAttributes(FILE_ATTRIBUTE_READONLY, value); + } + + @Override + public void setHidden(boolean value) throws IOException { + updateAttributes(FILE_ATTRIBUTE_HIDDEN, value); + } + + @Override + public void setArchive(boolean value) throws IOException { + updateAttributes(FILE_ATTRIBUTE_ARCHIVE, value); + } + + @Override + public void setSystem(boolean value) throws IOException { + updateAttributes(FILE_ATTRIBUTE_SYSTEM, value); + } + + // package-private + // Copy given attributes to the file. + void setAttributes(WindowsFileAttributes attrs) + throws IOException + { + // copy DOS attributes to target + int flags = 0; + if (attrs.isReadOnly()) flags |= FILE_ATTRIBUTE_READONLY; + if (attrs.isHidden()) flags |= FILE_ATTRIBUTE_HIDDEN; + if (attrs.isArchive()) flags |= FILE_ATTRIBUTE_ARCHIVE; + if (attrs.isSystem()) flags |= FILE_ATTRIBUTE_SYSTEM; + updateAttributes(flags, true); + + // copy file times to target - must be done after updating FAT attributes + // as otherwise the last modified time may be wrong. + setFileTimes( + WindowsFileAttributes.toWindowsTime(attrs.creationTime()), + WindowsFileAttributes.toWindowsTime(attrs.lastModifiedTime()), + WindowsFileAttributes.toWindowsTime(attrs.lastAccessTime())); + } + } + + static BasicFileAttributeView createBasicView(WindowsPath file, boolean followLinks) { + return new Basic(file, followLinks); + } + + static WindowsFileAttributeViews.Dos createDosView(WindowsPath file, boolean followLinks) { + return new Dos(file, followLinks); + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java new file mode 100644 index 00000000000..ce053cf901f --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java @@ -0,0 +1,461 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.util.concurrent.TimeUnit; +import java.security.AccessController; +import sun.misc.Unsafe; +import sun.security.action.GetPropertyAction; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * Windows implementation of DosFileAttributes/BasicFileAttributes + */ + +class WindowsFileAttributes + implements DosFileAttributes +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + /* + * typedef struct _BY_HANDLE_FILE_INFORMATION { + * DWORD dwFileAttributes; + * FILETIME ftCreationTime; + * FILETIME ftLastAccessTime; + * FILETIME ftLastWriteTime; + * DWORD dwVolumeSerialNumber; + * DWORD nFileSizeHigh; + * DWORD nFileSizeLow; + * DWORD nNumberOfLinks; + * DWORD nFileIndexHigh; + * DWORD nFileIndexLow; + * } BY_HANDLE_FILE_INFORMATION; + */ + private static final short SIZEOF_FILE_INFORMATION = 52; + private static final short OFFSETOF_FILE_INFORMATION_ATTRIBUTES = 0; + private static final short OFFSETOF_FILE_INFORMATION_CREATETIME = 4; + private static final short OFFSETOF_FILE_INFORMATION_LASTACCESSTIME = 12; + private static final short OFFSETOF_FILE_INFORMATION_LASTWRITETIME = 20; + private static final short OFFSETOF_FILE_INFORMATION_VOLSERIALNUM = 28; + private static final short OFFSETOF_FILE_INFORMATION_SIZEHIGH = 32; + private static final short OFFSETOF_FILE_INFORMATION_SIZELOW = 36; + private static final short OFFSETOF_FILE_INFORMATION_NUMLINKS = 40; + private static final short OFFSETOF_FILE_INFORMATION_INDEXHIGH = 44; + private static final short OFFSETOF_FILE_INFORMATION_INDEXLOW = 48; + + /* + * typedef struct _WIN32_FILE_ATTRIBUTE_DATA { + * DWORD dwFileAttributes; + * FILETIME ftCreationTime; + * FILETIME ftLastAccessTime; + * FILETIME ftLastWriteTime; + * DWORD nFileSizeHigh; + * DWORD nFileSizeLow; + * } WIN32_FILE_ATTRIBUTE_DATA; + */ + private static final short SIZEOF_FILE_ATTRIBUTE_DATA = 36; + private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES = 0; + private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME = 4; + private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME = 12; + private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME = 20; + private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH = 28; + private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW = 32; + + /** + * typedef struct _WIN32_FIND_DATA { + * DWORD dwFileAttributes; + * FILETIME ftCreationTime; + * FILETIME ftLastAccessTime; + * FILETIME ftLastWriteTime; + * DWORD nFileSizeHigh; + * DWORD nFileSizeLow; + * DWORD dwReserved0; + * DWORD dwReserved1; + * TCHAR cFileName[MAX_PATH]; + * TCHAR cAlternateFileName[14]; + * } WIN32_FIND_DATA; + */ + private static final short SIZEOF_FIND_DATA = 592; + private static final short OFFSETOF_FIND_DATA_ATTRIBUTES = 0; + private static final short OFFSETOF_FIND_DATA_CREATETIME = 4; + private static final short OFFSETOF_FIND_DATA_LASTACCESSTIME = 12; + private static final short OFFSETOF_FIND_DATA_LASTWRITETIME = 20; + private static final short OFFSETOF_FIND_DATA_SIZEHIGH = 28; + private static final short OFFSETOF_FIND_DATA_SIZELOW = 32; + private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36; + + // indicates if accurate metadata is required (interesting on NTFS only) + private static final boolean ensureAccurateMetadata; + static { + String propValue = AccessController.doPrivileged( + new GetPropertyAction("sun.nio.fs.ensureAccurateMetadata", "false")); + ensureAccurateMetadata = (propValue.length() == 0) ? + true : Boolean.valueOf(propValue); + } + + // attributes + private final int fileAttrs; + private final long creationTime; + private final long lastAccessTime; + private final long lastWriteTime; + private final long size; + private final int reparseTag; + + // additional attributes when using GetFileInformationByHandle + private final int linkCount; + private final int volSerialNumber; + private final int fileIndexHigh; + private final int fileIndexLow; + + /** + * Convert 64-bit value representing the number of 100-nanosecond intervals + * since January 1, 1601 to java time. + */ + private static long toJavaTime(long time) { + time /= 10000L; + time -= 11644473600000L; + return time; + } + + /** + * Convert java time to 64-bit value representing the number of 100-nanosecond + * intervals since January 1, 1601. + */ + static long toWindowsTime(long time) { + time += 11644473600000L; + time *= 10000L; + return time; + } + + /** + * Initialize a new instance of this class + */ + private WindowsFileAttributes(int fileAttrs, + long creationTime, + long lastAccessTime, + long lastWriteTime, + long size, + int reparseTag, + int linkCount, + int volSerialNumber, + int fileIndexHigh, + int fileIndexLow) + { + this.fileAttrs = fileAttrs; + this.creationTime = creationTime; + this.lastAccessTime = lastAccessTime; + this.lastWriteTime = lastWriteTime; + this.size = size; + this.reparseTag = reparseTag; + this.linkCount = linkCount; + this.volSerialNumber = volSerialNumber; + this.fileIndexHigh = fileIndexHigh; + this.fileIndexLow = fileIndexLow; + } + + /** + * Create a WindowsFileAttributes from a BY_HANDLE_FILE_INFORMATION structure + */ + private static WindowsFileAttributes fromFileInformation(long address, int reparseTag) { + int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); + long creationTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_CREATETIME)); + long lastAccessTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTACCESSTIME)); + long lastWriteTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTWRITETIME)); + long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZEHIGH)) << 32) + + (unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZELOW) & 0xFFFFFFFFL); + int linkCount = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_NUMLINKS); + int volSerialNumber = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_VOLSERIALNUM); + int fileIndexHigh = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXHIGH); + int fileIndexLow = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXLOW); + return new WindowsFileAttributes(fileAttrs, + creationTime, + lastAccessTime, + lastWriteTime, + size, + reparseTag, + linkCount, + volSerialNumber, + fileIndexHigh, + fileIndexLow); + } + + /** + * Create a WindowsFileAttributes from a WIN32_FILE_ATTRIBUTE_DATA structure + */ + private static WindowsFileAttributes fromFileAttributeData(long address, int reparseTag) { + int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); + long creationTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME)); + long lastAccessTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME)); + long lastWriteTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME)); + long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH)) << 32) + + (unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW) & 0xFFFFFFFFL); + return new WindowsFileAttributes(fileAttrs, + creationTime, + lastAccessTime, + lastWriteTime, + size, + reparseTag, + 1, // linkCount + 0, // volSerialNumber + 0, // fileIndexHigh + 0); // fileIndexLow + } + + + /** + * Allocates a native buffer for a WIN32_FIND_DATA structure + */ + static NativeBuffer getBufferForFindData() { + return NativeBuffers.getNativeBuffer(SIZEOF_FIND_DATA); + } + + /** + * Create a WindowsFileAttributes from a WIN32_FIND_DATA structure + */ + static WindowsFileAttributes fromFindData(long address) { + int fileAttrs = unsafe.getInt(address + OFFSETOF_FIND_DATA_ATTRIBUTES); + long creationTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FIND_DATA_CREATETIME)); + long lastAccessTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTACCESSTIME)); + long lastWriteTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME)); + long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32) + + (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL); + int reparseTag = ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) ? + + unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; + return new WindowsFileAttributes(fileAttrs, + creationTime, + lastAccessTime, + lastWriteTime, + size, + reparseTag, + 1, // linkCount + 0, // volSerialNumber + 0, // fileIndexHigh + 0); // fileIndexLow + } + + /** + * Reads the attributes of an open file + */ + static WindowsFileAttributes readAttributes(long handle) + throws WindowsException + { + NativeBuffer buffer = NativeBuffers + .getNativeBuffer(SIZEOF_FILE_INFORMATION); + try { + long address = buffer.address(); + GetFileInformationByHandle(handle, address); + + // if file is a reparse point then read the tag + int reparseTag = 0; + int fileAttrs = unsafe + .getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); + if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; + NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size); + try { + DeviceIoControlGetReparsePoint(handle, reparseBuffer.address(), size); + reparseTag = (int)unsafe.getLong(reparseBuffer.address()); + } finally { + reparseBuffer.release(); + } + } + + return fromFileInformation(address, reparseTag); + } finally { + buffer.release(); + } + } + + /** + * Returns attributes of given file. + */ + static WindowsFileAttributes get(WindowsPath path, boolean followLinks) + throws WindowsException + { + if (!ensureAccurateMetadata) { + NativeBuffer buffer = + NativeBuffers.getNativeBuffer(SIZEOF_FILE_ATTRIBUTE_DATA); + try { + long address = buffer.address(); + GetFileAttributesEx(path.getPathForWin32Calls(), address); + // if reparse point then file may be a sym link; otherwise + // just return the attributes + int fileAttrs = unsafe + .getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); + if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0) + return fromFileAttributeData(address, 0); + } finally { + buffer.release(); + } + } + + // file is reparse point so need to open file to get attributes + long handle = path.openForReadAttributeAccess(followLinks); + try { + return readAttributes(handle); + } finally { + CloseHandle(handle); + } + } + + /** + * Returns true if the attribtues are of the same file - both files must + * be open. + */ + static boolean isSameFile(WindowsFileAttributes attrs1, + WindowsFileAttributes attrs2) + { + // volume serial number and file index must be the same + return (attrs1.volSerialNumber == attrs2.volSerialNumber) && + (attrs1.fileIndexHigh == attrs2.fileIndexHigh) && + (attrs1.fileIndexLow == attrs2.fileIndexLow); + } + + // package-private + int attributes() { + return fileAttrs; + } + + int volSerialNumber() { + if (volSerialNumber == 0) + throw new AssertionError("Should not get here"); + return volSerialNumber; + } + + int fileIndexHigh() { + if (volSerialNumber == 0) + throw new AssertionError("Should not get here"); + return fileIndexHigh; + } + + int fileIndexLow() { + if (volSerialNumber == 0) + throw new AssertionError("Should not get here"); + return fileIndexLow; + } + + @Override + public long size() { + return size; + } + + @Override + public long lastModifiedTime() { + return (lastWriteTime >= 0L) ? lastWriteTime : 0L; + } + + @Override + public long lastAccessTime() { + return (lastAccessTime >= 0L) ? lastAccessTime : 0L; + } + + @Override + public long creationTime() { + return (creationTime >= 0L) ? creationTime : 0L; + } + + @Override + public TimeUnit resolution() { + return TimeUnit.MILLISECONDS; + } + + @Override + public int linkCount() { + return linkCount; + } + + @Override + public Object fileKey() { + return null; + } + + // package private + boolean isReparsePoint() { + return (fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + } + + boolean isDirectoryLink() { + return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0); + } + + @Override + public boolean isSymbolicLink() { + return reparseTag == IO_REPARSE_TAG_SYMLINK; + } + + @Override + public boolean isDirectory() { + // ignore FILE_ATTRIBUTE_DIRECTORY attribute if file is a sym link + if (isSymbolicLink()) + return false; + return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0); + } + + @Override + public boolean isOther() { + if (isSymbolicLink()) + return false; + // return true if device or reparse point + return ((fileAttrs & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0); + } + + @Override + public boolean isRegularFile() { + return !isSymbolicLink() && !isDirectory() && !isOther(); + } + + @Override + public boolean isReadOnly() { + return (fileAttrs & FILE_ATTRIBUTE_READONLY) != 0; + } + + @Override + public boolean isHidden() { + return (fileAttrs & FILE_ATTRIBUTE_HIDDEN) != 0; + } + + @Override + public boolean isArchive() { + return (fileAttrs & FILE_ATTRIBUTE_ARCHIVE) != 0; + } + + @Override + public boolean isSystem() { + return (fileAttrs & FILE_ATTRIBUTE_SYSTEM) != 0; + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java new file mode 100644 index 00000000000..69a41262aed --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java @@ -0,0 +1,519 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import com.sun.nio.file.ExtendedCopyOption; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * Utility methods for copying and moving files. + */ + +class WindowsFileCopy { + private WindowsFileCopy() { + } + + /** + * Copy file from source to target + */ + static void copy(final WindowsPath source, + final WindowsPath target, + CopyOption... options) + throws IOException + { + // map options + boolean replaceExisting = false; + boolean copyAttributes = false; + boolean followLinks = true; + boolean interruptible = false; + for (CopyOption option: options) { + if (option == StandardCopyOption.REPLACE_EXISTING) { + replaceExisting = true; + continue; + } + if (option == LinkOption.NOFOLLOW_LINKS) { + followLinks = false; + continue; + } + if (option == StandardCopyOption.COPY_ATTRIBUTES) { + copyAttributes = true; + continue; + } + if (option == ExtendedCopyOption.INTERRUPTIBLE) { + interruptible = true; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new UnsupportedOperationException("Unsupported copy option"); + } + + // check permissions. If the source file is a symbolic link then + // later we must also check LinkPermission + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + source.checkRead(); + target.checkWrite(); + } + + // get attributes of source file + // attempt to get attributes of target file + // if both files are the same there is nothing to do + // if target exists and !replace then throw exception + + WindowsFileAttributes sourceAttrs = null; + WindowsFileAttributes targetAttrs = null; + + long sourceHandle = 0L; + try { + sourceHandle = source.openForReadAttributeAccess(followLinks); + } catch (WindowsException x) { + x.rethrowAsIOException(source); + } + try { + // source attributes + try { + sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle); + } catch (WindowsException x) { + x.rethrowAsIOException(source); + } + + // open target (don't follow links) + long targetHandle = 0L; + try { + targetHandle = target.openForReadAttributeAccess(false); + try { + targetAttrs = WindowsFileAttributes.readAttributes(targetHandle); + + // if both files are the same then nothing to do + if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) { + return; + } + + // can't replace file + if (!replaceExisting) { + throw new FileAlreadyExistsException( + target.getPathForExceptionMessage()); + } + + } finally { + CloseHandle(targetHandle); + } + } catch (WindowsException x) { + // ignore + } + + } finally { + CloseHandle(sourceHandle); + } + + // if source file is a symbolic link then we must check for LinkPermission + if (sm != null && sourceAttrs.isSymbolicLink()) { + sm.checkPermission(new LinkPermission("symbolic")); + } + + final String sourcePath = asWin32Path(source); + final String targetPath = asWin32Path(target); + + // if target exists then delete it. + if (targetAttrs != null) { + try { + if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) { + RemoveDirectory(targetPath); + } else { + DeleteFile(targetPath); + } + } catch (WindowsException x) { + if (targetAttrs.isDirectory()) { + // ERROR_ALREADY_EXISTS is returned when attempting to delete + // non-empty directory on SAMBA servers. + if (x.lastError() == ERROR_DIR_NOT_EMPTY || + x.lastError() == ERROR_ALREADY_EXISTS) + { + throw new FileAlreadyExistsException( + target.getPathForExceptionMessage()); + } + } + x.rethrowAsIOException(target); + } + } + + // Use CopyFileEx if the file is not a directory or junction + if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) { + final int flags = + (source.getFileSystem().supportsLinks() && !followLinks) ? + COPY_FILE_COPY_SYMLINK : 0; + + if (interruptible) { + // interruptible copy + Cancellable copyTask = new Cancellable() { + @Override + public int cancelValue() { + return 1; // TRUE + } + @Override + public void implRun() throws IOException { + try { + CopyFileEx(sourcePath, targetPath, flags, + addressToPollForCancel()); + } catch (WindowsException x) { + x.rethrowAsIOException(source, target); + } + } + }; + try { + Cancellable.runInterruptibly(copyTask); + } catch (ExecutionException e) { + Throwable t = e.getCause(); + if (t instanceof IOException) + throw (IOException)t; + throw new IOException(t); + } + } else { + // non-interruptible copy + try { + CopyFileEx(sourcePath, targetPath, flags, 0L); + } catch (WindowsException x) { + x.rethrowAsIOException(source, target); + } + } + if (copyAttributes) { + // CopyFileEx does not copy security attributes + try { + copySecurityAttributes(source, target, followLinks); + } catch (IOException x) { + // ignore + } + } + return; + } + + // copy directory or directory junction + try { + if (sourceAttrs.isDirectory()) { + CreateDirectory(targetPath, 0L); + } else { + String linkTarget = WindowsLinkSupport.readLink(source); + int flags = SYMBOLIC_LINK_FLAG_DIRECTORY; + CreateSymbolicLink(targetPath, + addPrefixIfNeeded(linkTarget), + flags); + } + } catch (WindowsException x) { + x.rethrowAsIOException(target); + } + if (copyAttributes) { + // copy DOS/timestamps attributes + WindowsFileAttributeViews.Dos view = + WindowsFileAttributeViews.createDosView(target, false); + try { + view.setAttributes(sourceAttrs); + } catch (IOException x) { + if (sourceAttrs.isDirectory()) { + try { + RemoveDirectory(targetPath); + } catch (WindowsException ignore) { } + } + } + + // copy security attributes. If this fail it doesn't cause the move + // to fail. + try { + copySecurityAttributes(source, target, followLinks); + } catch (IOException ignore) { } + } + } + + /** + * Move file from source to target + */ + static void move(WindowsPath source, WindowsPath target, CopyOption... options) + throws IOException + { + // map options + boolean atomicMove = false; + boolean replaceExisting = false; + for (CopyOption option: options) { + if (option == StandardCopyOption.ATOMIC_MOVE) { + atomicMove = true; + continue; + } + if (option == StandardCopyOption.REPLACE_EXISTING) { + replaceExisting = true; + continue; + } + if (option == LinkOption.NOFOLLOW_LINKS) { + // ignore + continue; + } + if (option == null) throw new NullPointerException(); + throw new UnsupportedOperationException("Unsupported copy option"); + } + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + source.checkWrite(); + target.checkWrite(); + } + + final String sourcePath = asWin32Path(source); + final String targetPath = asWin32Path(target); + + // atomic case + if (atomicMove) { + try { + MoveFileEx(sourcePath, targetPath, MOVEFILE_REPLACE_EXISTING); + } catch (WindowsException x) { + if (x.lastError() == ERROR_NOT_SAME_DEVICE) { + throw new AtomicMoveNotSupportedException( + source.getPathForExceptionMessage(), + target.getPathForExceptionMessage(), + x.errorString()); + } + x.rethrowAsIOException(source, target); + } + return; + } + + // get attributes of source file + // attempt to get attributes of target file + // if both files are the same there is nothing to do + // if target exists and !replace then throw exception + + WindowsFileAttributes sourceAttrs = null; + WindowsFileAttributes targetAttrs = null; + + long sourceHandle = 0L; + try { + sourceHandle = source.openForReadAttributeAccess(false); + } catch (WindowsException x) { + x.rethrowAsIOException(source); + } + try { + // source attributes + try { + sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle); + } catch (WindowsException x) { + x.rethrowAsIOException(source); + } + + // open target (don't follow links) + long targetHandle = 0L; + try { + targetHandle = target.openForReadAttributeAccess(false); + try { + targetAttrs = WindowsFileAttributes.readAttributes(targetHandle); + + // if both files are the same then nothing to do + if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) { + return; + } + + // can't replace file + if (!replaceExisting) { + throw new FileAlreadyExistsException( + target.getPathForExceptionMessage()); + } + + } finally { + CloseHandle(targetHandle); + } + } catch (WindowsException x) { + // ignore + } + + } finally { + CloseHandle(sourceHandle); + } + + // if target exists then delete it. + if (targetAttrs != null) { + try { + if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) { + RemoveDirectory(targetPath); + } else { + DeleteFile(targetPath); + } + } catch (WindowsException x) { + if (targetAttrs.isDirectory()) { + // ERROR_ALREADY_EXISTS is returned when attempting to delete + // non-empty directory on SAMBA servers. + if (x.lastError() == ERROR_DIR_NOT_EMPTY || + x.lastError() == ERROR_ALREADY_EXISTS) + { + throw new FileAlreadyExistsException( + target.getPathForExceptionMessage()); + } + } + x.rethrowAsIOException(target); + } + } + + // first try MoveFileEx (no options). If target is on same volume then + // all attributes (including security attributes) are preserved. + try { + MoveFileEx(sourcePath, targetPath, 0); + return; + } catch (WindowsException x) { + if (x.lastError() != ERROR_NOT_SAME_DEVICE) + x.rethrowAsIOException(source, target); + } + + // target is on different volume so use MoveFileEx with copy option + if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) { + try { + MoveFileEx(sourcePath, targetPath, MOVEFILE_COPY_ALLOWED); + } catch (WindowsException x) { + x.rethrowAsIOException(source, target); + } + // MoveFileEx does not copy security attributes when moving + // across volumes. + try { + copySecurityAttributes(source, target, false); + } catch (IOException x) { + // ignore + } + return; + } + + // moving directory or directory-link to another file system + assert sourceAttrs.isDirectory() || sourceAttrs.isDirectoryLink(); + + // create new directory or directory junction + try { + if (sourceAttrs.isDirectory()) { + CreateDirectory(targetPath, 0L); + } else { + String linkTarget = WindowsLinkSupport.readLink(source); + CreateSymbolicLink(targetPath, + addPrefixIfNeeded(linkTarget), + SYMBOLIC_LINK_FLAG_DIRECTORY); + } + } catch (WindowsException x) { + x.rethrowAsIOException(target); + } + + // copy timestamps/DOS attributes + WindowsFileAttributeViews.Dos view = + WindowsFileAttributeViews.createDosView(target, false); + try { + view.setAttributes(sourceAttrs); + } catch (IOException x) { + // rollback + try { + RemoveDirectory(targetPath); + } catch (WindowsException ignore) { } + throw x; + } + + // copy security attributes. If this fails it doesn't cause the move + // to fail. + try { + copySecurityAttributes(source, target, false); + } catch (IOException ignore) { } + + // delete source + try { + RemoveDirectory(sourcePath); + } catch (WindowsException x) { + // rollback + try { + RemoveDirectory(targetPath); + } catch (WindowsException ignore) { } + // ERROR_ALREADY_EXISTS is returned when attempting to delete + // non-empty directory on SAMBA servers. + if (x.lastError() == ERROR_DIR_NOT_EMPTY || + x.lastError() == ERROR_ALREADY_EXISTS) + { + throw new DirectoryNotEmptyException( + target.getPathForExceptionMessage()); + } + x.rethrowAsIOException(source); + } + } + + + private static String asWin32Path(WindowsPath path) throws IOException { + try { + return path.getPathForWin32Calls(); + } catch (WindowsException x) { + x.rethrowAsIOException(path); + return null; + } + } + + /** + * Copy DACL/owner/group from source to target + */ + private static void copySecurityAttributes(WindowsPath source, + WindowsPath target, + boolean followLinks) + throws IOException + { + String path = WindowsLinkSupport.getFinalPath(source, followLinks); + + // may need SeRestorePrivilege to set file owner + WindowsSecurity.Privilege priv = + WindowsSecurity.enablePrivilege("SeRestorePrivilege"); + try { + int request = (DACL_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION); + NativeBuffer buffer = + WindowsAclFileAttributeView.getFileSecurity(path, request); + try { + try { + SetFileSecurity(target.getPathForWin32Calls(), request, + buffer.address()); + } catch (WindowsException x) { + x.rethrowAsIOException(target); + } + } finally { + buffer.release(); + } + } finally { + priv.drop(); + } + } + + /** + * Add long path prefix to path if required + */ + private static String addPrefixIfNeeded(String path) { + if (path.length() > 248) { + if (path.startsWith("\\\\")) { + path = "\\\\?\\UNC" + path.substring(1, path.length()); + } else { + path = "\\\\?\\" + path; + } + } + return path; + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java new file mode 100644 index 00000000000..5d3a0af2533 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java @@ -0,0 +1,337 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.util.*; +import java.io.IOException; + +import static sun.nio.fs.WindowsConstants.*; +import static sun.nio.fs.WindowsNativeDispatcher.*; + +/** + * Windows implementation of FileStore. + */ + +class WindowsFileStore + extends FileStore +{ + private final String root; + private final VolumeInformation volInfo; + private final int volType; + private final String displayName; // returned by toString + + private WindowsFileStore(String root) throws WindowsException { + assert root.charAt(root.length()-1) == '\\'; + this.root = root; + this.volInfo = GetVolumeInformation(root); + this.volType = GetDriveType(root); + + // file store "display name" is the volume name if available + String vol = volInfo.volumeName(); + if (vol.length() > 0) { + this.displayName = vol; + } else { + // TBD - should we map all types? Does this need to be localized? + this.displayName = (volType == DRIVE_REMOVABLE) ? "Removable Disk" : ""; + } + } + + static WindowsFileStore create(String root, boolean ignoreNotReady) + throws IOException + { + try { + return new WindowsFileStore(root); + } catch (WindowsException x) { + if (ignoreNotReady && x.lastError() == ERROR_NOT_READY) + return null; + x.rethrowAsIOException(root); + return null; // keep compiler happy + } + } + + static WindowsFileStore create(WindowsPath file) throws IOException { + try { + // if the file is a link then GetVolumePathName returns the + // volume that the link is on so we need to call it with the + // final target + String target; + if (file.getFileSystem().supportsLinks()) { + target = WindowsLinkSupport.getFinalPath(file, true); + } else { + // file must exist + WindowsFileAttributes.get(file, true); + target = file.getPathForWin32Calls(); + } + String root = GetVolumePathName(target); + return new WindowsFileStore(root); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } + } + + VolumeInformation volumeInformation() { + return volInfo; + } + + int volumeType() { + return volType; + } + + @Override + public String name() { + return volInfo.volumeName(); // "SYSTEM", "DVD-RW", ... + } + + @Override + public String type() { + return volInfo.fileSystemName(); // "FAT", "NTFS", ... + } + + @Override + public boolean isReadOnly() { + return ((volInfo.flags() & FILE_READ_ONLY_VOLUME) != 0); + } + + @Override + @SuppressWarnings("unchecked") + public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> view) { + if (view == FileStoreSpaceAttributeView.class) + return (V) new WindowsFileStoreAttributeView(this); + return (V) null; + } + + @Override + public FileStoreAttributeView getFileStoreAttributeView(String name) { + if (name.equals("space")) + return new WindowsFileStoreAttributeView(this); + if (name.equals("volume")) + return new VolumeFileStoreAttributeView(this); + return null; + } + + @Override + public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) { + if (type == BasicFileAttributeView.class) + return true; + if (type == AclFileAttributeView.class || type == FileOwnerAttributeView.class) + return ((volInfo.flags() & FILE_PERSISTENT_ACLS) != 0); + if (type == UserDefinedFileAttributeView.class) + return ((volInfo.flags() & FILE_NAMED_STREAMS) != 0); + return false; + } + + @Override + public boolean supportsFileAttributeView(String name) { + if (name.equals("basic") || name.equals("dos")) + return true; + if (name.equals("acl")) + return supportsFileAttributeView(AclFileAttributeView.class); + if (name.equals("owner")) + return supportsFileAttributeView(FileOwnerAttributeView.class); + if (name.equals("xattr")) + return supportsFileAttributeView(UserDefinedFileAttributeView.class); + return false; + } + + @Override + public boolean equals(Object ob) { + if (ob == this) + return true; + if (!(ob instanceof WindowsFileStore)) + return false; + WindowsFileStore other = (WindowsFileStore)ob; + return this.volInfo.volumeSerialNumber() == other.volInfo.volumeSerialNumber(); + } + + @Override + public int hashCode() { + // reveals VSN without permission check - okay? + return volInfo.volumeSerialNumber(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(displayName); + if (sb.length() > 0) + sb.append(" "); + sb.append("("); + // drop trailing slash + sb.append(root.subSequence(0, root.length()-1)); + sb.append(")"); + return sb.toString(); + } + + static class WindowsFileStoreAttributeView + extends AbstractFileStoreSpaceAttributeView + { + private final WindowsFileStore fs; + + WindowsFileStoreAttributeView(WindowsFileStore fs) { + this.fs = fs; + } + + @Override + public FileStoreSpaceAttributes readAttributes() + throws IOException + { + // read the free space info + DiskFreeSpace info = null; + try { + info = GetDiskFreeSpaceEx(fs.root); + } catch (WindowsException x) { + x.rethrowAsIOException(fs.root); + } + + final DiskFreeSpace result = info; + return new FileStoreSpaceAttributes() { + @Override + public long totalSpace() { + return result.totalNumberOfBytes(); + } + @Override + public long usableSpace() { + return result.freeBytesAvailable(); + } + @Override + public long unallocatedSpace() { + return result.totalNumberOfFreeBytes(); + } + }; + } + } + + /** + * Windows-specific attribute view to allow access to volume information. + */ + static class VolumeFileStoreAttributeView + implements FileStoreAttributeView + { + private static final String VSN_NAME = "vsn"; + private static final String COMPRESSED_NAME = "compressed"; + private static final String REMOVABLE_NAME = "removable"; + private static final String CDROM_NAME = "cdrom"; + + private final WindowsFileStore fs; + + VolumeFileStoreAttributeView(WindowsFileStore fs) { + this.fs = fs; + } + + @Override + public String name() { + return "volume"; + } + + private int vsn() { + return fs.volumeInformation().volumeSerialNumber(); + } + + private boolean isCompressed() { + return (fs.volumeInformation().flags() & + FILE_VOLUME_IS_COMPRESSED) > 0; + } + + private boolean isRemovable() { + return fs.volumeType() == DRIVE_REMOVABLE; + } + + private boolean isCdrom() { + return fs.volumeType() == DRIVE_CDROM; + } + + @Override + public Object getAttribute(String attribute) throws IOException { + if (attribute.equals(VSN_NAME)) + return vsn(); + if (attribute.equals(COMPRESSED_NAME)) + return isCompressed(); + if (attribute.equals(REMOVABLE_NAME)) + return isRemovable(); + if (attribute.equals(CDROM_NAME)) + return isCdrom(); + return null; + } + + @Override + public void setAttribute(String attribute, Object value) + throws IOException + { + throw new UnsupportedOperationException(); + } + + @Override + public Map<String,?> readAttributes(String first, String... rest) + throws IOException + { + boolean all = false; + boolean vsn = false; + boolean compressed = false; + boolean removable = false; + boolean cdrom = false; + + if (first.equals(VSN_NAME)) vsn = true; + else if (first.equals(COMPRESSED_NAME)) compressed = true; + else if (first.equals(REMOVABLE_NAME)) removable = true; + else if (first.equals(CDROM_NAME)) cdrom = true; + else if (first.equals("*")) all = true; + + if (!all) { + for (String attribute: rest) { + if (attribute.equals("*")) { + all = true; + break; + } + if (attribute.equals(VSN_NAME)) { + vsn = true; + continue; + } + if (attribute.equals(COMPRESSED_NAME)) { + compressed = true; + continue; + } + if (attribute.equals(REMOVABLE_NAME)) { + removable = true; + continue; + } + } + } + + Map<String,Object> result = new HashMap<String,Object>(); + if (all || vsn) + result.put(VSN_NAME, vsn()); + if (all || compressed) + result.put(COMPRESSED_NAME, isCompressed()); + if (all || removable) + result.put(REMOVABLE_NAME, isRemovable()); + if (all || cdrom) + result.put(CDROM_NAME, isCdrom()); + return result; + } + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java new file mode 100644 index 00000000000..e80c829f311 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java @@ -0,0 +1,317 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.*; +import java.util.*; +import java.util.regex.Pattern; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.security.action.GetPropertyAction; + +class WindowsFileSystem + extends FileSystem +{ + private final WindowsFileSystemProvider provider; + + // default directory (is absolute), and default root + private final String defaultDirectory; + private final String defaultRoot; + + private final boolean supportsLinks; + private final boolean supportsStreamEnumeration; + + // package-private + WindowsFileSystem(WindowsFileSystemProvider provider, + String dir) + { + this.provider = provider; + + // parse default directory and check it is absolute + WindowsPathParser.Result result = WindowsPathParser.parse(dir); + + if (result.type() != WindowsPathType.ABSOLUTE) + throw new AssertionError("Default directory must be absolute/non-UNC"); + this.defaultDirectory = result.path(); + this.defaultRoot = result.root(); + + PrivilegedAction<String> pa = new GetPropertyAction("os.version"); + String osversion = AccessController.doPrivileged(pa); + String[] vers = osversion.split("\\.", 0); + int major = Integer.parseInt(vers[0]); + int minor = Integer.parseInt(vers[1]); + + // symbolic links available on Vista and newer + supportsLinks = (major >= 6); + + // enumeration of data streams available on Windows Server 2003 and newer + supportsStreamEnumeration = (major >= 6) || (major == 5 && minor >= 2); + } + + // package-private + String defaultDirectory() { + return defaultDirectory; + } + + String defaultRoot() { + return defaultRoot; + } + + boolean supportsLinks() { + return supportsLinks; + } + + boolean supportsStreamEnumeration() { + return supportsStreamEnumeration; + } + + @Override + public FileSystemProvider provider() { + return provider; + } + + @Override + public String getSeparator() { + return "\\"; + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public boolean isReadOnly() { + return false; + } + + @Override + public void close() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public Iterable<Path> getRootDirectories() { + int drives = 0; + try { + drives = WindowsNativeDispatcher.GetLogicalDrives(); + } catch (WindowsException x) { + // shouldn't happen + throw new AssertionError(x.getMessage()); + } + + // iterate over roots, ignoring those that the security manager denies + ArrayList<Path> result = new ArrayList<Path>(); + SecurityManager sm = System.getSecurityManager(); + for (int i = 0; i <= 25; i++) { // 0->A, 1->B, 2->C... + if ((drives & (1 << i)) != 0) { + StringBuilder sb = new StringBuilder(3); + sb.append((char)('A' + i)); + sb.append(":\\"); + String root = sb.toString(); + if (sm != null) { + try { + sm.checkRead(root); + } catch (SecurityException x) { + continue; + } + } + result.add(WindowsPath.createFromNormalizedPath(this, root)); + } + } + return Collections.unmodifiableList(result); + } + + /** + * Iterator returned by getFileStores method. + */ + private class FileStoreIterator implements Iterator<FileStore> { + private final Iterator<Path> roots; + private FileStore next; + + FileStoreIterator() { + this.roots = getRootDirectories().iterator(); + } + + private FileStore readNext() { + assert Thread.holdsLock(this); + for (;;) { + if (!roots.hasNext()) + return null; + WindowsPath root = (WindowsPath)roots.next(); + // ignore if security manager denies access + try { + root.checkRead(); + } catch (SecurityException x) { + continue; + } + try { + FileStore fs = WindowsFileStore.create(root.toString(), true); + if (fs != null) + return fs; + } catch (IOException ioe) { + // skip it + } + } + } + + @Override + public synchronized boolean hasNext() { + if (next != null) + return true; + next = readNext(); + return next != null; + } + + @Override + public synchronized FileStore next() { + if (next == null) + next = readNext(); + if (next == null) { + throw new NoSuchElementException(); + } else { + FileStore result = next; + next = null; + return result; + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + @Override + public Iterable<FileStore> getFileStores() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); + } catch (SecurityException se) { + return Collections.emptyList(); + } + } + return new Iterable<FileStore>() { + public Iterator<FileStore> iterator() { + return new FileStoreIterator(); + } + }; + } + + // supported views + private static final Set<String> supportedFileAttributeViews = Collections + .unmodifiableSet(new HashSet<String>(Arrays.asList("basic", "dos", "acl", "owner", "xattr"))); + + @Override + public Set<String> supportedFileAttributeViews() { + return supportedFileAttributeViews; + } + + @Override + public Path getPath(String path) { + return WindowsPath.parse(this, path); + } + + @Override + public UserPrincipalLookupService getUserPrincipalLookupService() { + return theLookupService; + } + + private static final UserPrincipalLookupService theLookupService = + new UserPrincipalLookupService() { + @Override + public UserPrincipal lookupPrincipalByName(String name) + throws IOException + { + return WindowsUserPrincipals.lookup(name); + } + @Override + public GroupPrincipal lookupPrincipalByGroupName(String group) + throws IOException + { + UserPrincipal user = WindowsUserPrincipals.lookup(group); + if (!(user instanceof GroupPrincipal)) + throw new UserPrincipalNotFoundException(group); + return (GroupPrincipal)user; + } + }; + + @Override + public PathMatcher getPathMatcher(String syntaxAndInput) { + int pos = syntaxAndInput.indexOf(':'); + if (pos <= 0 || pos == syntaxAndInput.length()) + throw new IllegalArgumentException(); + String syntax = syntaxAndInput.substring(0, pos); + String input = syntaxAndInput.substring(pos+1); + + String expr; + if (syntax.equals(GLOB_SYNTAX)) { + expr = Globs.toWindowsRegexPattern(input); + } else { + if (syntax.equals(REGEX_SYNTAX)) { + expr = input; + } else { + throw new UnsupportedOperationException("Syntax '" + syntax + + "' not recognized"); + } + } + + // match in uppercase + StringBuilder sb = new StringBuilder(expr.length()); + for (int i=0; i<expr.length(); i++) { + sb.append(Character.toUpperCase(expr.charAt(i))); + } + expr = sb.toString(); + + // return matcher + final Pattern pattern = Pattern.compile(expr); + return new PathMatcher() { + @Override + public boolean matches(Path path) { + // match in uppercase + String s = path.toString(); + StringBuilder sb = new StringBuilder(s.length()); + for (int i=0; i<s.length(); i++) { + sb.append( Character.toUpperCase(s.charAt(i)) ); + } + return pattern.matcher(sb).matches(); + } + }; + } + private static final String GLOB_SYNTAX = "glob"; + private static final String REGEX_SYNTAX = "regex"; + + @Override + public WatchService newWatchService() + throws IOException + { + return new WindowsWatchService(this); + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java new file mode 100644 index 00000000000..bc28e95d01d --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java @@ -0,0 +1,146 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.spi.*; +import java.nio.file.attribute.*; +import java.nio.channels.*; +import java.net.URI; +import java.util.concurrent.ExecutorService; +import java.io.IOException; +import java.util.*; + +import sun.nio.ch.ThreadPool; + +public class WindowsFileSystemProvider + extends FileSystemProvider +{ + private static final String USER_DIR = "user.dir"; + private final WindowsFileSystem theFileSystem; + + public WindowsFileSystemProvider() { + theFileSystem = new WindowsFileSystem(this, System.getProperty(USER_DIR)); + } + + @Override + public String getScheme() { + return "file"; + } + + private void checkUri(URI uri) { + if (!uri.getScheme().equalsIgnoreCase(getScheme())) + throw new IllegalArgumentException("URI does not match this provider"); + if (uri.getAuthority() != null) + throw new IllegalArgumentException("Authority component present"); + if (uri.getPath() == null) + throw new IllegalArgumentException("Path component is undefined"); + if (!uri.getPath().equals("/")) + throw new IllegalArgumentException("Path component should be '/'"); + if (uri.getQuery() != null) + throw new IllegalArgumentException("Query component present"); + if (uri.getFragment() != null) + throw new IllegalArgumentException("Fragment component present"); + } + + @Override + public FileSystem newFileSystem(URI uri, Map<String,?> env) + throws IOException + { + checkUri(uri); + throw new FileSystemAlreadyExistsException(); + } + + @Override + public final FileSystem getFileSystem(URI uri) { + checkUri(uri); + return theFileSystem; + } + + @Override + public Path getPath(URI uri) { + return WindowsUriSupport.fromUri(theFileSystem, uri); + } + + @Override + public FileChannel newFileChannel(Path path, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + if (path == null) + throw new NullPointerException(); + if (!(path instanceof WindowsPath)) + throw new ProviderMismatchException(); + WindowsPath file = (WindowsPath)path; + + WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs); + try { + return WindowsChannelFactory + .newFileChannel(file.getPathForWin32Calls(), + file.getPathForPermissionCheck(), + options, + sd.address()); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + return null; + } finally { + if (sd != null) + sd.release(); + } + } + + @Override + public AsynchronousFileChannel newAsynchronousFileChannel(Path path, + Set<? extends OpenOption> options, + ExecutorService executor, + FileAttribute<?>... attrs) + throws IOException + { + if (path == null) + throw new NullPointerException(); + if (!(path instanceof WindowsPath)) + throw new ProviderMismatchException(); + WindowsPath file = (WindowsPath)path; + ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0); + WindowsSecurityDescriptor sd = + WindowsSecurityDescriptor.fromAttribute(attrs); + try { + return WindowsChannelFactory + .newAsynchronousFileChannel(file.getPathForWin32Calls(), + file.getPathForPermissionCheck(), + options, + sd.address(), + pool); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + return null; + } finally { + if (sd != null) + sd.release(); + } + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java b/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java new file mode 100644 index 00000000000..516275dfe55 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java @@ -0,0 +1,446 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.io.IOException; +import java.io.IOError; +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.misc.Unsafe; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * Utility methods for symbolic link support on Windows Vista and newer. + */ + +class WindowsLinkSupport { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + private WindowsLinkSupport() { + } + + /** + * Returns the target of a symbolic link + */ + static String readLink(WindowsPath path) throws IOException { + long handle = 0L; + try { + handle = path.openForReadAttributeAccess(false); // don't follow links + } catch (WindowsException x) { + x.rethrowAsIOException(path); + } + try { + return readLinkImpl(handle); + } finally { + CloseHandle(handle); + } + } + + /** + * Returns the final path of a given path as a String. This should be used + * prior to calling Win32 system calls that do not follow links. + */ + static String getFinalPath(WindowsPath input, boolean followLinks) + throws IOException + { + WindowsFileSystem fs = input.getFileSystem(); + + try { + // if not following links then don't need final path + if (!followLinks || !fs.supportsLinks()) + return input.getPathForWin32Calls(); + + // if file is a sym link then don't need final path + if (!WindowsFileAttributes.get(input, false).isSymbolicLink()) { + return input.getPathForWin32Calls(); + } + } catch (WindowsException x) { + x.rethrowAsIOException(input); + } + + // The file is a symbolic link so we open it and try to get the + // normalized path. This should succeed on NTFS but may fail if there + // is a link to a non-NFTS file system. + long h = 0; + try { + h = input.openForReadAttributeAccess(true); + } catch (WindowsException x) { + x.rethrowAsIOException(input); + } + try { + return stripPrefix(GetFinalPathNameByHandle(h)); + } catch (WindowsException x) { + // ERROR_INVALID_LEVEL is the error returned when not supported by + // the file system + if (x.lastError() != ERROR_INVALID_LEVEL) + x.rethrowAsIOException(input); + } finally { + CloseHandle(h); + } + + // Fallback: read target of link, resolve against parent, and repeat + // until file is not a link. + WindowsPath target = input; + int linkCount = 0; + do { + try { + WindowsFileAttributes attrs = + WindowsFileAttributes.get(target, false); + // non a link so we are done + if (!attrs.isSymbolicLink()) { + return target.getPathForWin32Calls(); + } + } catch (WindowsException x) { + x.rethrowAsIOException(target); + } + WindowsPath link = WindowsPath + .createFromNormalizedPath(fs, readLink(target)); + WindowsPath parent = target.getParent(); + if (parent == null) { + // no parent so use parent of absolute path + final WindowsPath t = target; + target = AccessController + .doPrivileged(new PrivilegedAction<WindowsPath>() { + @Override + public WindowsPath run() { + return t.toAbsolutePath(); + }}); + parent = target.getParent(); + } + target = parent.resolve(link); + + } while (++linkCount < 32); + + throw new FileSystemException(input.getPathForExceptionMessage(), null, + "Too many links"); + } + + /** + * Returns the actual path of a file, optionally resolving all symbolic + * links. + */ + static String getRealPath(WindowsPath input, boolean resolveLinks) + throws IOException + { + WindowsFileSystem fs = input.getFileSystem(); + if (!fs.supportsLinks()) + resolveLinks = false; + + // On Vista use GetFinalPathNameByHandle. This should succeed on NTFS + // but may fail if there is a link to a non-NFTS file system. + if (resolveLinks) { + long h = 0; + try { + h = input.openForReadAttributeAccess(true); + } catch (WindowsException x) { + x.rethrowAsIOException(input); + } + try { + return stripPrefix(GetFinalPathNameByHandle(h)); + } catch (WindowsException x) { + if (x.lastError() != ERROR_INVALID_LEVEL) + x.rethrowAsIOException(input); + } finally { + CloseHandle(h); + } + } + + // Not resolving links or we are on Windows Vista (or newer) with a + // link to non-NFTS file system. + + // Start with absolute path + String path = null; + try { + path = input.toAbsolutePath().toString(); + } catch (IOError x) { + throw (IOException)(x.getCause()); + } + + // Collapse "." and ".." + try { + path = GetFullPathName(path); + } catch (WindowsException x) { + x.rethrowAsIOException(input); + } + + // eliminate all symbolic links + if (resolveLinks) { + path = resolveAllLinks(WindowsPath.createFromNormalizedPath(fs, path)); + } + + // string builder to build up components of path + StringBuilder sb = new StringBuilder(path.length()); + + // Copy root component + int start; + char c0 = path.charAt(0); + char c1 = path.charAt(1); + if ((c0 <= 'z' && c0 >= 'a' || c0 <= 'Z' && c0 >= 'A') && + c1 == ':' && path.charAt(2) == '\\') { + // Driver specifier + sb.append(Character.toUpperCase(c0)); + sb.append(":\\"); + start = 3; + } else if (c0 == '\\' && c1 == '\\') { + // UNC pathname, begins with "\\\\host\\share" + int last = path.length() - 1; + int pos = path.indexOf('\\', 2); + // skip both server and share names + if (pos == -1 || (pos == last)) { + // The UNC does not have a share name (collapsed by GetFullPathName) + throw new FileSystemException(input.getPathForExceptionMessage(), + null, "UNC has invalid share"); + } + pos = path.indexOf('\\', pos+1); + if (pos < 0) { + pos = last; + sb.append(path).append("\\"); + } else { + sb.append(path, 0, pos+1); + } + start = pos + 1; + } else { + throw new AssertionError("path type not recognized"); + } + + // check root directory exists + try { + FirstFile fileData = FindFirstFile(sb.toString() + "*"); + FindClose(fileData.handle()); + } catch (WindowsException x) { + x.rethrowAsIOException(path); + } + + // iterate through each component to get its actual name in the + // directory + int curr = start; + while (curr < path.length()) { + int next = path.indexOf('\\', curr); + int end = (next == -1) ? path.length() : next; + String search = sb.toString() + path.substring(curr, end); + try { + FirstFile fileData = FindFirstFile(addLongPathPrefixIfNeeded(search)); + try { + sb.append(fileData.name()); + if (next != -1) { + sb.append('\\'); + } + } finally { + FindClose(fileData.handle()); + } + } catch (WindowsException e) { + e.rethrowAsIOException(path); + } + curr = end + 1; + } + + return sb.toString(); + } + + /** + * Returns target of a symbolic link given the handle of an open file + * (that should be a link). + */ + private static String readLinkImpl(long handle) throws IOException { + int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; + NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); + try { + try { + DeviceIoControlGetReparsePoint(handle, buffer.address(), size); + } catch (WindowsException x) { + // FIXME: exception doesn't have file name + if (x.lastError() == ERROR_NOT_A_REPARSE_POINT) + throw new NotLinkException(null, null, x.errorString()); + x.rethrowAsIOException((String)null); + } + + /* + * typedef struct _REPARSE_DATA_BUFFER { + * ULONG ReparseTag; + * USHORT ReparseDataLength; + * USHORT Reserved; + * union { + * struct { + * USHORT SubstituteNameOffset; + * USHORT SubstituteNameLength; + * USHORT PrintNameOffset; + * USHORT PrintNameLength; + * WCHAR PathBuffer[1]; + * } SymbolicLinkReparseBuffer; + * struct { + * USHORT SubstituteNameOffset; + * USHORT SubstituteNameLength; + * USHORT PrintNameOffset; + * USHORT PrintNameLength; + * WCHAR PathBuffer[1]; + * } MountPointReparseBuffer; + * struct { + * UCHAR DataBuffer[1]; + * } GenericReparseBuffer; + * }; + * } REPARSE_DATA_BUFFER + */ + final short OFFSETOF_REPARSETAG = 0; + final short OFFSETOF_PATHOFFSET = 8; + final short OFFSETOF_PATHLENGTH = 10; + final short OFFSETOF_PATHBUFFER = 16 + 4; // check this + + int tag = (int)unsafe.getLong(buffer.address() + OFFSETOF_REPARSETAG); + if (tag != IO_REPARSE_TAG_SYMLINK) { + // FIXME: exception doesn't have file name + throw new NotLinkException(null, null, "Reparse point is not a symbolic link"); + } + + // get offset and length of target + short nameOffset = unsafe.getShort(buffer.address() + OFFSETOF_PATHOFFSET); + short nameLengthInBytes = unsafe.getShort(buffer.address() + OFFSETOF_PATHLENGTH); + if ((nameLengthInBytes % 2) != 0) + throw new FileSystemException(null, null, "Symbolic link corrupted"); + + // copy into char array + char[] name = new char[nameLengthInBytes/2]; + unsafe.copyMemory(null, buffer.address() + OFFSETOF_PATHBUFFER + nameOffset, + name, Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes); + + // remove special prefix + String target = stripPrefix(new String(name)); + if (target.length() == 0) { + throw new IOException("Symbolic link target is invalid"); + } + return target; + } finally { + buffer.release(); + } + } + + /** + * Resolve all symbolic-links in a given absolute and normalized path + */ + private static String resolveAllLinks(WindowsPath path) + throws IOException + { + assert path.isAbsolute(); + WindowsFileSystem fs = path.getFileSystem(); + + // iterate through each name element of the path, resolving links as + // we go. + int linkCount = 0; + int elem = 0; + while (elem < path.getNameCount()) { + WindowsPath current = path.getRoot().resolve(path.subpath(0, elem+1)); + + WindowsFileAttributes attrs = null; + try { + attrs = WindowsFileAttributes.get(current, false); + } catch (WindowsException x) { + x.rethrowAsIOException(current); + } + + /** + * If a symbolic link then we resolve it against the parent + * of the current name element. We then resolve any remaining + * part of the path against the result. The target of the link + * may have "." and ".." components so re-normalize and restart + * the process from the first element. + */ + if (attrs.isSymbolicLink()) { + linkCount++; + if (linkCount > 32) + throw new IOException("Too many links"); + WindowsPath target = WindowsPath + .createFromNormalizedPath(fs, readLink(current)); + WindowsPath remainder = null; + int count = path.getNameCount(); + if ((elem+1) < count) { + remainder = path.subpath(elem+1, count); + } + path = current.getParent().resolve(target); + try { + String full = GetFullPathName(path.toString()); + if (!full.equals(path.toString())) { + path = WindowsPath.createFromNormalizedPath(fs, full); + } + } catch (WindowsException x) { + x.rethrowAsIOException(path); + } + if (remainder != null) { + path = path.resolve(remainder); + } + + // reset + elem = 0; + } else { + // not a link + elem++; + } + } + + return path.toString(); + } + + /** + * Add long path prefix to path if required. + */ + private static String addLongPathPrefixIfNeeded(String path) { + if (path.length() > 248) { + if (path.startsWith("\\\\")) { + path = "\\\\?\\UNC" + path.substring(1, path.length()); + } else { + path = "\\\\?\\" + path; + } + } + return path; + } + + /** + * Strip long path or symbolic link prefix from path + */ + private static String stripPrefix(String path) { + // prefix for resolved/long path + if (path.startsWith("\\\\?\\")) { + if (path.startsWith("\\\\?\\UNC\\")) { + path = "\\" + path.substring(7); + } else { + path = path.substring(4); + } + return path; + } + + // prefix for target of symbolic link + if (path.startsWith("\\??\\")) { + if (path.startsWith("\\??\\UNC\\")) { + path = "\\" + path.substring(7); + } else { + path = path.substring(4); + } + return path; + } + return path; + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java new file mode 100644 index 00000000000..fafee20a4cd --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java @@ -0,0 +1,1134 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.misc.Unsafe; + +/** + * Win32 and library calls. + */ + +class WindowsNativeDispatcher { + private WindowsNativeDispatcher() { } + + /** + * HANDLE CreateFile( + * LPCTSTR lpFileName, + * DWORD dwDesiredAccess, + * DWORD dwShareMode, + * LPSECURITY_ATTRIBUTES lpSecurityAttributes, + * DWORD dwCreationDisposition, + * DWORD dwFlagsAndAttributes, + * HANDLE hTemplateFile + * ) + */ + static long CreateFile(String path, + int dwDesiredAccess, + int dwShareMode, + long lpSecurityAttributes, + int dwCreationDisposition, + int dwFlagsAndAttributes) + throws WindowsException + { + NativeBuffer buffer = asNativeBuffer(path); + try { + return CreateFile0(buffer.address(), + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes); + } finally { + buffer.release(); + } + } + static long CreateFile(String path, + int dwDesiredAccess, + int dwShareMode, + int dwCreationDisposition, + int dwFlagsAndAttributes) + throws WindowsException + { + return CreateFile(path, dwDesiredAccess, dwShareMode, 0L, + dwCreationDisposition, dwFlagsAndAttributes); + } + private static native long CreateFile0(long lpFileName, + int dwDesiredAccess, + int dwShareMode, + long lpSecurityAttributes, + int dwCreationDisposition, + int dwFlagsAndAttributes) + throws WindowsException; + + /** + * CloseHandle( + * HANDLE hObject + * ) + */ + static native void CloseHandle(long handle); + + /** + * DeleteFile( + * LPCTSTR lpFileName + * ) + */ + static void DeleteFile(String path) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + DeleteFile0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native void DeleteFile0(long lpFileName) + throws WindowsException; + + /** + * CreateDirectory( + * LPCTSTR lpPathName, + * LPSECURITY_ATTRIBUTES lpSecurityAttributes + * ) + */ + static void CreateDirectory(String path, long lpSecurityAttributes) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + CreateDirectory0(buffer.address(), lpSecurityAttributes); + } finally { + buffer.release(); + } + } + private static native void CreateDirectory0(long lpFileName, long lpSecurityAttributes) + throws WindowsException; + + /** + * RemoveDirectory( + * LPCTSTR lpPathName + * ) + */ + static void RemoveDirectory(String path) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + RemoveDirectory0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native void RemoveDirectory0(long lpFileName) + throws WindowsException; + + /** + * Marks a file as a sparse file. + * + * DeviceIoControl( + * FSCTL_SET_SPARSE + * ) + */ + static native void DeviceIoControlSetSparse(long handle) + throws WindowsException; + + /** + * Retrieves the reparse point data associated with the file or directory. + * + * DeviceIoControl( + * FSCTL_GET_REPARSE_POINT + * ) + */ + static native void DeviceIoControlGetReparsePoint(long handle, + long bufferAddress, int bufferSize) throws WindowsException; + + /** + * HANDLE FindFirstFile( + * LPCTSTR lpFileName, + * LPWIN32_FIND_DATA lpFindFileData + * ) + */ + static FirstFile FindFirstFile(String path) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + FirstFile data = new FirstFile(); + FindFirstFile0(buffer.address(), data); + return data; + } finally { + buffer.release(); + } + } + static class FirstFile { + private long handle; + private String name; + + private FirstFile() { } + public long handle() { return handle; } + public String name() { return name; } + } + private static native void FindFirstFile0(long lpFileName, FirstFile obj) + throws WindowsException; + + /** + * HANDLE FindFirstFile( + * LPCTSTR lpFileName, + * LPWIN32_FIND_DATA lpFindFileData + * ) + */ + static long FindFirstFile(String path, long address) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + return FindFirstFile1(buffer.address(), address); + } finally { + buffer.release(); + } + } + private static native long FindFirstFile1(long lpFileName, long address) + throws WindowsException; + + /** + * FindNextFile( + * HANDLE hFindFile, + * LPWIN32_FIND_DATA lpFindFileData + * ) + * + * @return lpFindFileData->cFileName or null + */ + static native String FindNextFile(long handle, long address) + throws WindowsException; + + /** + * HANDLE FindFirstStreamW( + * LPCWSTR lpFileName, + * STREAM_INFO_LEVELS InfoLevel, + * LPVOID lpFindStreamData, + * DWORD dwFlags + * ) + */ + static FirstStream FindFirstStream(String path) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + FirstStream data = new FirstStream(); + FindFirstStream0(buffer.address(), data); + if (data.handle() == WindowsConstants.INVALID_HANDLE_VALUE) + return null; + return data; + } finally { + buffer.release(); + } + } + static class FirstStream { + private long handle; + private String name; + + private FirstStream() { } + public long handle() { return handle; } + public String name() { return name; } + } + private static native void FindFirstStream0(long lpFileName, FirstStream obj) + throws WindowsException; + + /* + * FindNextStreamW( + * HANDLE hFindStream, + * LPVOID lpFindStreamData + * ) + */ + static native String FindNextStream(long handle) throws WindowsException; + + /** + * FindClose( + * HANDLE hFindFile + * ) + */ + static native void FindClose(long handle) throws WindowsException; + + /** + * GetFileInformationByHandle( + * HANDLE hFile, + * LPBY_HANDLE_FILE_INFORMATION lpFileInformation + * ) + */ + static native void GetFileInformationByHandle(long handle, long address) + throws WindowsException; + + /** + * CopyFileEx( + * LPCWSTR lpExistingFileName + * LPCWSTR lpNewFileName, + * LPPROGRESS_ROUTINE lpProgressRoutine + * LPVOID lpData, + * LPBOOL pbCancel, + * DWORD dwCopyFlags + * ) + */ + static void CopyFileEx(String source, String target, int flags, + long addressToPollForCancel) + throws WindowsException + { + NativeBuffer sourceBuffer = asNativeBuffer(source); + NativeBuffer targetBuffer = asNativeBuffer(target); + try { + CopyFileEx0(sourceBuffer.address(), targetBuffer.address(), flags, + addressToPollForCancel); + } finally { + targetBuffer.release(); + sourceBuffer.release(); + } + } + private static native void CopyFileEx0(long existingAddress, long newAddress, + int flags, long addressToPollForCancel) throws WindowsException; + + /** + * MoveFileEx( + * LPCTSTR lpExistingFileName, + * LPCTSTR lpNewFileName, + * DWORD dwFlags + * ) + */ + static void MoveFileEx(String source, String target, int flags) + throws WindowsException + { + NativeBuffer sourceBuffer = asNativeBuffer(source); + NativeBuffer targetBuffer = asNativeBuffer(target); + try { + MoveFileEx0(sourceBuffer.address(), targetBuffer.address(), flags); + } finally { + targetBuffer.release(); + sourceBuffer.release(); + } + } + private static native void MoveFileEx0(long existingAddress, long newAddress, + int flags) throws WindowsException; + + /** + * DWORD GetFileAttributes( + * LPCTSTR lpFileName + * ) + */ + static int GetFileAttributes(String path) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + return GetFileAttributes0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native int GetFileAttributes0(long lpFileName) + throws WindowsException; + + /** + * SetFileAttributes( + * LPCTSTR lpFileName, + * DWORD dwFileAttributes + */ + static void SetFileAttributes(String path, int dwFileAttributes) + throws WindowsException + { + NativeBuffer buffer = asNativeBuffer(path); + try { + SetFileAttributes0(buffer.address(), dwFileAttributes); + } finally { + buffer.release(); + } + } + private static native void SetFileAttributes0(long lpFileName, + int dwFileAttributes) throws WindowsException; + + /** + * GetFileAttributesEx( + * LPCTSTR lpFileName, + * GET_FILEEX_INFO_LEVELS fInfoLevelId, + * LPVOID lpFileInformation + * ); + */ + static void GetFileAttributesEx(String path, long address) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + GetFileAttributesEx0(buffer.address(), address); + } finally { + buffer.release(); + } + } + private static native void GetFileAttributesEx0(long lpFileName, long address) + throws WindowsException; + /** + * SetFileTime( + * HANDLE hFile, + * CONST FILETIME *lpCreationTime, + * CONST FILETIME *lpLastAccessTime, + * CONST FILETIME *lpLastWriteTime + * ) + */ + static native void SetFileTime(long handle, long createTime, + long lastAccessTime, long lastWriteTime) throws WindowsException; + + /** + * SetEndOfFile( + * HANDLE hFile + * ) + */ + static native void SetEndOfFile(long handle) throws WindowsException; + + /** + * DWORD GetLogicalDrives(VOID) + */ + static native int GetLogicalDrives() throws WindowsException; + + /** + * GetVolumeInformation( + * LPCTSTR lpRootPathName, + * LPTSTR lpVolumeNameBuffer, + * DWORD nVolumeNameSize, + * LPDWORD lpVolumeSerialNumber, + * LPDWORD lpMaximumComponentLength, + * LPDWORD lpFileSystemFlags, + * LPTSTR lpFileSystemNameBuffer, + * DWORD nFileSystemNameSize + * ) + */ + static VolumeInformation GetVolumeInformation(String root) + throws WindowsException + { + NativeBuffer buffer = asNativeBuffer(root); + try { + VolumeInformation info = new VolumeInformation(); + GetVolumeInformation0(buffer.address(), info); + return info; + } finally { + buffer.release(); + } + } + static class VolumeInformation { + private String fileSystemName; + private String volumeName; + private int volumeSerialNumber; + private int flags; + private VolumeInformation() { } + + public String fileSystemName() { return fileSystemName; } + public String volumeName() { return volumeName; } + public int volumeSerialNumber() { return volumeSerialNumber; } + public int flags() { return flags; } + } + private static native void GetVolumeInformation0(long lpRoot, + VolumeInformation obj) + throws WindowsException; + + /** + * UINT GetDriveType( + * LPCTSTR lpRootPathName + * ) + */ + static int GetDriveType(String root) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(root); + try { + return GetDriveType0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native int GetDriveType0(long lpRoot) throws WindowsException; + + /** + * GetDiskFreeSpaceEx( + * LPCTSTR lpDirectoryName, + * PULARGE_INTEGER lpFreeBytesAvailableToCaller, + * PULARGE_INTEGER lpTotalNumberOfBytes, + * PULARGE_INTEGER lpTotalNumberOfFreeBytes + * ) + */ + static DiskFreeSpace GetDiskFreeSpaceEx(String path) + throws WindowsException + { + NativeBuffer buffer = asNativeBuffer(path); + try { + DiskFreeSpace space = new DiskFreeSpace(); + GetDiskFreeSpaceEx0(buffer.address(), space); + return space; + } finally { + buffer.release(); + } + } + static class DiskFreeSpace { + private long freeBytesAvailable; + private long totalNumberOfBytes; + private long totalNumberOfFreeBytes; + private DiskFreeSpace() { } + + public long freeBytesAvailable() { return freeBytesAvailable; } + public long totalNumberOfBytes() { return totalNumberOfBytes; } + public long totalNumberOfFreeBytes() { return totalNumberOfFreeBytes; } + } + private static native void GetDiskFreeSpaceEx0(long lpDirectoryName, + DiskFreeSpace obj) + throws WindowsException; + + + /** + * GetVolumePathName( + * LPCTSTR lpszFileName, + * LPTSTR lpszVolumePathName, + * DWORD cchBufferLength + * ) + * + * @return lpFileName + */ + static String GetVolumePathName(String path) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + return GetVolumePathName0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native String GetVolumePathName0(long lpFileName) + throws WindowsException; + + + /** + * InitializeSecurityDescriptor( + * PSECURITY_DESCRIPTOR pSecurityDescriptor, + * DWORD dwRevision + * ) + */ + static native void InitializeSecurityDescriptor(long sdAddress) + throws WindowsException; + + /** + * InitializeAcl( + * PACL pAcl, + * DWORD nAclLength, + * DWORD dwAclRevision + * ) + */ + static native void InitializeAcl(long aclAddress, int size) + throws WindowsException; + + /** + * GetFileSecurity( + * LPCTSTR lpFileName, + * SECURITY_INFORMATION RequestedInformation, + * PSECURITY_DESCRIPTOR pSecurityDescriptor, + * DWORD nLength, + * LPDWORD lpnLengthNeeded + * ) + */ + static int GetFileSecurity(String path, + int requestedInformation, + long pSecurityDescriptor, + int nLength) throws WindowsException + { + NativeBuffer buffer = asNativeBuffer(path); + try { + return GetFileSecurity0(buffer.address(), requestedInformation, + pSecurityDescriptor, nLength); + } finally { + buffer.release(); + } + } + private static native int GetFileSecurity0(long lpFileName, + int requestedInformation, + long pSecurityDescriptor, + int nLength) throws WindowsException; + + /** + * SetFileSecurity( + * LPCTSTR lpFileName, + * SECURITY_INFORMATION SecurityInformation, + * PSECURITY_DESCRIPTOR pSecurityDescriptor + * ) + */ + static void SetFileSecurity(String path, + int securityInformation, + long pSecurityDescriptor) + throws WindowsException + { + NativeBuffer buffer = asNativeBuffer(path); + try { + SetFileSecurity0(buffer.address(), securityInformation, + pSecurityDescriptor); + } finally { + buffer.release(); + } + } + static native void SetFileSecurity0(long lpFileName, int securityInformation, + long pSecurityDescriptor) throws WindowsException; + + /** + * GetSecurityDescriptorOwner( + * PSECURITY_DESCRIPTOR pSecurityDescriptor + * PSID *pOwner, + * LPBOOL lpbOwnerDefaulted + * ) + * + * @return pOwner + */ + static native long GetSecurityDescriptorOwner(long pSecurityDescriptor) + throws WindowsException; + + /** + * SetSecurityDescriptorOwner( + * PSECURITY_DESCRIPTOR pSecurityDescriptor, + * PSID pOwner, + * BOOL bOwnerDefaulted + * ) + */ + static native void SetSecurityDescriptorOwner(long pSecurityDescriptor, + long pOwner) + throws WindowsException; + + /** + * GetSecurityDescriptorDacl( + * PSECURITY_DESCRIPTOR pSecurityDescriptor, + * LPBOOL lpbDaclPresent, + * PACL *pDacl, + * LPBOOL lpbDaclDefaulted + * ) + */ + static native long GetSecurityDescriptorDacl(long pSecurityDescriptor); + + /** + * SetSecurityDescriptorDacl( + * PSECURITY_DESCRIPTOR pSecurityDescriptor, + * BOOL bDaclPresent, + * PACL pDacl, + * BOOL bDaclDefaulted + * ) + */ + static native void SetSecurityDescriptorDacl(long pSecurityDescriptor, long pAcl) + throws WindowsException; + + + /** + * GetAclInformation( + * PACL pAcl, + * LPVOID pAclInformation, + * DWORD nAclInformationLength, + * ACL_INFORMATION_CLASS dwAclInformationClass + * ) + */ + static AclInformation GetAclInformation(long aclAddress) { + AclInformation info = new AclInformation(); + GetAclInformation0(aclAddress, info); + return info; + } + static class AclInformation { + private int aceCount; + private AclInformation() { } + + public int aceCount() { return aceCount; } + } + private static native void GetAclInformation0(long aclAddress, + AclInformation obj); + + /** + * GetAce( + * PACL pAcl, + * DWORD dwAceIndex, + * LPVOID *pAce + * ) + */ + static native long GetAce(long aclAddress, int aceIndex); + + /** + * AddAccessAllowedAceEx( + * PACL pAcl, + * DWORD dwAceRevision, + * DWORD AceFlags, + * DWORD AccessMask, + * PSID pSid + * ) + */ + static native void AddAccessAllowedAceEx(long aclAddress, int flags, + int mask, long sidAddress) throws WindowsException; + + /** + * AddAccessDeniedAceEx( + * PACL pAcl, + * DWORD dwAceRevision, + * DWORD AceFlags, + * DWORD AccessMask, + * PSID pSid + * ) + */ + static native void AddAccessDeniedAceEx(long aclAddress, int flags, + int mask, long sidAddress) throws WindowsException; + + /** + * LookupAccountSid( + * LPCTSTR lpSystemName, + * PSID Sid, + * LPTSTR Name, + * LPDWORD cbName, + * LPTSTR ReferencedDomainName, + * LPDWORD cbReferencedDomainName, + * PSID_NAME_USE peUse + * ) + */ + static Account LookupAccountSid(long sidAddress) throws WindowsException { + Account acc = new Account(); + LookupAccountSid0(sidAddress, acc); + return acc; + } + static class Account { + private String domain; + private String name; + private int use; + private Account() { } + + public String domain() { return domain; } + public String name() { return name; } + public int use() { return use; } + } + private static native void LookupAccountSid0(long sidAddress, Account obj) + throws WindowsException; + + /** + * LookupAccountName( + * LPCTSTR lpSystemName, + * LPCTSTR lpAccountName, + * PSID Sid, + * LPDWORD cbSid, + * LPTSTR ReferencedDomainName, + * LPDWORD cbReferencedDomainName, + * PSID_NAME_USE peUse + * ) + * + * @return cbSid + */ + static int LookupAccountName(String accountName, + long pSid, + int cbSid) throws WindowsException + { + NativeBuffer buffer = asNativeBuffer(accountName); + try { + return LookupAccountName0(buffer.address(), pSid, cbSid); + } finally { + buffer.release(); + } + } + private static native int LookupAccountName0(long lpAccountName, long pSid, + int cbSid) throws WindowsException; + + /** + * DWORD GetLengthSid( + * PSID pSid + * ) + */ + static native int GetLengthSid(long sidAddress); + + /** + * ConvertSidToStringSid( + * PSID Sid, + * LPTSTR* StringSid + * ) + * + * @return StringSid + */ + static native String ConvertSidToStringSid(long sidAddress) + throws WindowsException; + + /** + * ConvertStringSidToSid( + * LPCTSTR StringSid, + * PSID* pSid + * ) + * + * @return pSid + */ + static long ConvertStringSidToSid(String sidString) + throws WindowsException + { + NativeBuffer buffer = asNativeBuffer(sidString); + try { + return ConvertStringSidToSid0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native long ConvertStringSidToSid0(long lpStringSid) + throws WindowsException; + + /** + * HANDLE GetCurrentProcess(VOID) + */ + static native long GetCurrentProcess(); + + /** + * HANDLE GetCurrentThread(VOID) + */ + static native long GetCurrentThread(); + + /** + * OpenProcessToken( + * HANDLE ProcessHandle, + * DWORD DesiredAccess, + * PHANDLE TokenHandle + * ) + */ + static native long OpenProcessToken(long hProcess, int desiredAccess) + throws WindowsException; + + /** + * OpenThreadToken( + * HANDLE ThreadHandle, + * DWORD DesiredAccess, + * BOOL OpenAsSelf, + * PHANDLE TokenHandle + * ) + */ + static native long OpenThreadToken(long hThread, int desiredAccess, + boolean openAsSelf) throws WindowsException; + + /** + */ + static native long DuplicateTokenEx(long hThread, int desiredAccess) + throws WindowsException; + + /** + * SetThreadToken( + * PHANDLE Thread, + * HANDLE Token + * ) + */ + static native void SetThreadToken(long thread, long hToken) + throws WindowsException; + + /** + * GetTokenInformation( + * HANDLE TokenHandle, + * TOKEN_INFORMATION_CLASS TokenInformationClass, + * LPVOID TokenInformation, + * DWORD TokenInformationLength, + * PDWORD ReturnLength + * ) + */ + static native int GetTokenInformation(long token, int tokenInfoClass, + long pTokenInfo, int tokenInfoLength) throws WindowsException; + + /** + * AdjustTokenPrivileges( + * HANDLE TokenHandle, + * BOOL DisableAllPrivileges + * PTOKEN_PRIVILEGES NewState + * DWORD BufferLength + * PTOKEN_PRIVILEGES + * PDWORD ReturnLength + * ) + */ + static native void AdjustTokenPrivileges(long token, long luid, int attributes) + throws WindowsException; + + /** + */ + static long LookupPrivilegeValue(String name) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(name); + try { + return LookupPrivilegeValue0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native long LookupPrivilegeValue0(long lpName) + throws WindowsException; + + /** + * BuildTrusteeWithSid( + * PTRUSTEE pTrustee, + * PSID pSid + * ) + * + * @return pTrustee + */ + static native long BuildTrusteeWithSid(long pSid); + + /** + * GetEffectiveRightsFromAcl( + * PACL pacl, + * PTRUSTEE pTrustee, + * PACCESS_MASK pAccessRights + * ) + * + * @return AccessRights + */ + static native int GetEffectiveRightsFromAcl(long pAcl, long pTrustee) + throws WindowsException; + + /** + * CreateSymbolicLink( + * LPCWSTR lpSymlinkFileName, + * LPCWSTR lpTargetFileName, + * DWORD dwFlags + * ) + */ + static void CreateSymbolicLink(String link, String target, int flags) + throws WindowsException + { + NativeBuffer linkBuffer = asNativeBuffer(link); + NativeBuffer targetBuffer = asNativeBuffer(target); + try { + CreateSymbolicLink0(linkBuffer.address(), targetBuffer.address(), + flags); + } finally { + targetBuffer.release(); + linkBuffer.release(); + } + } + private static native void CreateSymbolicLink0(long linkAddress, + long targetAddress, int flags) throws WindowsException; + + /** + * CreateHardLink( + * LPCTSTR lpFileName, + * LPCTSTR lpExistingFileName, + * LPSECURITY_ATTRIBUTES lpSecurityAttributes + * ) + */ + static void CreateHardLink(String newFile, String existingFile) + throws WindowsException + { + NativeBuffer newFileBuffer = asNativeBuffer(newFile); + NativeBuffer existingFileBuffer = asNativeBuffer(existingFile); + try { + CreateHardLink0(newFileBuffer.address(), existingFileBuffer.address()); + } finally { + existingFileBuffer.release(); + newFileBuffer.release(); + } + } + private static native void CreateHardLink0(long newFileBuffer, + long existingFiletBuffer) throws WindowsException; + + /** + * GetFullPathName( + * LPCTSTR lpFileName, + * DWORD nBufferLength, + * LPTSTR lpBuffer, + * LPTSTR *lpFilePart + * ) + */ + static String GetFullPathName(String path) throws WindowsException { + NativeBuffer buffer = asNativeBuffer(path); + try { + return GetFullPathName0(buffer.address()); + } finally { + buffer.release(); + } + } + private static native String GetFullPathName0(long pathAddress) + throws WindowsException; + + /** + * GetFinalPathNameByHandle( + * HANDLE hFile, + * LPTSTR lpszFilePath, + * DWORD cchFilePath, + * DWORD dwFlags + * ) + */ + static native String GetFinalPathNameByHandle(long handle) + throws WindowsException; + + /** + * FormatMessage( + * DWORD dwFlags, + * LPCVOID lpSource, + * DWORD dwMessageId, + * DWORD dwLanguageId, + * LPTSTR lpBuffer, + * DWORD nSize, + * va_list *Arguments + * ) + */ + static native String FormatMessage(int errorCode); + + /** + * LocalFree( + * HLOCAL hMem + * ) + */ + static native void LocalFree(long address); + + /** + * HANDLE CreateIoCompletionPort ( + * HANDLE FileHandle, + * HANDLE ExistingCompletionPort, + * DWORD CompletionKey, + * DWORD NumberOfConcurrentThreads + * ) + */ + static native long CreateIoCompletionPort(long fileHandle, long existingPort, + int completionKey) throws WindowsException; + + + /** + * GetQueuedCompletionStatus( + * HANDLE CompletionPort, + * LPDWORD lpNumberOfBytesTransferred, + * LPDWORD lpCompletionKey, + * LPOVERLAPPED *lpOverlapped, + * DWORD dwMilliseconds + */ + static CompletionStatus GetQueuedCompletionStatus(long completionPort) + throws WindowsException + { + CompletionStatus status = new CompletionStatus(); + GetQueuedCompletionStatus0(completionPort, status); + return status; + } + static class CompletionStatus { + private int error; + private int bytesTransferred; + private int completionKey; + private CompletionStatus() { } + + int error() { return error; } + int bytesTransferred() { return bytesTransferred; } + int completionKey() { return completionKey; } + } + private static native void GetQueuedCompletionStatus0(long completionPort, + CompletionStatus status) throws WindowsException; + + /** + * PostQueuedCompletionStatus( + * HANDLE CompletionPort, + * DWORD dwNumberOfBytesTransferred, + * DWORD dwCompletionKey, + * LPOVERLAPPED lpOverlapped + * ) + */ + static native void PostQueuedCompletionStatus(long completionPort, + int completionKey) throws WindowsException; + + /** + * ReadDirectoryChangesW( + * HANDLE hDirectory, + * LPVOID lpBuffer, + * DWORD nBufferLength, + * BOOL bWatchSubtree, + * DWORD dwNotifyFilter, + * LPDWORD lpBytesReturned, + * LPOVERLAPPED lpOverlapped, + * LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine + * ) + */ + static native void ReadDirectoryChangesW(long hDirectory, + long bufferAddress, + int bufferLength, + boolean watchSubTree, + int filter, + long bytesReturnedAddress, + long pOverlapped) + throws WindowsException; + + /** + * BackupRead( + * HANDLE hFile, + * LPBYTE lpBuffer, + * DWORD nNumberOfBytesToRead, + * LPDWORD lpNumberOfBytesRead, + * BOOL bAbort, + * BOOL bProcessSecurity, + * LPVOID* lpContext + * ) + */ + static BackupResult BackupRead(long hFile, + long bufferAddress, + int bufferSize, + boolean abort, + long context) + throws WindowsException + { + BackupResult result = new BackupResult(); + BackupRead0(hFile, bufferAddress, bufferSize, abort, context, result); + return result; + } + static class BackupResult { + private int bytesTransferred; + private long context; + private BackupResult() { } + + int bytesTransferred() { return bytesTransferred; } + long context() { return context; } + } + private static native void BackupRead0(long hFile, long bufferAddress, + int bufferSize, boolean abort, long context, BackupResult result) + throws WindowsException; + + /** + * BackupSeek( + * HANDLE hFile, + * DWORD dwLowBytesToSeek, + * DWORD dwHighBytesToSeek, + * LPDWORD lpdwLowByteSeeked, + * LPDWORD lpdwHighByteSeeked, + * LPVOID* lpContext + * ) + */ + static native void BackupSeek(long hFile, long bytesToSeek, long context) + throws WindowsException; + + + // -- support for copying String with a NativeBuffer -- + + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + static NativeBuffer asNativeBuffer(String s) { + int stringLengthInBytes = s.length() << 1; + int sizeInBytes = stringLengthInBytes + 2; // char terminator + + // get a native buffer of sufficient size + NativeBuffer buffer = NativeBuffers.getNativeBufferFromCache(sizeInBytes); + if (buffer == null) { + buffer = NativeBuffers.allocNativeBuffer(sizeInBytes); + } else { + // buffer already contains the string contents + if (buffer.owner() == s) + return buffer; + } + + // copy into buffer and zero terminate + char[] chars = s.toCharArray(); + unsafe.copyMemory(chars, Unsafe.ARRAY_CHAR_BASE_OFFSET, null, + buffer.address(), (long)stringLengthInBytes); + unsafe.putChar(buffer.address() + stringLengthInBytes, (char)0); + buffer.setOwner(s); + return buffer; + } + + // -- native library initialization -- + + private static native void initIDs(); + + static { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + // nio.dll has dependency on net.dll + System.loadLibrary("net"); + System.loadLibrary("nio"); + return null; + }}); + initIDs(); + } + +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java b/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java new file mode 100644 index 00000000000..2fda59d2bfb --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java @@ -0,0 +1,1375 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.AbstractPath; +import java.nio.channels.*; +import java.io.*; +import java.net.URI; +import java.security.AccessController; +import java.util.*; +import java.lang.ref.WeakReference; + +import com.sun.nio.file.ExtendedWatchEventModifier; + +import sun.security.util.SecurityConstants; +import sun.misc.Unsafe; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * Windows implementation of Path + */ + +class WindowsPath extends AbstractPath { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // The maximum path that does not require long path prefix. On Windows + // the maximum path is 260 minus 1 (NUL) but for directories it is 260 + // minus 12 minus 1 (to allow for the creation of a 8.3 file in the + // directory). + private static final int MAX_PATH = 247; + + // Maximum extended-length path + private static final int MAX_LONG_PATH = 32000; + + // FIXME - eliminate this reference to reduce space + private final WindowsFileSystem fs; + + // path type + private final WindowsPathType type; + // root component (may be empty) + private final String root; + // normalized path + private final String path; + + // the path to use in Win32 calls. This differs from path for relative + // paths and has a long path prefix for all paths longer than MAX_PATH. + private volatile WeakReference<String> pathForWin32Calls; + + // offsets into name components (computed lazily) + private volatile Integer[] offsets; + + // computed hash code (computed lazily, no need to be volatile) + private int hash; + + + /** + * Initializes a new instance of this class. + */ + private WindowsPath(WindowsFileSystem fs, + WindowsPathType type, + String root, + String path) + { + this.fs = fs; + this.type = type; + this.root = root; + this.path = path; + } + + /** + * Creates a Path by parsing the given path. + */ + static WindowsPath parse(WindowsFileSystem fs, String path) { + WindowsPathParser.Result result = WindowsPathParser.parse(path); + return new WindowsPath(fs, result.type(), result.root(), result.path()); + } + + /** + * Creates a Path from a given path that is known to be normalized. + */ + static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, + String path, + BasicFileAttributes attrs) + { + try { + WindowsPathParser.Result result = + WindowsPathParser.parseNormalizedPath(path); + if (attrs == null) { + return new WindowsPath(fs, + result.type(), + result.root(), + result.path()); + } else { + return new WindowsPathWithAttributes(fs, + result.type(), + result.root(), + result.path(), + attrs); + } + } catch (InvalidPathException x) { + throw new AssertionError(x.getMessage()); + } + } + + /** + * Creates a WindowsPath from a given path that is known to be normalized. + */ + static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, + String path) + { + return createFromNormalizedPath(fs, path, null); + } + + /** + * Special implementation with attached/cached attributes (used to quicken + * file tree traveral) + */ + private static class WindowsPathWithAttributes + extends WindowsPath implements BasicFileAttributesHolder + { + final WeakReference<BasicFileAttributes> ref; + + WindowsPathWithAttributes(WindowsFileSystem fs, + WindowsPathType type, + String root, + String path, + BasicFileAttributes attrs) + { + super(fs, type, root, path); + ref = new WeakReference<BasicFileAttributes>(attrs); + } + + @Override + public BasicFileAttributes get() { + return ref.get(); + } + + @Override + public void invalidate() { + ref.clear(); + } + } + + // use this message when throwing exceptions + String getPathForExceptionMessage() { + return path; + } + + // use this path for permission checks + String getPathForPermissionCheck() { + return path; + } + + // use this path for Win32 calls + // This method will prefix long paths with \\?\ or \\?\UNC as required. + String getPathForWin32Calls() throws WindowsException { + // short absolute paths can be used directly + if (isAbsolute() && path.length() <= MAX_PATH) + return path; + + // return cached values if available + WeakReference<String> ref = pathForWin32Calls; + String resolved = (ref != null) ? ref.get() : null; + if (resolved != null) { + // Win32 path already available + return resolved; + } + + // resolve against default directory + resolved = getAbsolutePath(); + + // Long paths need to have "." and ".." removed and be prefixed with + // "\\?\". Note that it is okay to remove ".." even when it follows + // a link - for example, it is okay for foo/link/../bar to be changed + // to foo/bar. The reason is that Win32 APIs to access foo/link/../bar + // will access foo/bar anyway (which differs to Unix systems) + if (resolved.length() > MAX_PATH) { + if (resolved.length() > MAX_LONG_PATH) { + throw new WindowsException("Cannot access file with path exceeding " + + MAX_LONG_PATH + " characters"); + } + resolved = addPrefixIfNeeded(GetFullPathName(resolved)); + } + + // cache the resolved path (except drive relative paths as the working + // directory on removal media devices can change during the lifetime + // of the VM) + if (type != WindowsPathType.DRIVE_RELATIVE) { + synchronized (path) { + pathForWin32Calls = new WeakReference<String>(resolved); + } + } + return resolved; + } + + // return this path resolved against the file system's default directory + private String getAbsolutePath() throws WindowsException { + if (isAbsolute()) + return path; + + // Relative path ("foo" for example) + if (type == WindowsPathType.RELATIVE) { + String defaultDirectory = getFileSystem().defaultDirectory(); + if (defaultDirectory.endsWith("\\")) { + return defaultDirectory + path; + } else { + StringBuilder sb = + new StringBuilder(defaultDirectory.length() + path.length() + 1); + return sb.append(defaultDirectory).append('\\').append(path).toString(); + } + } + + // Directory relative path ("\foo" for example) + if (type == WindowsPathType.DIRECTORY_RELATIVE) { + String defaultRoot = getFileSystem().defaultRoot(); + return defaultRoot + path.substring(1); + } + + // Drive relative path ("C:foo" for example). + if (isSameDrive(root, getFileSystem().defaultRoot())) { + // relative to default directory + String remaining = path.substring(root.length()); + String defaultDirectory = getFileSystem().defaultDirectory(); + String result; + if (defaultDirectory.endsWith("\\")) { + result = defaultDirectory + remaining; + } else { + result = defaultDirectory + "\\" + remaining; + } + return result; + } else { + // relative to some other drive + String wd; + try { + int dt = GetDriveType(root + "\\"); + if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR) + throw new WindowsException(""); + wd = GetFullPathName(root + "."); + } catch (WindowsException x) { + throw new WindowsException("Unable to get working directory of drive '" + + Character.toUpperCase(root.charAt(0)) + "'"); + } + String result = wd; + if (wd.endsWith("\\")) { + result += path.substring(root.length()); + } else { + if (path.length() > root.length()) + result += "\\" + path.substring(root.length()); + } + return result; + } + } + + // returns true if same drive letter + private static boolean isSameDrive(String root1, String root2) { + return Character.toUpperCase(root1.charAt(0)) == + Character.toUpperCase(root2.charAt(0)); + } + + // Add long path prefix to path if required + private static String addPrefixIfNeeded(String path) { + if (path.length() > 248) { + if (path.startsWith("\\\\")) { + path = "\\\\?\\UNC" + path.substring(1, path.length()); + } else { + path = "\\\\?\\" + path; + } + } + return path; + } + + @Override + public WindowsFileSystem getFileSystem() { + return fs; + } + + // -- Path operations -- + + @Override + public Path getName() { + // represents root component only + if (root.length() == path.length()) + return null; + int off = path.lastIndexOf('\\'); + if (off < root.length()) + off = root.length(); + else + off++; + return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", path.substring(off)); + } + + @Override + public WindowsPath getParent() { + // represents root component only + if (root.length() == path.length()) + return null; + int off = path.lastIndexOf('\\'); + if (off < root.length()) + return getRoot(); + else + return new WindowsPath(getFileSystem(), + type, + root, + path.substring(0, off)); + } + + @Override + public WindowsPath getRoot() { + if (root.length() == 0) + return null; + return new WindowsPath(getFileSystem(), type, root, root); + } + + // package-private + boolean isUnc() { + return type == WindowsPathType.UNC; + } + + boolean needsSlashWhenResolving() { + if (path.endsWith("\\")) + return false; + return path.length() > root.length(); + } + + @Override + public boolean isAbsolute() { + return type == WindowsPathType.ABSOLUTE || type == WindowsPathType.UNC; + } + + private WindowsPath checkPath(FileRef path) { + if (path == null) + throw new NullPointerException(); + if (!(path instanceof WindowsPath)) { + throw new ProviderMismatchException(); + } + return (WindowsPath)path; + } + + @Override + public WindowsPath relativize(Path obj) { + WindowsPath other = checkPath(obj); + if (this.equals(other)) + return null; + + // can only relativize paths of the same type + if (this.type != other.type) + throw new IllegalArgumentException("'other' is different type of Path"); + + // can only relativize paths if root component matches + if (!this.root.equalsIgnoreCase(other.root)) + throw new IllegalArgumentException("'other' has different root"); + + int bn = this.getNameCount(); + int cn = other.getNameCount(); + + // skip matching names + int n = (bn > cn) ? cn : bn; + int i = 0; + while (i < n) { + if (!this.getName(i).equals(other.getName(i))) + break; + i++; + } + + // append ..\ for remaining names in the base + StringBuilder result = new StringBuilder(); + for (int j=i; j<bn; j++) { + result.append("..\\"); + } + + // append remaining names in child + for (int j=i; j<cn; j++) { + result.append(other.getName(j).toString()); + result.append("\\"); + } + + // drop trailing slash in result + result.setLength(result.length()-1); + return createFromNormalizedPath(getFileSystem(), result.toString()); + } + + @Override + public Path normalize() { + final int count = getNameCount(); + if (count == 0) + return this; + + boolean[] ignore = new boolean[count]; // true => ignore name + int remaining = count; // number of names remaining + + // multiple passes to eliminate all occurences of "." and "name/.." + int prevRemaining; + do { + prevRemaining = remaining; + int prevName = -1; + for (int i=0; i<count; i++) { + if (ignore[i]) + continue; + + String name = elementAsString(i); + + // not "." or ".." + if (name.length() > 2) { + prevName = i; + continue; + } + + // "." or something else + if (name.length() == 1) { + // ignore "." + if (name.charAt(0) == '.') { + ignore[i] = true; + remaining--; + } else { + prevName = i; + } + continue; + } + + // not ".." + if (name.charAt(0) != '.' || name.charAt(1) != '.') { + prevName = i; + continue; + } + + // ".." found + if (prevName >= 0) { + // name/<ignored>/.. found so mark name and ".." to be + // ignored + ignore[prevName] = true; + ignore[i] = true; + remaining = remaining - 2; + prevName = -1; + } else { + // Cases: + // C:\<ignored>\.. + // \\server\\share\<ignored>\.. + // \<ignored>.. + if (isAbsolute() || type == WindowsPathType.DIRECTORY_RELATIVE) { + boolean hasPrevious = false; + for (int j=0; j<i; j++) { + if (!ignore[j]) { + hasPrevious = true; + break; + } + } + if (!hasPrevious) { + // all proceeding names are ignored + ignore[i] = true; + remaining--; + } + } + } + } + } while (prevRemaining > remaining); + + // no redundant names + if (remaining == count) + return this; + + // corner case - all names removed + if (remaining == 0) { + return getRoot(); + } + + // re-constitute the path from the remaining names. + StringBuilder result = new StringBuilder(); + if (root != null) + result.append(root); + for (int i=0; i<count; i++) { + if (!ignore[i]) { + result.append(getName(i).toString()); + result.append("\\"); + } + } + + // drop trailing slash in result + result.setLength(result.length()-1); + return createFromNormalizedPath(getFileSystem(), result.toString()); + } + + @Override + public WindowsPath resolve(Path obj) { + if (obj == null) + return this; + WindowsPath other = checkPath(obj); + if (other.isAbsolute()) + return other; + + switch (other.type) { + case RELATIVE: { + String result; + if (path.endsWith("\\") || (root.length() == path.length())) { + result = path + other.path; + } else { + result = path + "\\" + other.path; + } + return new WindowsPath(getFileSystem(), type, root, result); + } + + case DIRECTORY_RELATIVE: { + String result; + if (root.endsWith("\\")) { + result = root + other.path.substring(1); + } else { + result = root + other.path; + } + return createFromNormalizedPath(getFileSystem(), result); + } + + case DRIVE_RELATIVE: { + if (!root.endsWith("\\")) + return other; + // if different roots then return other + String thisRoot = root.substring(0, root.length()-1); + if (!thisRoot.equalsIgnoreCase(other.root)) + return other; + // same roots + String remaining = other.path.substring(other.root.length()); + String result; + if (path.endsWith("\\")) { + result = path + remaining; + } else { + result = path + "\\" + remaining; + } + return createFromNormalizedPath(getFileSystem(), result); + } + + default: + throw new AssertionError(); + } + } + + @Override + public WindowsPath resolve(String other) { + return resolve(getFileSystem().getPath(other)); + } + + // generate offset array + private void initOffsets() { + if (offsets == null) { + ArrayList<Integer> list = new ArrayList<Integer>(); + int start = root.length(); + int off = root.length(); + while (off < path.length()) { + if (path.charAt(off) != '\\') { + off++; + } else { + list.add(start); + start = ++off; + } + } + if (start != off) + list.add(start); + synchronized (this) { + if (offsets == null) + offsets = list.toArray(new Integer[list.size()]); + } + } + } + + @Override + public int getNameCount() { + initOffsets(); + return offsets.length; + } + + private String elementAsString(int i) { + initOffsets(); + if (i == (offsets.length-1)) + return path.substring(offsets[i]); + return path.substring(offsets[i], offsets[i+1]-1); + } + + @Override + public WindowsPath getName(int index) { + initOffsets(); + if (index < 0 || index >= offsets.length) + throw new IllegalArgumentException(); + return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", elementAsString(index)); + } + + @Override + public WindowsPath subpath(int beginIndex, int endIndex) { + initOffsets(); + if (beginIndex < 0) + throw new IllegalArgumentException(); + if (beginIndex >= offsets.length) + throw new IllegalArgumentException(); + if (endIndex > offsets.length) + throw new IllegalArgumentException(); + if (beginIndex >= endIndex) + throw new IllegalArgumentException(); + + StringBuilder sb = new StringBuilder(); + Integer[] nelems = new Integer[endIndex - beginIndex]; + for (int i = beginIndex; i < endIndex; i++) { + nelems[i-beginIndex] = sb.length(); + sb.append(elementAsString(i)); + if (i != (endIndex-1)) + sb.append("\\"); + } + return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", sb.toString()); + } + + @Override + public boolean startsWith(Path obj) { + WindowsPath other = checkPath(obj); + + // if this path has a root component the given path's root must match + if (!this.root.equalsIgnoreCase(other.root)) + return false; + + // roots match so compare elements + int thisCount = getNameCount(); + int otherCount = other.getNameCount(); + if (otherCount <= thisCount) { + while (--otherCount >= 0) { + String thisElement = this.elementAsString(otherCount); + String otherElement = other.elementAsString(otherCount); + // FIXME: should compare in uppercase + if (!thisElement.equalsIgnoreCase(otherElement)) + return false; + } + return true; + } + return false; + } + + @Override + public boolean endsWith(Path obj) { + WindowsPath other = checkPath(obj); + + // other path is longer + if (other.path.length() > path.length()) { + return false; + } + + int thisCount = this.getNameCount(); + int otherCount = other.getNameCount(); + + // given path has more elements that this path + if (otherCount > thisCount) { + return false; + } + + // compare roots + if (other.root.length() > 0) { + if (otherCount < thisCount) + return false; + // FIXME: should compare in uppercase + if (!this.root.equalsIgnoreCase(other.root)) + return false; + } + + // match last 'otherCount' elements + int off = thisCount - otherCount; + while (--otherCount >= 0) { + String thisElement = this.elementAsString(off + otherCount); + String otherElement = other.elementAsString(otherCount); + // FIXME: should compare in uppercase + if (!thisElement.equalsIgnoreCase(otherElement)) + return false; + } + return true; + } + + @Override + public int compareTo(Path obj) { + if (obj == null) + throw new NullPointerException(); + String s1 = path; + String s2 = ((WindowsPath)obj).path; + int n1 = s1.length(); + int n2 = s2.length(); + int min = Math.min(n1, n2); + for (int i = 0; i < min; i++) { + char c1 = s1.charAt(i); + char c2 = s2.charAt(i); + if (c1 != c2) { + c1 = Character.toUpperCase(c1); + c2 = Character.toUpperCase(c2); + if (c1 != c2) { + return c1 - c2; + } + } + } + return n1 - n2; + } + + @Override + public boolean equals(Object obj) { + if ((obj != null) && (obj instanceof WindowsPath)) { + return compareTo((Path)obj) == 0; + } + return false; + } + + @Override + public int hashCode() { + // OK if two or more threads compute hash + int h = hash; + if (h == 0) { + for (int i = 0; i< path.length(); i++) { + h = 31*h + Character.toUpperCase(path.charAt(i)); + } + hash = h; + } + return h; + } + + @Override + public String toString() { + return path; + } + + @Override + public Iterator<Path> iterator() { + return new Iterator<Path>() { + private int i = 0; + @Override + public boolean hasNext() { + return (i < getNameCount()); + } + @Override + public Path next() { + if (i < getNameCount()) { + Path result = getName(i); + i++; + return result; + } else { + throw new NoSuchElementException(); + } + } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + // -- file operations -- + + // package-private + long openForReadAttributeAccess(boolean followLinks) + throws WindowsException + { + int flags = FILE_FLAG_BACKUP_SEMANTICS; + if (!followLinks && getFileSystem().supportsLinks()) + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + return CreateFile(getPathForWin32Calls(), + FILE_READ_ATTRIBUTES, + (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), + 0L, + OPEN_EXISTING, + flags); + } + + void checkRead() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkRead(getPathForPermissionCheck()); + } + } + + void checkWrite() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkWrite(getPathForPermissionCheck()); + } + } + + void checkDelete() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkDelete(getPathForPermissionCheck()); + } + } + + @Override + public FileStore getFileStore() + throws IOException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); + checkRead(); + } + return WindowsFileStore.create(this); + } + + /** + * Returns buffer with SID_AND_ATTRIBUTES structure representing the user + * associated with the current thread access token. + * FIXME - this should be cached. + */ + private NativeBuffer getUserInfo() throws IOException { + try { + long hToken = WindowsSecurity.processTokenWithQueryAccess; + int size = GetTokenInformation(hToken, TokenUser, 0L, 0); + assert size > 0; + + NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); + try { + int newsize = GetTokenInformation(hToken, TokenUser, + buffer.address(), size); + if (newsize != size) + throw new AssertionError(); + return buffer; + } catch (WindowsException x) { + buffer.release(); + throw x; + } + } catch (WindowsException x) { + throw new IOException(x.getMessage()); + } + } + + /** + * Reads the file ACL and return the effective access as ACCESS_MASK + */ + private int getEffectiveAccess() throws IOException { + // read security descriptor continaing ACL (symlinks are followed) + String target = WindowsLinkSupport.getFinalPath(this, true); + NativeBuffer aclBuffer = WindowsAclFileAttributeView + .getFileSecurity(target, DACL_SECURITY_INFORMATION); + + // retrieves DACL from security descriptor + long pAcl = GetSecurityDescriptorDacl(aclBuffer.address()); + + // Use GetEffectiveRightsFromAcl to get effective access to file + try { + NativeBuffer userBuffer = getUserInfo(); + try { + try { + // SID_AND_ATTRIBUTES->pSid + long pSid = unsafe.getAddress(userBuffer.address()); + long pTrustee = BuildTrusteeWithSid(pSid); + try { + return GetEffectiveRightsFromAcl(pAcl, pTrustee); + } finally { + LocalFree(pTrustee); + } + } catch (WindowsException x) { + throw new IOException("Unable to get effective rights from ACL: " + + x.getMessage()); + } + } finally { + userBuffer.release(); + } + } finally { + aclBuffer.release(); + } + } + + @Override + public void checkAccess(AccessMode... modes) throws IOException { + // if no access modes then simply file attributes + if (modes.length == 0) { + checkRead(); + try { + WindowsFileAttributes.get(this, true); + } catch (WindowsException exc) { + exc.rethrowAsIOException(this); + } + return; + } + + boolean r = false; + boolean w = false; + boolean x = false; + for (AccessMode mode: modes) { + switch (mode) { + case READ : r = true; break; + case WRITE : w = true; break; + case EXECUTE : x = true; break; + default: throw new AssertionError("Should not get here"); + } + } + + int mask = 0; + if (r) { + checkRead(); + mask |= FILE_READ_DATA; + } + if (w) { + checkWrite(); + mask |= FILE_WRITE_DATA; + } + if (x) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkExec(getPathForPermissionCheck()); + mask |= FILE_EXECUTE; + } + + if ((getEffectiveAccess() & mask) == 0) + throw new AccessDeniedException( + this.getPathForExceptionMessage(), null, + "Effective permissions does not allow requested access"); + + // for write access we neeed to check if the DOS readonly attribute + // and if the volume is read-only + if (w) { + try { + WindowsFileAttributes attrs = WindowsFileAttributes.get(this, true); + if (!attrs.isDirectory() && attrs.isReadOnly()) + throw new AccessDeniedException( + this.getPathForExceptionMessage(), null, + "DOS readonly attribute is set"); + } catch (WindowsException exc) { + exc.rethrowAsIOException(this); + } + + if (WindowsFileStore.create(this).isReadOnly()) { + throw new AccessDeniedException( + this.getPathForExceptionMessage(), null, "Read-only file system"); + } + return; + } + } + + @Override + public void delete(boolean failIfNotExists) throws IOException { + checkDelete(); + + WindowsFileAttributes attrs = null; + try { + // need to know if file is a directory or junction + attrs = WindowsFileAttributes.get(this, false); + if (attrs.isDirectory() || attrs.isDirectoryLink()) { + RemoveDirectory(getPathForWin32Calls()); + } else { + DeleteFile(getPathForWin32Calls()); + } + } catch (WindowsException x) { + + // no-op if file does not exist + if (!failIfNotExists && + (x.lastError() == ERROR_FILE_NOT_FOUND || + x.lastError() == ERROR_PATH_NOT_FOUND)) return; + + if (attrs != null && attrs.isDirectory()) { + // ERROR_ALREADY_EXISTS is returned when attempting to delete + // non-empty directory on SAMBA servers. + if (x.lastError() == ERROR_DIR_NOT_EMPTY || + x.lastError() == ERROR_ALREADY_EXISTS) + { + throw new DirectoryNotEmptyException( + getPathForExceptionMessage()); + } + } + x.rethrowAsIOException(this); + } + } + + @Override + public DirectoryStream<Path> newDirectoryStream(DirectoryStream.Filter<? super Path> filter) + throws IOException + { + checkRead(); + if (filter == null) + throw new NullPointerException(); + return new WindowsDirectoryStream(this, filter); + } + + @Override + public void implCopyTo(Path obj, CopyOption... options) throws IOException { + WindowsPath target = (WindowsPath)obj; + WindowsFileCopy.copy(this, target, options); + } + + @Override + public void implMoveTo(Path obj, CopyOption... options) throws IOException { + WindowsPath target = (WindowsPath)obj; + WindowsFileCopy.move(this, target, options); + } + + private boolean followLinks(LinkOption... options) { + boolean followLinks = true; + for (LinkOption option: options) { + if (option == LinkOption.NOFOLLOW_LINKS) { + followLinks = false; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new AssertionError("Should not get here"); + } + return followLinks; + } + + @Override + @SuppressWarnings("unchecked") + public <V extends FileAttributeView> V + getFileAttributeView(Class<V> view, LinkOption... options) + { + if (view == null) + throw new NullPointerException(); + boolean followLinks = followLinks(options); + if (view == BasicFileAttributeView.class) + return (V) WindowsFileAttributeViews.createBasicView(this, followLinks); + if (view == DosFileAttributeView.class) + return (V) WindowsFileAttributeViews.createDosView(this, followLinks); + if (view == AclFileAttributeView.class) + return (V) new WindowsAclFileAttributeView(this, followLinks); + if (view == FileOwnerAttributeView.class) + return (V) new FileOwnerAttributeViewImpl( + new WindowsAclFileAttributeView(this, followLinks)); + if (view == UserDefinedFileAttributeView.class) + return (V) new WindowsUserDefinedFileAttributeView(this, followLinks); + return (V) null; + } + + @Override + public FileAttributeView getFileAttributeView(String name, LinkOption... options) { + boolean followLinks = followLinks(options); + if (name.equals("basic")) + return WindowsFileAttributeViews.createBasicView(this, followLinks); + if (name.equals("dos")) + return WindowsFileAttributeViews.createDosView(this, followLinks); + if (name.equals("acl")) + return new WindowsAclFileAttributeView(this, followLinks); + if (name.equals("owner")) + return new FileOwnerAttributeViewImpl( + new WindowsAclFileAttributeView(this, followLinks)); + if (name.equals("xattr")) + return new WindowsUserDefinedFileAttributeView(this, followLinks); + return null; + } + + @Override + public WindowsPath createDirectory(FileAttribute<?>... attrs) + throws IOException + { + checkWrite(); + WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs); + try { + CreateDirectory(getPathForWin32Calls(), sd.address()); + } catch (WindowsException x) { + x.rethrowAsIOException(this); + } finally { + sd.release(); + } + return this; + } + + @Override + public InputStream newInputStream()throws IOException { + try { + Set<OpenOption> options = Collections.emptySet(); + FileChannel fc = WindowsChannelFactory + .newFileChannel(getPathForWin32Calls(), + getPathForPermissionCheck(), + options, + 0L); + return Channels.newInputStream(fc); + } catch (WindowsException x) { + x.rethrowAsIOException(this); + return null; // keep compiler happy + } + } + + @Override + public SeekableByteChannel newByteChannel(Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + WindowsSecurityDescriptor sd = + WindowsSecurityDescriptor.fromAttribute(attrs); + try { + return WindowsChannelFactory + .newFileChannel(getPathForWin32Calls(), + getPathForPermissionCheck(), + options, + sd.address()); + } catch (WindowsException x) { + x.rethrowAsIOException(this); + return null; // keep compiler happy + } finally { + sd.release(); + } + } + + @Override + public OutputStream newOutputStream(Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + // need to copy options to add WRITE + Set<OpenOption> opts = new HashSet<OpenOption>(options); + if (opts.contains(StandardOpenOption.READ)) + throw new IllegalArgumentException("READ not allowed"); + opts.add(StandardOpenOption.WRITE); + + WindowsSecurityDescriptor sd = + WindowsSecurityDescriptor.fromAttribute(attrs); + FileChannel fc; + try { + fc = WindowsChannelFactory + .newFileChannel(getPathForWin32Calls(), + getPathForPermissionCheck(), + opts, + sd.address()); + return Channels.newOutputStream(fc); + } catch (WindowsException x) { + x.rethrowAsIOException(this); + return null; // keep compiler happy + } finally { + sd.release(); + } + } + + @Override + public boolean isSameFile(FileRef obj) throws IOException { + if (this.equals(obj)) + return true; + if (!(obj instanceof WindowsPath)) // includes null check + return false; + WindowsPath other = (WindowsPath)obj; + + // check security manager access to both files + this.checkRead(); + other.checkRead(); + + // open both files and see if they are the same + long h1 = 0L; + try { + h1 = this.openForReadAttributeAccess(true); + } catch (WindowsException x) { + x.rethrowAsIOException(this); + } + try { + WindowsFileAttributes attrs1 = null; + try { + attrs1 = WindowsFileAttributes.readAttributes(h1); + } catch (WindowsException x) { + x.rethrowAsIOException(this); + } + long h2 = 0L; + try { + h2 = other.openForReadAttributeAccess(true); + } catch (WindowsException x) { + x.rethrowAsIOException(other); + } + try { + WindowsFileAttributes attrs2 = null; + try { + attrs2 = WindowsFileAttributes.readAttributes(h2); + } catch (WindowsException x) { + x.rethrowAsIOException(other); + } + return WindowsFileAttributes.isSameFile(attrs1, attrs2); + } finally { + CloseHandle(h2); + } + } finally { + CloseHandle(h1); + } + } + + @Override + public WindowsPath createSymbolicLink(Path obj, FileAttribute<?>... attrs) + throws IOException + { + if (!getFileSystem().supportsLinks()) { + throw new UnsupportedOperationException("Symbolic links not supported " + + "on this operating system"); + } + + WindowsPath target = checkPath(obj); + + // no attributes allowed + if (attrs.length > 0) { + WindowsSecurityDescriptor.fromAttribute(attrs); // may throw NPE or UOE + throw new UnsupportedOperationException("Initial file attributes" + + "not supported when creating symbolic link"); + } + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new LinkPermission("symbolic")); + this.checkWrite(); + } + + /** + * Throw I/O exception for the drive-relative case because Windows + * creates a link with the resolved target for this case. + */ + if (target.type == WindowsPathType.DRIVE_RELATIVE) { + throw new IOException("Cannot create symbolic link to drive-relative target"); + } + + /* + * Windows treates symbolic links to directories differently than it + * does to other file types. For that reason we check if the exists and + * is a directory. + */ + int flags = 0; + WindowsPath resolvedTarget = + WindowsPath.createFromNormalizedPath(getFileSystem(), resolve(target).path); + try { + if (WindowsFileAttributes.get(resolvedTarget, true).isDirectory()) + flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; + } catch (WindowsException x) { + // unable to access target so assume target is not a directory + } + + // create the link + try { + CreateSymbolicLink(getPathForWin32Calls(), + addPrefixIfNeeded(target.toString()), + flags); + } catch (WindowsException x) { + if (x.lastError() == ERROR_INVALID_REPARSE_DATA) { + x.rethrowAsIOException(this, target); + } else { + x.rethrowAsIOException(this); + } + } + return this; + } + + @Override + public Path createLink(Path obj) throws IOException { + WindowsPath existing = checkPath(obj); + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new LinkPermission("hard")); + this.checkWrite(); + existing.checkWrite(); + } + + // create hard link + try { + CreateHardLink(this.getPathForWin32Calls(), + existing.getPathForWin32Calls()); + } catch (WindowsException x) { + x.rethrowAsIOException(this, existing); + } + + return this; + } + + @Override + public WindowsPath readSymbolicLink() throws IOException { + if (!getFileSystem().supportsLinks()) { + throw new UnsupportedOperationException("symbolic links not supported"); + } + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + FilePermission perm = new FilePermission(getPathForPermissionCheck(), + SecurityConstants.FILE_READLINK_ACTION); + AccessController.checkPermission(perm); + } + + String target = WindowsLinkSupport.readLink(this); + return createFromNormalizedPath(getFileSystem(), target); + } + + @Override + public URI toUri() { + return WindowsUriSupport.toUri(this); + } + + @Override + public WindowsPath toAbsolutePath() { + if (isAbsolute()) + return this; + + // permission check as per spec + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPropertyAccess("user.dir"); + } + + try { + return createFromNormalizedPath(getFileSystem(), getAbsolutePath()); + } catch (WindowsException x) { + throw new IOError(new IOException(x.getMessage())); + } + } + + @Override + public WindowsPath toRealPath(boolean resolveLinks) throws IOException { + checkRead(); + String rp = WindowsLinkSupport.getRealPath(this, resolveLinks); + return createFromNormalizedPath(getFileSystem(), rp); + } + + @Override + public boolean isHidden() throws IOException { + checkRead(); + WindowsFileAttributes attrs = null; + try { + attrs = WindowsFileAttributes.get(this, true); + } catch (WindowsException x) { + x.rethrowAsIOException(this); + } + // DOS hidden attribute not meaningful when set on directories + if (attrs.isDirectory()) + return false; + return attrs.isHidden(); + } + + @Override + public WatchKey register(WatchService watcher, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) + throws IOException + { + if (watcher == null) + throw new NullPointerException(); + if (!(watcher instanceof WindowsWatchService)) + throw new ProviderMismatchException(); + + // When a security manager is set then we need to make a defensive + // copy of the modifiers and check for the Windows specific FILE_TREE + // modifier. When the modifier is present then check that permission + // has been granted recursively. + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + boolean watchSubtree = false; + final int ml = modifiers.length; + if (ml > 0) { + modifiers = Arrays.copyOf(modifiers, ml); + int i=0; + while (i < ml) { + if (modifiers[i++] == ExtendedWatchEventModifier.FILE_TREE) { + watchSubtree = true; + break; + } + } + } + String s = getPathForPermissionCheck(); + sm.checkRead(s); + if (watchSubtree) + sm.checkRead(s + "\\-"); + } + + return ((WindowsWatchService)watcher).register(this, events, modifiers); + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsPathParser.java b/jdk/src/windows/classes/sun/nio/fs/WindowsPathParser.java new file mode 100644 index 00000000000..411b91b1c47 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPathParser.java @@ -0,0 +1,225 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.InvalidPathException; + +/** + * A parser of Windows path strings + */ + +class WindowsPathParser { + private WindowsPathParser() { } + + /** + * The result of a parse operation + */ + static class Result { + private final WindowsPathType type; + private final String root; + private final String path; + + Result(WindowsPathType type, String root, String path) { + this.type = type; + this.root = root; + this.path = path; + } + + /** + * The path type + */ + WindowsPathType type() { + return type; + } + + /** + * The root component + */ + String root() { + return root; + } + + /** + * The normalized path (includes root) + */ + String path() { + return path; + } + } + + /** + * Parses the given input as a Windows path + */ + static Result parse(String input) { + if (input == null || input.length() == 0) + throw new InvalidPathException(input, "Empty or null path"); + return parse(input, true); + } + + /** + * Parses the given input as a Windows path where it is known that the + * path is already normalized. + */ + static Result parseNormalizedPath(String input) { + return parse(input, false); + } + + /** + * Parses the given input as a Windows path. + * + * @param requireToNormalize + * Indicates if the path requires to be normalized + */ + private static Result parse(String input, boolean requireToNormalize) { + String root = ""; + WindowsPathType type = null; + + int len = input.length(); + int off = 0; + if (len > 1) { + char c0 = input.charAt(0); + char c1 = input.charAt(1); + char c = 0; + int next = 2; + if (isSlash(c0) && isSlash(c1)) { + // UNC: We keep the first two slash, collapse all the + // following, then take the hostname and share name out, + // meanwhile collapsing all the redundant slashes. + type = WindowsPathType.UNC; + off = nextNonSlash(input, next, len); + next = nextSlash(input, off, len); + if (off == next) + throw new InvalidPathException(input, "UNC path is missing hostname"); + String host = input.substring(off, next); //host + off = nextNonSlash(input, next, len); + next = nextSlash(input, off, len); + if (off == next) + throw new InvalidPathException(input, "UNC path is missing sharename"); + root = "\\\\" + host + "\\" + input.substring(off, next) + "\\"; + off = next; + } else { + if (isLetter(c0) && c1 == ':') { + root = input.substring(0, 2); + if (len > 2 && isSlash(input.charAt(2))) { + off = 3; + root += "\\"; + type = WindowsPathType.ABSOLUTE; + } else { + off = 2; + type = WindowsPathType.DRIVE_RELATIVE; + } + } + } + } + if (off == 0) { + if (isSlash(input.charAt(0))) { + type = WindowsPathType.DIRECTORY_RELATIVE; + root = "\\"; + } else { + type = WindowsPathType.RELATIVE; + } + } + + if (requireToNormalize) { + StringBuilder sb = new StringBuilder(input.length()); + sb.append(root); + return new Result(type, root, normalize(sb, input, off)); + } else { + return new Result(type, root, input); + } + } + + /** + * Remove redundant slashes from the rest of the path, forcing all slashes + * into the preferred slash. + */ + private static String normalize(StringBuilder sb, String path, int off) { + int len = path.length(); + off = nextNonSlash(path, off, len); + int start = off; + char lastC = 0; + while (off < len) { + char c = path.charAt(off); + if (isSlash(c)) { + if (lastC == ' ') + throw new InvalidPathException(path, + "Trailing char <" + lastC + ">", + off - 1); + sb.append(path, start, off); + off = nextNonSlash(path, off, len); + if (off != len) //no slash at the end of normalized path + sb.append('\\'); + start = off; + } else { + if (isInvalidPathChar(c)) + throw new InvalidPathException(path, + "Illegal char <" + c + ">", + off); + lastC = c; + off++; + } + } + if (start != off) { + if (lastC == ' ') + throw new InvalidPathException(path, + "Trailing char <" + lastC + ">", + off - 1); + sb.append(path, start, off); + } + return sb.toString(); + } + + private static final boolean isSlash(char c) { + return (c == '\\') || (c == '/'); + } + + private static final int nextNonSlash(String path, int off, int end) { + while (off < end && isSlash(path.charAt(off))) { off++; } + return off; + } + + private static final int nextSlash(String path, int off, int end) { + char c; + while (off < end && !isSlash(c=path.charAt(off))) { + if (isInvalidPathChar(c)) + throw new InvalidPathException(path, + "Illegal character [" + c + "] in path", + off); + off++; + } + return off; + } + + private static final boolean isLetter(char c) { + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); + } + + // Reserved characters for window path name + private static final String reservedChars = "<>:\"|?*"; + private static final boolean isInvalidPathChar(char ch) { + return ch < '\u0020' || reservedChars.indexOf(ch) != -1; + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsPathType.java b/jdk/src/windows/classes/sun/nio/fs/WindowsPathType.java new file mode 100644 index 00000000000..ae3651f1f2d --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPathType.java @@ -0,0 +1,38 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +/** + * A type safe enum of Windows path types. + */ + +enum WindowsPathType { + ABSOLUTE, // C:\foo + UNC, // \\server\share\foo + RELATIVE, // foo + DIRECTORY_RELATIVE, // \foo + DRIVE_RELATIVE // C:foo +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java new file mode 100644 index 00000000000..9d44257b5ad --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java @@ -0,0 +1,123 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * Security related utility methods. + */ + +class WindowsSecurity { + private WindowsSecurity() { } + + // opens process token for given access + private static long openProcessToken(int access) { + try { + return OpenProcessToken(GetCurrentProcess(), access); + } catch (WindowsException x) { + return 0L; + } + } + + /** + * Returns the access token for this process with TOKEN_DUPLICATE access + */ + static final long processTokenWithDuplicateAccess = + openProcessToken(TOKEN_DUPLICATE); + + /** + * Returns the access token for this process with TOKEN_QUERY access + */ + static final long processTokenWithQueryAccess = + openProcessToken(TOKEN_QUERY); + + /** + * Returned by enablePrivilege when code may require a given privilege. + * The drop method should be invoked after the operation completes so as + * to revert the privilege. + */ + static interface Privilege { + void drop(); + } + + /** + * Attempts to enable the given privilege for this method. + */ + static Privilege enablePrivilege(String priv) { + final long pLuid; + try { + pLuid = LookupPrivilegeValue(priv); + } catch (WindowsException x) { + // indicates bug in caller + throw new AssertionError(x); + } + + long hToken = 0L; + boolean impersontating = false; + boolean elevated = false; + try { + hToken = OpenThreadToken(GetCurrentThread(), + TOKEN_ADJUST_PRIVILEGES, false); + if (hToken == 0L && processTokenWithDuplicateAccess != 0L) { + hToken = DuplicateTokenEx(processTokenWithDuplicateAccess, + (TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE)); + SetThreadToken(0L, hToken); + impersontating = true; + } + + if (hToken != 0L) { + AdjustTokenPrivileges(hToken, pLuid, SE_PRIVILEGE_ENABLED); + elevated = true; + } + } catch (WindowsException x) { + // nothing to do, privilege not enabled + } + + final long token = hToken; + final boolean stopImpersontating = impersontating; + final boolean needToRevert = elevated; + + return new Privilege() { + @Override + public void drop() { + try { + if (stopImpersontating) { + SetThreadToken(0L, 0L); + } else { + if (needToRevert) { + AdjustTokenPrivileges(token, pLuid, 0); + } + } + } catch (WindowsException x) { + // should not happen + throw new AssertionError(x); + } + } + }; + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java new file mode 100644 index 00000000000..0fa0725c5db --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java @@ -0,0 +1,392 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.ProviderMismatchException; +import java.nio.file.attribute.*; +import java.util.*; +import java.io.IOException; +import sun.misc.Unsafe; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * A SecurityDescriptor for use when setting a file's ACL or creating a file + * with an initial ACL. + */ + +class WindowsSecurityDescriptor { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + /** + * typedef struct _ACL { + * BYTE AclRevision; + * BYTE Sbz1; + * WORD AclSize; + * WORD AceCount; + * WORD Sbz2; + * } ACL; + * + * typedef struct _ACE_HEADER { + * BYTE AceType; + * BYTE AceFlags; + * WORD AceSize; + * } ACE_HEADER; + * + * typedef struct _ACCESS_ALLOWED_ACE { + * ACE_HEADER Header; + * ACCESS_MASK Mask; + * DWORD SidStart; + * } ACCESS_ALLOWED_ACE; + * + * typedef struct _ACCESS_DENIED_ACE { + * ACE_HEADER Header; + * ACCESS_MASK Mask; + * DWORD SidStart; + * } ACCESS_DENIED_ACE; + * + * typedef struct _SECURITY_DESCRIPTOR { + * BYTE Revision; + * BYTE Sbz1; + * SECURITY_DESCRIPTOR_CONTROL Control; + * PSID Owner; + * PSID Group; + * PACL Sacl; + * PACL Dacl; + * } SECURITY_DESCRIPTOR; + */ + private static final short SIZEOF_ACL = 8; + private static final short SIZEOF_ACCESS_ALLOWED_ACE = 12; + private static final short SIZEOF_ACCESS_DENIED_ACE = 12; + private static final short SIZEOF_SECURITY_DESCRIPTOR = 20; + + private static final short OFFSETOF_TYPE = 0; + private static final short OFFSETOF_FLAGS = 1; + private static final short OFFSETOF_ACCESS_MASK = 4; + private static final short OFFSETOF_SID = 8; + + // null security descriptor + private static final WindowsSecurityDescriptor NULL_DESCRIPTOR = + new WindowsSecurityDescriptor(); + + // native resources + private final List<Long> sidList; + private final NativeBuffer aclBuffer, sdBuffer; + + /** + * Creates the "null" SecurityDescriptor + */ + private WindowsSecurityDescriptor() { + this.sidList = null; + this.aclBuffer = null; + this.sdBuffer = null; + } + + /** + * Creates a SecurityDescriptor from the given ACL + */ + private WindowsSecurityDescriptor(List<AclEntry> acl) throws IOException { + boolean initialized = false; + + // SECURITY: need to copy list in case size changes during processing + acl = new ArrayList<AclEntry>(acl); + + // list of SIDs + sidList = new ArrayList<Long>(acl.size()); + try { + // initial size of ACL + int size = SIZEOF_ACL; + + // get the SID for each entry + for (AclEntry entry: acl) { + UserPrincipal user = entry.principal(); + if (!(user instanceof WindowsUserPrincipals.User)) + throw new ProviderMismatchException(); + String sidString = ((WindowsUserPrincipals.User)user).sidString(); + try { + long pSid = ConvertStringSidToSid(sidString); + sidList.add(pSid); + + // increase size to allow for entry + size += GetLengthSid(pSid) + + Math.max(SIZEOF_ACCESS_ALLOWED_ACE, SIZEOF_ACCESS_DENIED_ACE); + + } catch (WindowsException x) { + throw new IOException("Failed to get SID for " + user.getName() + + ": " + x.errorString()); + } + } + + // allocate memory for the ACL + aclBuffer = NativeBuffers.getNativeBuffer(size); + sdBuffer = NativeBuffers.getNativeBuffer(SIZEOF_SECURITY_DESCRIPTOR); + + InitializeAcl(aclBuffer.address(), size); + + // Add entry ACE to the ACL + int i = 0; + while (i < acl.size()) { + AclEntry entry = acl.get(i); + long pSid = sidList.get(i); + try { + encode(entry, pSid, aclBuffer.address()); + } catch (WindowsException x) { + throw new IOException("Failed to encode ACE: " + + x.errorString()); + } + i++; + } + + // initialize security descriptor and set DACL + InitializeSecurityDescriptor(sdBuffer.address()); + SetSecurityDescriptorDacl(sdBuffer.address(), aclBuffer.address()); + initialized = true; + } catch (WindowsException x) { + throw new IOException(x.getMessage()); + } finally { + // release resources if not completely initialized + if (!initialized) + release(); + } + } + + /** + * Releases memory associated with SecurityDescriptor + */ + void release() { + if (sdBuffer != null) + sdBuffer.release(); + if (aclBuffer != null) + aclBuffer.release(); + if (sidList != null) { + // release memory for SIDs + for (Long sid: sidList) { + LocalFree(sid); + } + } + } + + /** + * Returns address of SecurityDescriptor + */ + long address() { + return (sdBuffer == null) ? 0L : sdBuffer.address(); + } + + // decode Windows ACE to NFSv4 AclEntry + private static AclEntry decode(long aceAddress) + throws IOException + { + // map type + byte aceType = unsafe.getByte(aceAddress + OFFSETOF_TYPE); + if (aceType != ACCESS_ALLOWED_ACE_TYPE && aceType != ACCESS_DENIED_ACE_TYPE) + return null; + AclEntryType type; + if (aceType == ACCESS_ALLOWED_ACE_TYPE) { + type = AclEntryType.ALLOW; + } else { + type = AclEntryType.DENY; + } + + // map flags + byte aceFlags = unsafe.getByte(aceAddress + OFFSETOF_FLAGS); + Set<AclEntryFlag> flags = new HashSet<AclEntryFlag>(); + if ((aceFlags & OBJECT_INHERIT_ACE) != 0) + flags.add(AclEntryFlag.FILE_INHERIT); + if ((aceFlags & CONTAINER_INHERIT_ACE) != 0) + flags.add(AclEntryFlag.DIRECTORY_INHERIT); + if ((aceFlags & NO_PROPAGATE_INHERIT_ACE) != 0) + flags.add(AclEntryFlag.NO_PROPAGATE_INHERIT); + if ((aceFlags & INHERIT_ONLY_ACE) != 0) + flags.add(AclEntryFlag.INHERIT_ONLY); + + // map access mask + int mask = unsafe.getInt(aceAddress + OFFSETOF_ACCESS_MASK); + Set<AclEntryPermission> perms = new HashSet<AclEntryPermission>(); + if ((mask & FILE_READ_DATA) > 0) + perms.add(AclEntryPermission.READ_DATA); + if ((mask & FILE_WRITE_DATA) > 0) + perms.add(AclEntryPermission.WRITE_DATA); + if ((mask & FILE_APPEND_DATA ) > 0) + perms.add(AclEntryPermission.APPEND_DATA); + if ((mask & FILE_READ_EA) > 0) + perms.add(AclEntryPermission.READ_NAMED_ATTRS); + if ((mask & FILE_WRITE_EA) > 0) + perms.add(AclEntryPermission.WRITE_NAMED_ATTRS); + if ((mask & FILE_EXECUTE) > 0) + perms.add(AclEntryPermission.EXECUTE); + if ((mask & FILE_DELETE_CHILD ) > 0) + perms.add(AclEntryPermission.DELETE_CHILD); + if ((mask & FILE_READ_ATTRIBUTES) > 0) + perms.add(AclEntryPermission.READ_ATTRIBUTES); + if ((mask & FILE_WRITE_ATTRIBUTES) > 0) + perms.add(AclEntryPermission.WRITE_ATTRIBUTES); + if ((mask & DELETE) > 0) + perms.add(AclEntryPermission.DELETE); + if ((mask & READ_CONTROL) > 0) + perms.add(AclEntryPermission.READ_ACL); + if ((mask & WRITE_DAC) > 0) + perms.add(AclEntryPermission.WRITE_ACL); + if ((mask & WRITE_OWNER) > 0) + perms.add(AclEntryPermission.WRITE_OWNER); + if ((mask & SYNCHRONIZE) > 0) + perms.add(AclEntryPermission.SYNCHRONIZE); + + // lookup SID to create UserPrincipal + long sidAddress = aceAddress + OFFSETOF_SID; + UserPrincipal user = WindowsUserPrincipals.fromSid(sidAddress); + + return AclEntry.newBuilder() + .setType(type) + .setPrincipal(user) + .setFlags(flags).setPermissions(perms).build(); + } + + // encode NFSv4 AclEntry as Windows ACE to given ACL + private static void encode(AclEntry ace, long sidAddress, long aclAddress) + throws WindowsException + { + // ignore non-allow/deny entries for now + if (ace.type() != AclEntryType.ALLOW && ace.type() != AclEntryType.DENY) + return; + boolean allow = (ace.type() == AclEntryType.ALLOW); + + // map access mask + Set<AclEntryPermission> aceMask = ace.permissions(); + int mask = 0; + if (aceMask.contains(AclEntryPermission.READ_DATA)) + mask |= FILE_READ_DATA; + if (aceMask.contains(AclEntryPermission.WRITE_DATA)) + mask |= FILE_WRITE_DATA; + if (aceMask.contains(AclEntryPermission.APPEND_DATA)) + mask |= FILE_APPEND_DATA; + if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS)) + mask |= FILE_READ_EA; + if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS)) + mask |= FILE_WRITE_EA; + if (aceMask.contains(AclEntryPermission.EXECUTE)) + mask |= FILE_EXECUTE; + if (aceMask.contains(AclEntryPermission.DELETE_CHILD)) + mask |= FILE_DELETE_CHILD; + if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES)) + mask |= FILE_READ_ATTRIBUTES; + if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES)) + mask |= FILE_WRITE_ATTRIBUTES; + if (aceMask.contains(AclEntryPermission.DELETE)) + mask |= DELETE; + if (aceMask.contains(AclEntryPermission.READ_ACL)) + mask |= READ_CONTROL; + if (aceMask.contains(AclEntryPermission.WRITE_ACL)) + mask |= WRITE_DAC; + if (aceMask.contains(AclEntryPermission.WRITE_OWNER)) + mask |= WRITE_OWNER; + if (aceMask.contains(AclEntryPermission.SYNCHRONIZE)) + mask |= SYNCHRONIZE; + + // map flags + Set<AclEntryFlag> aceFlags = ace.flags(); + byte flags = 0; + if (aceFlags.contains(AclEntryFlag.FILE_INHERIT)) + flags |= OBJECT_INHERIT_ACE; + if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT)) + flags |= CONTAINER_INHERIT_ACE; + if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT)) + flags |= NO_PROPAGATE_INHERIT_ACE; + if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY)) + flags |= INHERIT_ONLY_ACE; + + if (allow) { + AddAccessAllowedAceEx(aclAddress, flags, mask, sidAddress); + } else { + AddAccessDeniedAceEx(aclAddress, flags, mask, sidAddress); + } + } + + /** + * Creates a security descriptor with a DACL representing the given ACL. + */ + static WindowsSecurityDescriptor create(List<AclEntry> acl) + throws IOException + { + return new WindowsSecurityDescriptor(acl); + } + + /** + * Processes the array of attributes looking for the attribute "acl:acl". + * Returns security descriptor representing the ACL or the "null" security + * descriptor if the attribute is not in the array. + */ + @SuppressWarnings("unchecked") + static WindowsSecurityDescriptor fromAttribute(FileAttribute<?>... attrs) + throws IOException + { + WindowsSecurityDescriptor sd = NULL_DESCRIPTOR; + for (FileAttribute<?> attr: attrs) { + // if more than one ACL specified then last one wins + if (sd != NULL_DESCRIPTOR) + sd.release(); + if (attr == null) + throw new NullPointerException(); + if (attr.name().equals("acl:acl")) { + List<AclEntry> acl = (List<AclEntry>)attr.value(); + sd = new WindowsSecurityDescriptor(acl); + } else { + throw new UnsupportedOperationException("'" + attr.name() + + "' not supported as initial attribute"); + } + } + return sd; + } + + /** + * Extracts DACL from security descriptor. + */ + static List<AclEntry> getAcl(long pSecurityDescriptor) throws IOException { + // get address of DACL + long aclAddress = GetSecurityDescriptorDacl(pSecurityDescriptor); + + // get ACE count + int aceCount = 0; + if (aclAddress == 0L) { + // no ACEs + aceCount = 0; + } else { + AclInformation aclInfo = GetAclInformation(aclAddress); + aceCount = aclInfo.aceCount(); + } + ArrayList<AclEntry> result = new ArrayList<AclEntry>(aceCount); + + // decode each of the ACEs to AclEntry objects + for (int i=0; i<aceCount; i++) { + long aceAddress = GetAce(aclAddress, i); + AclEntry entry = decode(aceAddress); + if (entry != null) + result.add(entry); + } + return result; + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsUriSupport.java b/jdk/src/windows/classes/sun/nio/fs/WindowsUriSupport.java new file mode 100644 index 00000000000..d87ba82b732 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsUriSupport.java @@ -0,0 +1,167 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.net.URI; +import java.net.URISyntaxException; + +/** + * Utility methods to convert between Path and URIs. + */ + +class WindowsUriSupport { + private WindowsUriSupport() { + } + + // suffix for IPv6 literal address + private static final String IPV6_LITERAL_SUFFIX = ".ipv6-literal.net"; + + /** + * Returns URI to represent the given (absolute) path + */ + private static URI toUri(String path, boolean isUnc, boolean addSlash) { + String uriHost; + String uriPath; + + if (isUnc) { + int slash = path.indexOf('\\', 2); + uriHost = path.substring(2, slash); + uriPath = path.substring(slash).replace('\\', '/'); + + // handle IPv6 literal addresses + // 1. drop .ivp6-literal.net + // 2. replace "-" with ":" + // 3. replace "s" with "%" (zone/scopeID delimiter) + if (uriHost.endsWith(IPV6_LITERAL_SUFFIX)) { + uriHost = uriHost + .substring(0, uriHost.length() - IPV6_LITERAL_SUFFIX.length()) + .replace('-', ':') + .replace('s', '%'); + } + } else { + uriHost = ""; + uriPath = "/" + path.replace('\\', '/'); + } + + // append slash if known to be directory + if (addSlash) + uriPath += "/"; + + // return file:///C:/My%20Documents or file://server/share/foo + try { + return new URI("file", uriHost, uriPath, null); + } catch (URISyntaxException x) { + if (!isUnc) + throw new AssertionError(x); + } + + // if we get here it means we've got a UNC with reserved characters + // in the server name. The authority component cannot contain escaped + // octets so fallback to encoding the server name into the URI path + // component. + uriPath = "//" + path.replace('\\', '/'); + if (addSlash) + uriPath += "/"; + try { + return new URI("file", null, uriPath, null); + } catch (URISyntaxException x) { + throw new AssertionError(x); + } + } + + /** + * Converts given Path to a URI + */ + static URI toUri(WindowsPath path) { + path = path.toAbsolutePath(); + String s = path.toString(); + + // trailing slash will be added if file is a directory. Skip check if + // already have trailing space + boolean addSlash = false; + if (!s.endsWith("\\")) { + try { + addSlash = WindowsFileAttributes.get(path, true).isDirectory(); + } catch (WindowsException x) { + } + } + + return toUri(s, path.isUnc(), addSlash); + } + + /** + * Converts given URI to a Path + */ + static WindowsPath fromUri(WindowsFileSystem fs, URI uri) { + if (!uri.isAbsolute()) + throw new IllegalArgumentException("URI is not absolute"); + if (uri.isOpaque()) + throw new IllegalArgumentException("URI is not hierarchical"); + String scheme = uri.getScheme(); + if ((scheme == null) || !scheme.equalsIgnoreCase("file")) + throw new IllegalArgumentException("URI scheme is not \"file\""); + if (uri.getFragment() != null) + throw new IllegalArgumentException("URI has a fragment component"); + if (uri.getQuery() != null) + throw new IllegalArgumentException("URI has a query component"); + String path = uri.getPath(); + if (path.equals("")) + throw new IllegalArgumentException("URI path component is empty"); + + // UNC + String auth = uri.getAuthority(); + if (auth != null && !auth.equals("")) { + String host = uri.getHost(); + if (host == null) + throw new IllegalArgumentException("URI authority component has undefined host"); + if (uri.getUserInfo() != null) + throw new IllegalArgumentException("URI authority component has user-info"); + if (uri.getPort() != -1) + throw new IllegalArgumentException("URI authority component has port number"); + + // IPv6 literal + // 1. drop enclosing brackets + // 2. replace ":" with "-" + // 3. replace "%" with "s" (zone/scopeID delimiter) + // 4. Append .ivp6-literal.net + if (host.startsWith("[")) { + host = host.substring(1, host.length()-1) + .replace(':', '-') + .replace('%', 's'); + host += IPV6_LITERAL_SUFFIX; + } + + // reconstitute the UNC + path = "\\\\" + host + path; + } else { + if ((path.length() > 2) && (path.charAt(2) == ':')) { + // "/c:/foo" --> "c:/foo" + path = path.substring(1); + } + } + return WindowsPath.parse(fs, path); + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java b/jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java new file mode 100644 index 00000000000..db361c97e0d --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java @@ -0,0 +1,342 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import static java.nio.file.StandardOpenOption.*; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.io.IOException; +import java.util.*; +import sun.misc.Unsafe; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/** + * Windows emulation of NamedAttributeView using Alternative Data Streams + */ + +class WindowsUserDefinedFileAttributeView + extends AbstractUserDefinedFileAttributeView +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // syntax to address named streams + private String join(String file, String name) { + if (name == null) + throw new NullPointerException("'name' is null"); + return file + ":" + name; + } + private String join(WindowsPath file, String name) throws WindowsException { + return join(file.getPathForWin32Calls(), name); + } + + private final WindowsPath file; + private final boolean followLinks; + + WindowsUserDefinedFileAttributeView(WindowsPath file, boolean followLinks) { + this.file = file; + this.followLinks = followLinks; + } + + // enumerates the file streams using FindFirstStream/FindNextStream APIs. + private List<String> listUsingStreamEnumeration() throws IOException { + List<String> list = new ArrayList<String>(); + try { + FirstStream first = FindFirstStream(file.getPathForWin32Calls()); + if (first != null) { + long handle = first.handle(); + try { + // first stream is always ::$DATA for files + String name = first.name(); + if (!name.equals("::$DATA")) { + String[] segs = name.split(":"); + list.add(segs[1]); + } + while ((name = FindNextStream(handle)) != null) { + String[] segs = name.split(":"); + list.add(segs[1]); + } + } finally { + FindClose(handle); + } + } + } catch (WindowsException x) { + x.rethrowAsIOException(file); + } + return Collections.unmodifiableList(list); + } + + // enumerates the file streams by reading the stream headers using + // BackupRead + private List<String> listUsingBackupRead() throws IOException { + long handle = -1L; + try { + int flags = FILE_FLAG_BACKUP_SEMANTICS; + if (!followLinks && file.getFileSystem().supportsLinks()) + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + + handle = CreateFile(file.getPathForWin32Calls(), + GENERIC_READ, + FILE_SHARE_READ, // no write as we depend on file size + OPEN_EXISTING, + flags); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + } + + // buffer to read stream header and stream name. + final int BUFFER_SIZE = 4096; + NativeBuffer buffer = null; + + // result with names of alternative data streams + final List<String> list = new ArrayList<String>(); + + try { + buffer = NativeBuffers.getNativeBuffer(BUFFER_SIZE); + long address = buffer.address(); + + /** + * typedef struct _WIN32_STREAM_ID { + * DWORD dwStreamId; + * DWORD dwStreamAttributes; + * LARGE_INTEGER Size; + * DWORD dwStreamNameSize; + * WCHAR cStreamName[ANYSIZE_ARRAY]; + * } WIN32_STREAM_ID; + */ + final int SIZEOF_STREAM_HEADER = 20; + final int OFFSETOF_STREAM_ID = 0; + final int OFFSETOF_STREAM_SIZE = 8; + final int OFFSETOF_STREAM_NAME_SIZE = 16; + + long context = 0L; + try { + for (;;) { + // read stream header + BackupResult result = BackupRead(handle, address, + SIZEOF_STREAM_HEADER, false, context); + context = result.context(); + if (result.bytesTransferred() == 0) + break; + + int streamId = unsafe.getInt(address + OFFSETOF_STREAM_ID); + long streamSize = unsafe.getLong(address + OFFSETOF_STREAM_SIZE); + int nameSize = unsafe.getInt(address + OFFSETOF_STREAM_NAME_SIZE); + + // read stream name + if (nameSize > 0) { + result = BackupRead(handle, address, nameSize, false, context); + if (result.bytesTransferred() != nameSize) + break; + } + + // check for alternative data stream + if (streamId == BACKUP_ALTERNATE_DATA) { + char[] nameAsArray = new char[nameSize/2]; + unsafe.copyMemory(null, address, nameAsArray, + Unsafe.ARRAY_CHAR_BASE_OFFSET, nameSize); + + String[] segs = new String(nameAsArray).split(":"); + if (segs.length == 3) + list.add(segs[1]); + } + + // sparse blocks not currently handled as documentation + // is not sufficient on how the spase block can be skipped. + if (streamId == BACKUP_SPARSE_BLOCK) { + throw new IOException("Spare blocks not handled"); + } + + // seek to end of stream + if (streamSize > 0L) { + BackupSeek(handle, streamSize, context); + } + } + } catch (WindowsException x) { + // failed to read or seek + throw new IOException(x.errorString()); + } finally { + // release context + if (context != 0L) { + try { + BackupRead(handle, 0L, 0, true, context); + } catch (WindowsException ignore) { } + } + } + } finally { + if (buffer != null) + buffer.release(); + CloseHandle(handle); + } + return Collections.unmodifiableList(list); + } + + @Override + public List<String> list() throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + // use stream APIs on Windwos Server 2003 and newer + if (file.getFileSystem().supportsStreamEnumeration()) { + return listUsingStreamEnumeration(); + } else { + return listUsingBackupRead(); + } + } + + @Override + public int size(String name) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + // wrap with channel + FileChannel fc = null; + try { + Set<OpenOption> opts = new HashSet<OpenOption>(); + opts.add(READ); + if (!followLinks) + opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT); + fc = WindowsChannelFactory + .newFileChannel(join(file, name), null, opts, 0L); + } catch (WindowsException x) { + x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name)); + } + try { + long size = fc.size(); + if (size > Integer.MAX_VALUE) + throw new ArithmeticException("Stream too large"); + return (int)size; + } finally { + fc.close(); + } + } + + @Override + public int read(String name, ByteBuffer dst) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), true, false); + + // wrap with channel + FileChannel fc = null; + try { + Set<OpenOption> opts = new HashSet<OpenOption>(); + opts.add(READ); + if (!followLinks) + opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT); + fc = WindowsChannelFactory + .newFileChannel(join(file, name), null, opts, 0L); + } catch (WindowsException x) { + x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name)); + } + + // read to EOF (nothing we can do if I/O error occurs) + try { + if (fc.size() > dst.remaining()) + throw new IOException("Stream too large"); + int total = 0; + while (dst.hasRemaining()) { + int n = fc.read(dst); + if (n < 0) + break; + total += n; + } + return total; + } finally { + fc.close(); + } + } + + @Override + public int write(String name, ByteBuffer src) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), false, true); + + /** + * Creating a named stream will cause the unnamed stream to be created + * if it doesn't already exist. To avoid this we open the unnamed stream + * for reading and hope it isn't deleted/moved while we create or + * replace the named stream. Opening the file without sharing options + * may cause sharing violations with other programs that are accessing + * the unnamed stream. + */ + long handle = -1L; + try { + int flags = FILE_FLAG_BACKUP_SEMANTICS; + if (!followLinks) + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + + handle = CreateFile(file.getPathForWin32Calls(), + GENERIC_READ, + (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), + OPEN_EXISTING, + flags); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + } + try { + Set<OpenOption> opts = new HashSet<OpenOption>(); + if (!followLinks) + opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT); + opts.add(CREATE); + opts.add(WRITE); + opts.add(StandardOpenOption.TRUNCATE_EXISTING); + FileChannel named = null; + try { + named = WindowsChannelFactory + .newFileChannel(join(file, name), null, opts, 0L); + } catch (WindowsException x) { + x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name)); + } + // write value (nothing we can do if I/O error occurs) + try { + int rem = src.remaining(); + while (src.hasRemaining()) { + named.write(src); + } + return rem; + } finally { + named.close(); + } + } finally { + CloseHandle(handle); + } + } + + @Override + public void delete(String name) throws IOException { + if (System.getSecurityManager() != null) + checkAccess(file.getPathForPermissionCheck(), false, true); + + String path = WindowsLinkSupport.getFinalPath(file, followLinks); + String toDelete = join(path, name); + try { + DeleteFile(toDelete); + } catch (WindowsException x) { + x.rethrowAsIOException(toDelete); + } + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsUserPrincipals.java b/jdk/src/windows/classes/sun/nio/fs/WindowsUserPrincipals.java new file mode 100644 index 00000000000..caf36f17c12 --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsUserPrincipals.java @@ -0,0 +1,169 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.io.IOException; + +import static sun.nio.fs.WindowsConstants.*; +import static sun.nio.fs.WindowsNativeDispatcher.*; + +class WindowsUserPrincipals { + private WindowsUserPrincipals() { } + + static class User implements UserPrincipal { + // String representation of SID + private final String sidString; + + // SID type + private final int sidType; + + // Account name (if available) or SID + private final String accountName; + + User(String sidString, int sidType, String accountName) { + this.sidString = sidString; + this.sidType = sidType; + this.accountName = accountName; + } + + // package-private + String sidString() { + return sidString; + } + + @Override + public String getName() { + return accountName; + } + + @Override + public String toString() { + String type; + switch (sidType) { + case SidTypeUser : type = "User"; break; + case SidTypeGroup : type = "Group"; break; + case SidTypeDomain : type = "Domain"; break; + case SidTypeAlias : type = "Alias"; break; + case SidTypeWellKnownGroup : type = "Well-known group"; break; + case SidTypeDeletedAccount : type = "Deleted"; break; + case SidTypeInvalid : type = "Invalid"; break; + case SidTypeComputer : type = "Computer"; break; + default: type = "Unknown"; + } + return accountName + " (" + type + ")"; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (!(obj instanceof WindowsUserPrincipals.User)) + return false; + WindowsUserPrincipals.User other = (WindowsUserPrincipals.User)obj; + return this.sidString.equals(other.sidString); + } + + @Override + public int hashCode() { + return sidString.hashCode(); + } + } + + static class Group extends User implements GroupPrincipal { + Group(String sidString, int sidType, String accountName) { + super(sidString, sidType, accountName); + } + } + + static UserPrincipal fromSid(long sidAddress) throws IOException { + String sidString; + try { + sidString = ConvertSidToStringSid(sidAddress); + if (sidString == null) { + // pre-Windows XP system? + throw new AssertionError(); + } + } catch (WindowsException x) { + throw new IOException("Unable to convert SID to String: " + + x.errorString()); + } + + // lookup account; if not available then use the SID as the name + Account account = null; + String name; + try { + account = LookupAccountSid(sidAddress); + name = account.domain() + "\\" + account.name(); + } catch (WindowsException x) { + name = sidString; + } + + int sidType = (account == null) ? SidTypeUnknown : account.use(); + if ((sidType == SidTypeGroup) || + (sidType == SidTypeWellKnownGroup) || + (sidType == SidTypeAlias)) // alias for local group + { + return new Group(sidString, sidType, name); + } else { + return new User(sidString, sidType, name); + } + } + + static UserPrincipal lookup(String name) throws IOException { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("lookupUserInformation")); + } + + // invoke LookupAccountName to get buffer size needed for SID + int size = 0; + try { + size = LookupAccountName(name, 0L, 0); + } catch (WindowsException x) { + if (x.lastError() == ERROR_NONE_MAPPED) + throw new UserPrincipalNotFoundException(name); + throw new IOException(name + ": " + x.errorString()); + } + assert size > 0; + + // allocate buffer and re-invoke LookupAccountName get SID + NativeBuffer sidBuffer = NativeBuffers.getNativeBuffer(size); + try { + int newSize = LookupAccountName(name, sidBuffer.address(), size); + if (newSize != size) { + // can this happen? + throw new AssertionError("SID change during lookup"); + } + + // return user principal + return fromSid(sidBuffer.address()); + } catch (WindowsException x) { + throw new IOException(name + ": " + x.errorString()); + } finally { + sidBuffer.release(); + } + } +} diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java b/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java new file mode 100644 index 00000000000..6a5190784dc --- /dev/null +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java @@ -0,0 +1,582 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.io.IOException; +import java.util.*; +import com.sun.nio.file.ExtendedWatchEventModifier; +import sun.misc.Unsafe; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; + +/* + * Win32 implementation of WatchService based on ReadDirectoryChangesW. + */ + +class WindowsWatchService + extends AbstractWatchService +{ + private final Unsafe unsafe = Unsafe.getUnsafe(); + + // background thread to service I/O completion port + private final Poller poller; + + /** + * Creates an I/O completion port and a daemon thread to service it + */ + WindowsWatchService(WindowsFileSystem fs) throws IOException { + // create I/O completion port + long port = 0L; + try { + port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0); + } catch (WindowsException x) { + throw new IOException(x.getMessage()); + } + + this.poller = new Poller(fs, this, port); + this.poller.start(); + } + + @Override + WatchKey register(Path path, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) + throws IOException + { + // delegate to poller + return poller.register(path, events, modifiers); + } + + @Override + void implClose() throws IOException { + // delegate to poller + poller.close(); + } + + /** + * Windows implementation of WatchKey. + */ + private class WindowsWatchKey extends AbstractWatchKey { + // file key (used to detect existing registrations) + private FileKey fileKey; + + // handle to directory + private volatile long handle = INVALID_HANDLE_VALUE; + + // interest events + private Set<? extends WatchEvent.Kind<?>> events; + + // subtree + private boolean watchSubtree; + + // buffer for change events + private NativeBuffer buffer; + + // pointer to bytes returned (in buffer) + private long countAddress; + + // pointer to overlapped structure (in buffer) + private long overlappedAddress; + + // completion key (used to map I/O completion to WatchKey) + private int completionKey; + + WindowsWatchKey(AbstractWatchService watcher, FileKey fileKey) { + super(watcher); + this.fileKey = fileKey; + } + + WindowsWatchKey init(long handle, + Set<? extends WatchEvent.Kind<?>> events, + boolean watchSubtree, + NativeBuffer buffer, + long countAddress, + long overlappedAddress, + int completionKey) + { + this.handle = handle; + this.events = events; + this.watchSubtree = watchSubtree; + this.buffer = buffer; + this.countAddress = countAddress; + this.overlappedAddress = overlappedAddress; + this.completionKey = completionKey; + return this; + } + + long handle() { + return handle; + } + + Set<? extends WatchEvent.Kind<?>> events() { + return events; + } + + void setEvents(Set<? extends WatchEvent.Kind<?>> events) { + this.events = events; + } + + boolean watchSubtree() { + return watchSubtree; + } + + NativeBuffer buffer() { + return buffer; + } + + long countAddress() { + return countAddress; + } + + long overlappedAddress() { + return overlappedAddress; + } + + FileKey fileKey() { + return fileKey; + } + + int completionKey() { + return completionKey; + } + + // close directory and release buffer + void releaseResources() { + CloseHandle(handle); + buffer.cleaner().clean(); + } + + // Invalidate key by closing directory and releasing buffer + void invalidate() { + releaseResources(); + handle = INVALID_HANDLE_VALUE; + buffer = null; + countAddress = 0; + overlappedAddress = 0; + } + + @Override + public boolean isValid() { + return handle != INVALID_HANDLE_VALUE; + } + + @Override + public void cancel() { + if (isValid()) { + // delegate to poller + poller.cancel(this); + } + } + } + + // file key to unique identify (open) directory + private static class FileKey { + private final int volSerialNumber; + private final int fileIndexHigh; + private final int fileIndexLow; + + FileKey(int volSerialNumber, int fileIndexHigh, int fileIndexLow) { + this.volSerialNumber = volSerialNumber; + this.fileIndexHigh = fileIndexHigh; + this.fileIndexLow = fileIndexLow; + } + + @Override + public int hashCode() { + return volSerialNumber ^ fileIndexHigh ^ fileIndexLow; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (!(obj instanceof FileKey)) + return false; + FileKey other = (FileKey)obj; + if (this.volSerialNumber != other.volSerialNumber) return false; + if (this.fileIndexHigh != other.fileIndexHigh) return false; + if (this.fileIndexLow != other.fileIndexLow) return false; + return true; + } + } + + // all change events + private static final int ALL_FILE_NOTIFY_EVENTS = + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY; + + /** + * Background thread to service I/O completion port. + */ + private class Poller extends AbstractPoller { + /* + * typedef struct _OVERLAPPED { + * DWORD Internal; + * DWORD InternalHigh; + * DWORD Offset; + * DWORD OffsetHigh; + * HANDLE hEvent; + * } OVERLAPPED; + */ + private static final short SIZEOF_DWORD = 4; + private static final short SIZEOF_OVERLAPPED = 32; // 20 on 32-bit + + /* + * typedef struct _FILE_NOTIFY_INFORMATION { + * DWORD NextEntryOffset; + * DWORD Action; + * DWORD FileNameLength; + * WCHAR FileName[1]; + * } FileNameLength; + */ + private static final short OFFSETOF_NEXTENTRYOFFSET = 0; + private static final short OFFSETOF_ACTION = 4; + private static final short OFFSETOF_FILENAMELENGTH = 8; + private static final short OFFSETOF_FILENAME = 12; + + // size of per-directory buffer for events (FIXME - make this configurable) + private static final int CHANGES_BUFFER_SIZE = 16 * 1024; + + private final WindowsFileSystem fs; + private final WindowsWatchService watcher; + private final long port; + + // maps completion key to WatchKey + private final Map<Integer,WindowsWatchKey> int2key; + + // maps file key to WatchKey + private final Map<FileKey,WindowsWatchKey> fk2key; + + // unique completion key for each directory + private int lastCompletionKey; + + Poller(WindowsFileSystem fs, WindowsWatchService watcher, long port) { + this.fs = fs; + this.watcher = watcher; + this.port = port; + this.int2key = new HashMap<Integer,WindowsWatchKey>(); + this.fk2key = new HashMap<FileKey,WindowsWatchKey>(); + this.lastCompletionKey = 0; + } + + @Override + void wakeup() throws IOException { + try { + PostQueuedCompletionStatus(port, 0); + } catch (WindowsException x) { + throw new IOException(x.getMessage()); + } + } + + /** + * Register a directory for changes as follows: + * + * 1. Open directory + * 2. Read its attributes (and check it really is a directory) + * 3. Assign completion key and associated handle with completion port + * 4. Call ReadDirectoryChangesW to start (async) read of changes + * 5. Create or return existing key representing registration + */ + @Override + Object implRegister(Path obj, + Set<? extends WatchEvent.Kind<?>> events, + WatchEvent.Modifier... modifiers) + { + WindowsPath dir = (WindowsPath)obj; + boolean watchSubtree = false; + + // FILE_TREE modifier allowed + for (WatchEvent.Modifier modifier: modifiers) { + if (modifier == ExtendedWatchEventModifier.FILE_TREE) { + watchSubtree = true; + continue; + } else { + if (modifier == null) + return new NullPointerException(); + if (modifier instanceof com.sun.nio.file.SensitivityWatchEventModifier) + continue; // ignore + return new UnsupportedOperationException("Modifier not supported"); + } + } + + // open directory + long handle = -1L; + try { + handle = CreateFile(dir.getPathForWin32Calls(), + FILE_LIST_DIRECTORY, + (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED); + } catch (WindowsException x) { + return x.asIOException(dir); + } + + boolean registered = false; + try { + // read attributes and check file is a directory + WindowsFileAttributes attrs = null; + try { + attrs = WindowsFileAttributes.readAttributes(handle); + } catch (WindowsException x) { + return x.asIOException(dir); + } + if (!attrs.isDirectory()) { + return new NotDirectoryException(dir.getPathForExceptionMessage()); + } + + // check if this directory is already registered + FileKey fk = new FileKey(attrs.volSerialNumber(), + attrs.fileIndexHigh(), + attrs.fileIndexLow()); + WindowsWatchKey existing = fk2key.get(fk); + + // if already registered and we're not changing the subtree + // modifier then simply update the event and return the key. + if (existing != null && watchSubtree == existing.watchSubtree()) { + existing.setEvents(events); + return existing; + } + + // unique completion key (skip 0) + int completionKey = ++lastCompletionKey; + if (completionKey == 0) + completionKey = ++lastCompletionKey; + + // associate handle with completion port + try { + CreateIoCompletionPort(handle, port, completionKey); + } catch (WindowsException x) { + return new IOException(x.getMessage()); + } + + // allocate memory for events, including space for other structures + // needed to do overlapped I/O + int size = CHANGES_BUFFER_SIZE + SIZEOF_DWORD + SIZEOF_OVERLAPPED; + NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); + + long bufferAddress = buffer.address(); + long overlappedAddress = bufferAddress + size - SIZEOF_OVERLAPPED; + long countAddress = overlappedAddress - SIZEOF_DWORD; + + // start async read of changes to directory + try { + ReadDirectoryChangesW(handle, + bufferAddress, + CHANGES_BUFFER_SIZE, + watchSubtree, + ALL_FILE_NOTIFY_EVENTS, + countAddress, + overlappedAddress); + } catch (WindowsException x) { + buffer.release(); + return new IOException(x.getMessage()); + } + + WindowsWatchKey watchKey; + if (existing == null) { + // not registered so create new watch key + watchKey = new WindowsWatchKey(watcher, fk) + .init(handle, events, watchSubtree, buffer, countAddress, + overlappedAddress, completionKey); + // map file key to watch key + fk2key.put(fk, watchKey); + } else { + // directory already registered so need to: + // 1. remove mapping from old completion key to existing watch key + // 2. release existing key's resources (handle/buffer) + // 3. re-initialize key with new handle/buffer + int2key.remove(existing.completionKey()); + existing.releaseResources(); + watchKey = existing.init(handle, events, watchSubtree, buffer, + countAddress, overlappedAddress, completionKey); + } + // map completion map to watch key + int2key.put(completionKey, watchKey); + + registered = true; + return watchKey; + + } finally { + if (!registered) CloseHandle(handle); + } + } + + // cancel single key + @Override + void implCancelKey(WatchKey obj) { + WindowsWatchKey key = (WindowsWatchKey)obj; + if (key.isValid()) { + fk2key.remove(key.fileKey()); + int2key.remove(key.completionKey()); + key.invalidate(); + } + } + + // close watch service + @Override + void implCloseAll() { + // cancel all keys + for (Map.Entry<Integer,WindowsWatchKey> entry: int2key.entrySet()) { + entry.getValue().invalidate(); + } + fk2key.clear(); + int2key.clear(); + + // close I/O completion port + CloseHandle(port); + } + + // Translate file change action into watch event + private WatchEvent.Kind<?> translateActionToEvent(int action) + { + switch (action) { + case FILE_ACTION_MODIFIED : + return StandardWatchEventKind.ENTRY_MODIFY; + + case FILE_ACTION_ADDED : + case FILE_ACTION_RENAMED_NEW_NAME : + return StandardWatchEventKind.ENTRY_CREATE; + + case FILE_ACTION_REMOVED : + case FILE_ACTION_RENAMED_OLD_NAME : + return StandardWatchEventKind.ENTRY_DELETE; + + default : + return null; // action not recognized + } + } + + // process events (list of FILE_NOTIFY_INFORMATION structures) + private void processEvents(WindowsWatchKey key, int size) { + long address = key.buffer().address(); + + int nextOffset; + do { + int action = unsafe.getInt(address + OFFSETOF_ACTION); + + // map action to event + WatchEvent.Kind<?> kind = translateActionToEvent(action); + if (key.events().contains(kind)) { + // copy the name + int nameLengthInBytes = unsafe.getInt(address + OFFSETOF_FILENAMELENGTH); + if ((nameLengthInBytes % 2) != 0) { + throw new AssertionError("FileNameLength.FileNameLength is not a multiple of 2"); + } + char[] nameAsArray = new char[nameLengthInBytes/2]; + unsafe.copyMemory(null, address + OFFSETOF_FILENAME, nameAsArray, + Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes); + + // create FileName and queue event + WindowsPath name = WindowsPath + .createFromNormalizedPath(fs, new String(nameAsArray)); + key.signalEvent(kind, name); + } + + // next event + nextOffset = unsafe.getInt(address + OFFSETOF_NEXTENTRYOFFSET); + address += (long)nextOffset; + } while (nextOffset != 0); + } + + /** + * Poller main loop + */ + @Override + public void run() { + for (;;) { + CompletionStatus info = null; + try { + info = GetQueuedCompletionStatus(port); + } catch (WindowsException x) { + // this should not happen + x.printStackTrace(); + return; + } + + // wakeup + if (info.completionKey() == 0) { + boolean shutdown = processRequests(); + if (shutdown) { + return; + } + continue; + } + + // map completionKey to get WatchKey + WindowsWatchKey key = int2key.get(info.completionKey()); + if (key == null) { + // We get here when a registration is changed. In that case + // the directory is closed which causes an event with the + // old completion key. + continue; + } + + // ReadDirectoryChangesW failed + if (info.error() != 0) { + // buffer overflow + if (info.error() == ERROR_NOTIFY_ENUM_DIR) { + key.signalEvent(StandardWatchEventKind.OVERFLOW, null); + } else { + // other error so cancel key + implCancelKey(key); + key.signal(); + } + continue; + } + + // process the events + if (info.bytesTransferred() > 0) { + processEvents(key, info.bytesTransferred()); + } else { + // insufficient buffer size + key.signalEvent(StandardWatchEventKind.OVERFLOW, null); + } + + // start read for next batch of changes + try { + ReadDirectoryChangesW(key.handle(), + key.buffer().address(), + CHANGES_BUFFER_SIZE, + key.watchSubtree(), + ALL_FILE_NOTIFY_EVENTS, + key.countAddress(), + key.overlappedAddress()); + } catch (WindowsException x) { + // no choice but to cancel key + implCancelKey(key); + key.signal(); + } + } + } + } +} diff --git a/jdk/src/windows/native/java/io/WinNTFileSystem_md.c b/jdk/src/windows/native/java/io/WinNTFileSystem_md.c index 13d4c7e919b..f4cc691115b 100644 --- a/jdk/src/windows/native/java/io/WinNTFileSystem_md.c +++ b/jdk/src/windows/native/java/io/WinNTFileSystem_md.c @@ -309,12 +309,13 @@ Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this, /* No template file */ NULL); if (h != INVALID_HANDLE_VALUE) { - GetFileTime(h, NULL, NULL, &t); + if (GetFileTime(h, NULL, NULL, &t)) { + modTime.LowPart = (DWORD) t.dwLowDateTime; + modTime.HighPart = (LONG) t.dwHighDateTime; + rv = modTime.QuadPart / 10000; + rv -= 11644473600000; + } CloseHandle(h); - modTime.LowPart = (DWORD) t.dwLowDateTime; - modTime.HighPart = (LONG) t.dwHighDateTime; - rv = modTime.QuadPart / 10000; - rv -= 11644473600000; } free(pathbuf); return rv; diff --git a/jdk/src/windows/native/java/lang/java_props_md.c b/jdk/src/windows/native/java/lang/java_props_md.c index f75721f9f71..b15a9bafac0 100644 --- a/jdk/src/windows/native/java/lang/java_props_md.c +++ b/jdk/src/windows/native/java/lang/java_props_md.c @@ -717,6 +717,7 @@ GetJavaProperties(JNIEnv* env) * Windows Vista family 6 0 * Windows 2008 6 0 * where ((&ver.wServicePackMinor) + 2) = 1 + * Windows 7 6 1 * * This mapping will presumably be augmented as new Windows * versions are released. @@ -773,13 +774,18 @@ GetJavaProperties(JNIEnv* env) * and Windows Vista are identical, you must also test * whether the wProductType member is VER_NT_WORKSTATION. * If wProductType is VER_NT_WORKSTATION, the operating - * system is Windows Vista; otherwise, it is Windows + * system is Windows Vista or 7; otherwise, it is Windows * Server 2008." */ - if (ver.wProductType == VER_NT_WORKSTATION) - sprops.os_name = "Windows Vista"; - else + if (ver.wProductType == VER_NT_WORKSTATION) { + switch (ver.dwMinorVersion) { + case 0: sprops.os_name = "Windows Vista"; break; + case 1: sprops.os_name = "Windows 7"; break; + default: sprops.os_name = "Windows NT (unknown)"; + } + } else { sprops.os_name = "Windows Server 2008"; + } } else { sprops.os_name = "Windows NT (unknown)"; } diff --git a/jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c b/jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c index da96a109a7f..d1056b883b3 100644 --- a/jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c +++ b/jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,10 +34,6 @@ static jfieldID chan_fd; /* id for jobject 'fd' in java.io.FileChannel */ - -/* false for 95/98/ME, true for NT/W2K */ -static jboolean onNT = JNI_FALSE; - /************************************************************** * static method to store field ID's in initializers * and retrieve the allocation granularity @@ -47,15 +43,9 @@ Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz) { SYSTEM_INFO si; jint align; - OSVERSIONINFO ver; GetSystemInfo(&si); align = si.dwAllocationGranularity; chan_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;"); - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) { - onNT = JNI_TRUE; - } return align; } @@ -146,56 +136,6 @@ Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this, return 0; } -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileChannelImpl_truncate0(JNIEnv *env, jobject this, - jobject fdo, jlong size) -{ - DWORD lowPos = 0; - long highPos = 0; - BOOL result = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - - lowPos = (DWORD)size; - highPos = (long)(size >> 32); - lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN); - if (lowPos == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Truncation failed"); - return IOS_THROWN; - } - } - result = SetEndOfFile(h); - if (result == 0) { - JNU_ThrowIOExceptionWithLastError(env, "Truncation failed"); - return IOS_THROWN; - } - return 0; -} - - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileChannelImpl_force0(JNIEnv *env, jobject this, - jobject fdo, jboolean md) -{ - int result = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - - if (h != INVALID_HANDLE_VALUE) { - result = FlushFileBuffers(h); - if (result == 0) { - int error = GetLastError(); - if (error != ERROR_ACCESS_DENIED) { - JNU_ThrowIOExceptionWithLastError(env, "Force failed"); - return IOS_THROWN; - } - } - } else { - JNU_ThrowIOExceptionWithLastError(env, "Force failed"); - return IOS_THROWN; - } - return 0; -} - JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this, jobject fdo, jlong offset) @@ -220,23 +160,6 @@ Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this, return (((jlong)highPos) << 32) | lowPos; } -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileChannelImpl_size0(JNIEnv *env, jobject this, jobject fdo) -{ - DWORD sizeLow = 0; - DWORD sizeHigh = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - - sizeLow = GetFileSize(h, &sizeHigh); - if (sizeLow == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Size failed"); - return IOS_THROWN; - } - } - return (((jlong)sizeHigh) << 32) | sizeLow; -} - JNIEXPORT void JNICALL Java_sun_nio_ch_FileChannelImpl_close0(JNIEnv *env, jobject this, jobject fdo) { @@ -257,99 +180,3 @@ Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, { return IOS_UNSUPPORTED; } - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileChannelImpl_lock0(JNIEnv *env, jobject this, jobject fdo, - jboolean block, jlong pos, jlong size, - jboolean shared) -{ - HANDLE h = (HANDLE)(handleval(env, fdo)); - DWORD lowPos = (DWORD)pos; - long highPos = (long)(pos >> 32); - DWORD lowNumBytes = (DWORD)size; - DWORD highNumBytes = (DWORD)(size >> 32); - jint result = 0; - if (onNT) { - DWORD flags = 0; - OVERLAPPED o; - o.hEvent = 0; - o.Offset = lowPos; - o.OffsetHigh = highPos; - if (block == JNI_FALSE) { - flags |= LOCKFILE_FAIL_IMMEDIATELY; - } - if (shared == JNI_FALSE) { - flags |= LOCKFILE_EXCLUSIVE_LOCK; - } - result = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, &o); - if (result == 0) { - int error = GetLastError(); - if (error != ERROR_LOCK_VIOLATION) { - JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); - return sun_nio_ch_FileChannelImpl_NO_LOCK; - } - if (flags & LOCKFILE_FAIL_IMMEDIATELY) { - return sun_nio_ch_FileChannelImpl_NO_LOCK; - } - JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); - return sun_nio_ch_FileChannelImpl_NO_LOCK; - } - return sun_nio_ch_FileChannelImpl_LOCKED; - } else { - for(;;) { - if (size > 0x7fffffff) { - size = 0x7fffffff; - } - lowNumBytes = (DWORD)size; - highNumBytes = 0; - result = LockFile(h, lowPos, highPos, lowNumBytes, highNumBytes); - if (result != 0) { - if (shared == JNI_TRUE) { - return sun_nio_ch_FileChannelImpl_RET_EX_LOCK; - } else { - return sun_nio_ch_FileChannelImpl_LOCKED; - } - } else { - int error = GetLastError(); - if (error != ERROR_LOCK_VIOLATION) { - JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); - return sun_nio_ch_FileChannelImpl_NO_LOCK; - } - if (block == JNI_FALSE) { - return sun_nio_ch_FileChannelImpl_NO_LOCK; - } - } - Sleep(100); - } - } - return sun_nio_ch_FileChannelImpl_NO_LOCK; -} - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileChannelImpl_release0(JNIEnv *env, jobject this, - jobject fdo, jlong pos, jlong size) -{ - HANDLE h = (HANDLE)(handleval(env, fdo)); - DWORD lowPos = (DWORD)pos; - long highPos = (long)(pos >> 32); - DWORD lowNumBytes = (DWORD)size; - DWORD highNumBytes = (DWORD)(size >> 32); - jint result = 0; - if (onNT) { - OVERLAPPED o; - o.hEvent = 0; - o.Offset = lowPos; - o.OffsetHigh = highPos; - result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o); - } else { - if (size > 0x7fffffff) { - size = 0x7fffffff; - } - lowNumBytes = (DWORD)size; - highNumBytes = 0; - result = UnlockFile(h, lowPos, highPos, lowNumBytes, highNumBytes); - } - if (result == 0) { - JNU_ThrowIOExceptionWithLastError(env, "Release failed"); - } -} diff --git a/jdk/src/windows/native/sun/nio/ch/FileDispatcher.c b/jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c similarity index 67% rename from jdk/src/windows/native/sun/nio/ch/FileDispatcher.c rename to jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c index a3c3985e7a0..a65ad90e24d 100644 --- a/jdk/src/windows/native/sun/nio/ch/FileDispatcher.c +++ b/jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,18 +28,18 @@ #include "jni_util.h" #include "jvm.h" #include "jlong.h" -#include "sun_nio_ch_FileDispatcher.h" +#include "sun_nio_ch_FileDispatcherImpl.h" #include <io.h> #include "nio.h" #include "nio_util.h" /************************************************************** - * FileDispatcher.c + * FileDispatcherImpl.c */ JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcher_read0(JNIEnv *env, jclass clazz, jobject fdo, +Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { DWORD read = 0; @@ -70,7 +70,7 @@ Java_sun_nio_ch_FileDispatcher_read0(JNIEnv *env, jclass clazz, jobject fdo, } JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcher_readv0(JNIEnv *env, jclass clazz, jobject fdo, +Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { DWORD read = 0; @@ -119,7 +119,7 @@ Java_sun_nio_ch_FileDispatcher_readv0(JNIEnv *env, jclass clazz, jobject fdo, } JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcher_pread0(JNIEnv *env, jclass clazz, jobject fdo, +Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len, jlong offset) { DWORD read = 0; @@ -182,7 +182,7 @@ Java_sun_nio_ch_FileDispatcher_pread0(JNIEnv *env, jclass clazz, jobject fdo, } JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo, +Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { BOOL result = 0; @@ -205,7 +205,7 @@ Java_sun_nio_ch_FileDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo, } JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcher_writev0(JNIEnv *env, jclass clazz, jobject fdo, +Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { BOOL result = 0; @@ -244,7 +244,7 @@ Java_sun_nio_ch_FileDispatcher_writev0(JNIEnv *env, jclass clazz, jobject fdo, } JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcher_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, +Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len, jlong offset) { BOOL result = 0; @@ -295,6 +295,130 @@ Java_sun_nio_ch_FileDispatcher_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, return convertReturnVal(env, (jint)written, JNI_FALSE); } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, + jobject fdo, jboolean md) +{ + int result = 0; + HANDLE h = (HANDLE)(handleval(env, fdo)); + + if (h != INVALID_HANDLE_VALUE) { + result = FlushFileBuffers(h); + if (result == 0) { + int error = GetLastError(); + if (error != ERROR_ACCESS_DENIED) { + JNU_ThrowIOExceptionWithLastError(env, "Force failed"); + return IOS_THROWN; + } + } + } else { + JNU_ThrowIOExceptionWithLastError(env, "Force failed"); + return IOS_THROWN; + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, + jobject fdo, jlong size) +{ + DWORD lowPos = 0; + long highPos = 0; + BOOL result = 0; + HANDLE h = (HANDLE)(handleval(env, fdo)); + + lowPos = (DWORD)size; + highPos = (long)(size >> 32); + lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN); + if (lowPos == ((DWORD)-1)) { + if (GetLastError() != ERROR_SUCCESS) { + JNU_ThrowIOExceptionWithLastError(env, "Truncation failed"); + return IOS_THROWN; + } + } + result = SetEndOfFile(h); + if (result == 0) { + JNU_ThrowIOExceptionWithLastError(env, "Truncation failed"); + return IOS_THROWN; + } + return 0; +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) +{ + DWORD sizeLow = 0; + DWORD sizeHigh = 0; + HANDLE h = (HANDLE)(handleval(env, fdo)); + + sizeLow = GetFileSize(h, &sizeHigh); + if (sizeLow == ((DWORD)-1)) { + if (GetLastError() != ERROR_SUCCESS) { + JNU_ThrowIOExceptionWithLastError(env, "Size failed"); + return IOS_THROWN; + } + } + return (((jlong)sizeHigh) << 32) | sizeLow; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, + jboolean block, jlong pos, jlong size, + jboolean shared) +{ + HANDLE h = (HANDLE)(handleval(env, fdo)); + DWORD lowPos = (DWORD)pos; + long highPos = (long)(pos >> 32); + DWORD lowNumBytes = (DWORD)size; + DWORD highNumBytes = (DWORD)(size >> 32); + BOOL result; + DWORD flags = 0; + OVERLAPPED o; + o.hEvent = 0; + o.Offset = lowPos; + o.OffsetHigh = highPos; + if (block == JNI_FALSE) { + flags |= LOCKFILE_FAIL_IMMEDIATELY; + } + if (shared == JNI_FALSE) { + flags |= LOCKFILE_EXCLUSIVE_LOCK; + } + result = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, &o); + if (result == 0) { + int error = GetLastError(); + if (error != ERROR_LOCK_VIOLATION) { + JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); + return sun_nio_ch_FileDispatcherImpl_NO_LOCK; + } + if (flags & LOCKFILE_FAIL_IMMEDIATELY) { + return sun_nio_ch_FileDispatcherImpl_NO_LOCK; + } + JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); + return sun_nio_ch_FileDispatcherImpl_NO_LOCK; + } + return sun_nio_ch_FileDispatcherImpl_LOCKED; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, + jobject fdo, jlong pos, jlong size) +{ + HANDLE h = (HANDLE)(handleval(env, fdo)); + DWORD lowPos = (DWORD)pos; + long highPos = (long)(pos >> 32); + DWORD lowNumBytes = (DWORD)size; + DWORD highNumBytes = (DWORD)(size >> 32); + jint result = 0; + OVERLAPPED o; + o.hEvent = 0; + o.Offset = lowPos; + o.OffsetHigh = highPos; + result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o); + if (result == 0) { + JNU_ThrowIOExceptionWithLastError(env, "Release failed"); + } +} + static void closeFile(JNIEnv *env, jlong fd) { HANDLE h = (HANDLE)fd; if (h != INVALID_HANDLE_VALUE) { @@ -305,14 +429,14 @@ static void closeFile(JNIEnv *env, jlong fd) { } JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcher_close0(JNIEnv *env, jclass clazz, jobject fdo) +Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) { jlong fd = handleval(env, fdo); closeFile(env, fd); } JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcher_closeByHandle(JNIEnv *env, jclass clazz, +Java_sun_nio_ch_FileDispatcherImpl_closeByHandle(JNIEnv *env, jclass clazz, jlong fd) { closeFile(env, fd); diff --git a/jdk/src/windows/native/sun/nio/ch/Iocp.c b/jdk/src/windows/native/sun/nio/ch/Iocp.c new file mode 100644 index 00000000000..9568189ee6b --- /dev/null +++ b/jdk/src/windows/native/sun/nio/ch/Iocp.c @@ -0,0 +1,147 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <windows.h> + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" + +#include "sun_nio_ch_Iocp.h" + + +static jfieldID completionStatus_error; +static jfieldID completionStatus_bytesTransferred; +static jfieldID completionStatus_completionKey; +static jfieldID completionStatus_overlapped; + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Iocp_initIDs(JNIEnv* env, jclass this) +{ + jclass clazz; + + clazz = (*env)->FindClass(env, "sun/nio/ch/Iocp$CompletionStatus"); + if (clazz == NULL) { + return; + } + completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I"); + if (completionStatus_error == NULL) return; + completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I"); + if (completionStatus_bytesTransferred == NULL) return; + completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "I"); + if (completionStatus_completionKey == NULL) return; + completionStatus_overlapped = (*env)->GetFieldID(env, clazz, "overlapped", "J"); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_Iocp_createIoCompletionPort(JNIEnv* env, jclass this, + jlong handle, jlong existingPort, jint completionKey, jint concurrency) +{ + HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(handle), + (HANDLE)jlong_to_ptr(existingPort), + (DWORD)completionKey, + (DWORD)concurrency); + if (port == NULL) { + JNU_ThrowIOExceptionWithLastError(env, "CreateIoCompletionPort failed"); + } + return ptr_to_jlong(port); +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Iocp_close0(JNIEnv* env, jclass this, + jlong handle) +{ + HANDLE h = (HANDLE)jlong_to_ptr(handle); + CloseHandle(h); +} + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Iocp_getQueuedCompletionStatus(JNIEnv* env, jclass this, + jlong completionPort, jobject obj) +{ + DWORD bytesTransferred; + DWORD completionKey; + OVERLAPPED *lpOverlapped; + BOOL res; + + res = GetQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort), + &bytesTransferred, + &completionKey, + &lpOverlapped, + INFINITE); + if (res == 0 && lpOverlapped == NULL) { + JNU_ThrowIOExceptionWithLastError(env, "GetQueuedCompletionStatus failed"); + } else { + DWORD ioResult = (res == 0) ? GetLastError() : 0; + (*env)->SetIntField(env, obj, completionStatus_error, ioResult); + (*env)->SetIntField(env, obj, completionStatus_bytesTransferred, + (jint)bytesTransferred); + (*env)->SetIntField(env, obj, completionStatus_completionKey, + (jint)completionKey); + (*env)->SetLongField(env, obj, completionStatus_overlapped, + ptr_to_jlong(lpOverlapped)); + + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Iocp_postQueuedCompletionStatus(JNIEnv* env, jclass this, + jlong completionPort, jint completionKey) +{ + BOOL res; + + res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort), + (DWORD)0, + (DWORD)completionKey, + NULL); + if (res == 0) { + JNU_ThrowIOExceptionWithLastError(env, "PostQueuedCompletionStatus"); + } +} + +JNIEXPORT jstring JNICALL +Java_sun_nio_ch_Iocp_getErrorMessage(JNIEnv* env, jclass this, jint errorCode) +{ + WCHAR message[255]; + + DWORD len = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + (DWORD)errorCode, + 0, + &message[0], + 255, + NULL); + + + if (len == 0) { + return NULL; + } else { + return (*env)->NewString(env, (const jchar *)message, (jsize)wcslen(message)); + } +} diff --git a/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c new file mode 100644 index 00000000000..d8346ba3e7a --- /dev/null +++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c @@ -0,0 +1,132 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <windows.h> + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" + +#include "sun_nio_ch_WindowsAsynchronousFileChannelImpl.h" + + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_readFile(JNIEnv* env, jclass this, + jlong handle, jlong address, jint len, jlong offset, jlong ov) +{ + BOOL res; + DWORD nread = 0; + + OVERLAPPED* lpOverlapped = (OVERLAPPED*)jlong_to_ptr(ov); + lpOverlapped->Offset = (DWORD)offset; + lpOverlapped->OffsetHigh = (DWORD)((long)(offset >> 32)); + lpOverlapped->hEvent = NULL; + + res = ReadFile((HANDLE) jlong_to_ptr(handle), + (LPVOID) jlong_to_ptr(address), + (DWORD)len, + &nread, + lpOverlapped); + + if (res == 0) { + int error = GetLastError(); + if (error == ERROR_IO_PENDING) + return IOS_UNAVAILABLE; + if (error == ERROR_HANDLE_EOF) + return IOS_EOF; + JNU_ThrowIOExceptionWithLastError(env, "ReadFile failed"); + return IOS_THROWN; + } + + return (jint)nread; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_writeFile(JNIEnv* env, jclass this, + jlong handle, jlong address, jint len, jlong offset, jlong ov) +{ + BOOL res; + DWORD nwritten = 0; + + OVERLAPPED* lpOverlapped = (OVERLAPPED*)jlong_to_ptr(ov); + lpOverlapped->Offset = (DWORD)offset; + lpOverlapped->OffsetHigh = (DWORD)((long)(offset >> 32)); + lpOverlapped->hEvent = NULL; + + res = WriteFile((HANDLE)jlong_to_ptr(handle), + (LPVOID) jlong_to_ptr(address), + (DWORD)len, + &nwritten, + lpOverlapped); + + if (res == 0) { + int error = GetLastError(); + if (error == ERROR_IO_PENDING) { + return IOS_UNAVAILABLE; + } + JNU_ThrowIOExceptionWithLastError(env, "WriteFile failed"); + return IOS_THROWN; + } + return (jint)nwritten; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_lockFile(JNIEnv *env, jobject this, jlong handle, + jlong pos, jlong size, jboolean shared, jlong ov) +{ + BOOL res; + HANDLE h = jlong_to_ptr(handle); + DWORD lowPos = (DWORD)pos; + long highPos = (long)(pos >> 32); + DWORD lowNumBytes = (DWORD)size; + DWORD highNumBytes = (DWORD)(size >> 32); + DWORD flags = (shared == JNI_TRUE) ? 0 : LOCKFILE_EXCLUSIVE_LOCK; + OVERLAPPED* lpOverlapped = (OVERLAPPED*)jlong_to_ptr(ov); + + lpOverlapped->Offset = lowPos; + lpOverlapped->OffsetHigh = highPos; + lpOverlapped->hEvent = NULL; + + res = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, lpOverlapped); + if (res == 0) { + int error = GetLastError(); + if (error == ERROR_IO_PENDING) { + return IOS_UNAVAILABLE; + } + JNU_ThrowIOExceptionWithLastError(env, "WriteFile failed"); + return IOS_THROWN; + } + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_close0(JNIEnv* env, jclass this, + jlong handle) +{ + HANDLE h = (HANDLE)jlong_to_ptr(handle); + CloseHandle(h); +} diff --git a/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.c b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.c new file mode 100644 index 00000000000..ba706a4d86b --- /dev/null +++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.c @@ -0,0 +1,142 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <windows.h> +#include <winsock2.h> + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" +#include "net_util.h" + +#include "sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl.h" + + +#ifndef WSAID_ACCEPTEX +#define WSAID_ACCEPTEX {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} +#endif + +#ifndef SO_UPDATE_ACCEPT_CONTEXT +#define SO_UPDATE_ACCEPT_CONTEXT 0x700B +#endif + + +typedef BOOL (*AcceptEx_t) +( + SOCKET sListenSocket, + SOCKET sAcceptSocket, + PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPDWORD lpdwBytesReceived, + LPOVERLAPPED lpOverlapped +); + + +static AcceptEx_t AcceptEx_func; + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_initIDs(JNIEnv* env, jclass this) { + GUID GuidAcceptEx = WSAID_ACCEPTEX; + SOCKET s; + int rv; + DWORD dwBytes; + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) { + JNU_ThrowIOExceptionWithLastError(env, "socket failed"); + return; + } + rv = WSAIoctl(s, + SIO_GET_EXTENSION_FUNCTION_POINTER, + (LPVOID)&GuidAcceptEx, + sizeof(GuidAcceptEx), + &AcceptEx_func, + sizeof(AcceptEx_func), + &dwBytes, + NULL, + NULL); + if (rv != 0) + JNU_ThrowIOExceptionWithLastError(env, "WSAIoctl failed"); + closesocket(s); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_accept0(JNIEnv* env, jclass this, + jlong listenSocket, jlong acceptSocket, jlong ov, jlong buf) +{ + BOOL res; + SOCKET s1 = (SOCKET)jlong_to_ptr(listenSocket); + SOCKET s2 = (SOCKET)jlong_to_ptr(acceptSocket); + PVOID outputBuffer = (PVOID)jlong_to_ptr(buf); + + DWORD nread = 0; + OVERLAPPED* lpOverlapped = (OVERLAPPED*)jlong_to_ptr(ov); + ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); + + res = (*AcceptEx_func)(s1, + s2, + outputBuffer, + 0, + sizeof(SOCKETADDRESS)+16, + sizeof(SOCKETADDRESS)+16, + &nread, + lpOverlapped); + if (res == 0) { + int error = WSAGetLastError(); + if (error == ERROR_IO_PENDING) { + return IOS_UNAVAILABLE; + } + JNU_ThrowIOExceptionWithLastError(env, "AcceptEx failed"); + return IOS_THROWN; + } + + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_updateAcceptContext(JNIEnv* env, jclass this, + jlong listenSocket, jlong acceptSocket) +{ + SOCKET s1 = (SOCKET)jlong_to_ptr(listenSocket); + SOCKET s2 = (SOCKET)jlong_to_ptr(acceptSocket); + + setsockopt(s2, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&s1, sizeof(s1)); +} + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_closesocket0(JNIEnv* env, jclass this, + jlong socket) +{ + SOCKET s = (SOCKET)jlong_to_ptr(socket); + + if (closesocket(s) == SOCKET_ERROR) + JNU_ThrowIOExceptionWithLastError(env, "closesocket failed"); +} diff --git a/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c new file mode 100644 index 00000000000..97c49f60a71 --- /dev/null +++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c @@ -0,0 +1,222 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <windows.h> +#include <winsock2.h> +#include <stddef.h> + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" +#include "net_util.h" + +#include "sun_nio_ch_WindowsAsynchronousSocketChannelImpl.h" + +#ifndef WSAID_CONNECTEX +#define WSAID_CONNECTEX {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}} +#endif + +#ifndef SO_UPDATE_CONNECT_CONTEXT +#define SO_UPDATE_CONNECT_CONTEXT 0x7010 +#endif + +typedef BOOL (*ConnectEx_t) +( + SOCKET s, + const struct sockaddr* name, + int namelen, + PVOID lpSendBuffer, + DWORD dwSendDataLength, + LPDWORD lpdwBytesSent, + LPOVERLAPPED lpOverlapped +); + +static ConnectEx_t ConnectEx_func; + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_initIDs(JNIEnv* env, jclass this) { + GUID GuidConnectEx = WSAID_CONNECTEX; + SOCKET s; + int rv; + DWORD dwBytes; + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) { + JNU_ThrowIOExceptionWithLastError(env, "socket failed"); + return; + } + rv = WSAIoctl(s, + SIO_GET_EXTENSION_FUNCTION_POINTER, + (LPVOID)&GuidConnectEx, + sizeof(GuidConnectEx), + &ConnectEx_func, + sizeof(ConnectEx_func), + &dwBytes, + NULL, + NULL); + if (rv != 0) + JNU_ThrowIOExceptionWithLastError(env, "WSAIoctl failed"); + closesocket(s); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_connect0(JNIEnv* env, jclass this, + jlong socket, jboolean preferIPv6, jobject iao, jint port, jlong ov) +{ + SOCKET s = (SOCKET) jlong_to_ptr(socket); + OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov); + + SOCKETADDRESS sa; + int sa_len; + BOOL res; + + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { + return IOS_THROWN; + } + + ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); + + res = (*ConnectEx_func)(s, + (struct sockaddr *)&sa, + sa_len, + NULL, + 0, + NULL, + lpOverlapped); + if (res == 0) { + int error = GetLastError(); + if (error == ERROR_IO_PENDING) { + return IOS_UNAVAILABLE; + } + JNU_ThrowIOExceptionWithLastError(env, "ConnectEx failed"); + return IOS_THROWN; + } + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_updateConnectContext(JNIEnv* env, jclass this, + jlong socket) +{ + SOCKET s = (SOCKET)jlong_to_ptr(socket); + setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0); +} + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_shutdown0(JNIEnv *env, jclass cl, + jlong socket, jint how) +{ + SOCKET s =(SOCKET) jlong_to_ptr(socket); + if (shutdown(s, how) == SOCKET_ERROR) { + JNU_ThrowIOExceptionWithLastError(env, "shutdown failed"); + } +} + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_closesocket0(JNIEnv* env, jclass this, + jlong socket) +{ + SOCKET s = (SOCKET)jlong_to_ptr(socket); + if (closesocket(s) == SOCKET_ERROR) + JNU_ThrowIOExceptionWithLastError(env, "closesocket failed"); +} + + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_read0(JNIEnv* env, jclass this, + jlong socket, jint count, jlong address, jlong ov) +{ + SOCKET s = (SOCKET) jlong_to_ptr(socket); + WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address); + OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov); + BOOL res; + DWORD nread = 0; + DWORD flags = 0; + + ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); + res = WSARecv(s, + lpWsaBuf, + (DWORD)count, + &nread, + &flags, + lpOverlapped, + NULL); + + if (res == SOCKET_ERROR) { + int error = WSAGetLastError(); + if (error == WSA_IO_PENDING) { + return IOS_UNAVAILABLE; + } + if (error == WSAESHUTDOWN) { + return 0; // input shutdown + } + JNU_ThrowIOExceptionWithLastError(env, "WSARecv failed"); + return IOS_THROWN; + } + if (nread == 0) { + // Handle graceful close or bytes not yet available cases + // via completion port notification. + return IOS_UNAVAILABLE; + } + return (jint)nread; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_write0(JNIEnv* env, jclass this, + jlong socket, jint count, jlong address, jlong ov) +{ + SOCKET s = (SOCKET) jlong_to_ptr(socket); + WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address); + OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov); + BOOL res; + DWORD nwritten; + + ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); + res = WSASend(s, + lpWsaBuf, + (DWORD)count, + &nwritten, + 0, + lpOverlapped, + NULL); + + if (res == SOCKET_ERROR) { + int error = WSAGetLastError(); + if (error == WSA_IO_PENDING) { + return IOS_UNAVAILABLE; + } + if (error == WSAESHUTDOWN) { + return IOS_EOF; // output shutdown + } + JNU_ThrowIOExceptionWithLastError(env, "WSASend failed"); + return IOS_THROWN; + } + return (jint)nwritten; +} diff --git a/jdk/src/windows/native/sun/nio/fs/RegistryFileTypeDetector.c b/jdk/src/windows/native/sun/nio/fs/RegistryFileTypeDetector.c new file mode 100644 index 00000000000..14c7f6af948 --- /dev/null +++ b/jdk/src/windows/native/sun/nio/fs/RegistryFileTypeDetector.c @@ -0,0 +1,62 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include <windows.h> + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" + +#include "sun_nio_fs_RegistryFileTypeDetector.h" + + +JNIEXPORT jstring JNICALL +Java_sun_nio_fs_RegistryFileTypeDetector_queryStringValue(JNIEnv* env, jclass this, + jlong keyAddress, jlong nameAddress) +{ + LPCWSTR lpSubKey= (LPCWSTR)jlong_to_ptr(keyAddress); + LPWSTR lpValueName = (LPWSTR)jlong_to_ptr(nameAddress); + LONG res; + HKEY hKey; + jstring result = NULL; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, lpSubKey, 0, KEY_READ, &hKey); + if (res == ERROR_SUCCESS) { + DWORD type; + BYTE data[255]; + DWORD size = sizeof(data); + + res = RegQueryValueExW(hKey, lpValueName, NULL, &type, (LPBYTE)&data, &size); + if (res == ERROR_SUCCESS) { + if (type == REG_SZ) { + jsize len = wcslen((WCHAR*)data); + result = (*env)->NewString(env, (const jchar*)&data, len); + } + } + + RegCloseKey(hKey); + } + return result; +} diff --git a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c new file mode 100644 index 00000000000..45a3646275c --- /dev/null +++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c @@ -0,0 +1,1345 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <direct.h> +#include <malloc.h> +#include <io.h> +#include <windows.h> +#include <aclapi.h> +#include <winioctl.h> + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" + +#include "sun_nio_fs_WindowsNativeDispatcher.h" + +/** + * jfieldIDs + */ +static jfieldID findFirst_handle; +static jfieldID findFirst_name; + +static jfieldID findStream_handle; +static jfieldID findStream_name; + +static jfieldID volumeInfo_fsName; +static jfieldID volumeInfo_volName; +static jfieldID volumeInfo_volSN; +static jfieldID volumeInfo_flags; + +static jfieldID diskSpace_bytesAvailable; +static jfieldID diskSpace_totalBytes; +static jfieldID diskSpace_totalFree; + +static jfieldID account_domain; +static jfieldID account_name; +static jfieldID account_use; + +static jfieldID aclInfo_aceCount; + +static jfieldID completionStatus_error; +static jfieldID completionStatus_bytesTransferred; +static jfieldID completionStatus_completionKey; + +static jfieldID backupResult_bytesTransferred; +static jfieldID backupResult_context; + + +/** + * Win32 APIs not defined in Visual Studio 2003 header files + */ + +typedef enum { + FindStreamInfoStandard +} MY_STREAM_INFO_LEVELS; + +typedef struct _MY_WIN32_FIND_STREAM_DATA { + LARGE_INTEGER StreamSize; + WCHAR cStreamName[MAX_PATH + 36]; +} MY_WIN32_FIND_STREAM_DATA; + +typedef HANDLE (WINAPI* FindFirstStream_Proc)(LPCWSTR, MY_STREAM_INFO_LEVELS, LPVOID, DWORD); +typedef BOOL (WINAPI* FindNextStream_Proc)(HANDLE, LPVOID); + +typedef BOOLEAN (WINAPI* CreateSymbolicLinkProc) (LPCWSTR, LPCWSTR, DWORD); +typedef BOOL (WINAPI* CreateHardLinkProc) (LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); +typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD); + +typedef BOOL (WINAPI* ConvertSidToStringSidProc) (PSID, LPWSTR*); +typedef BOOL (WINAPI* ConvertStringSidToSidProc) (LPWSTR, PSID*); +typedef DWORD (WINAPI* GetLengthSidProc) (PSID); + +static FindFirstStream_Proc FindFirstStream_func; +static FindNextStream_Proc FindNextStream_func; + +static CreateSymbolicLinkProc CreateSymbolicLink_func; +static CreateHardLinkProc CreateHardLink_func; +static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func; + +static ConvertSidToStringSidProc ConvertSidToStringSid_func; +static ConvertStringSidToSidProc ConvertStringSidToSid_func; +static GetLengthSidProc GetLengthSid_func; + +static void throwWindowsException(JNIEnv* env, DWORD lastError) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/WindowsException", + "(I)V", lastError); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +/** + * Initializes jfieldIDs and get address of Win32 calls that are located + * at runtime. + */ +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) +{ + jclass clazz; + HMODULE h; + + clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstFile"); + if (clazz == NULL) { + return; + } + findFirst_handle = (*env)->GetFieldID(env, clazz, "handle", "J"); + findFirst_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstStream"); + if (clazz == NULL) { + return; + } + findStream_handle = (*env)->GetFieldID(env, clazz, "handle", "J"); + findStream_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$VolumeInformation"); + if (clazz == NULL) { + return; + } + volumeInfo_fsName = (*env)->GetFieldID(env, clazz, "fileSystemName", "Ljava/lang/String;"); + volumeInfo_volName = (*env)->GetFieldID(env, clazz, "volumeName", "Ljava/lang/String;"); + volumeInfo_volSN = (*env)->GetFieldID(env, clazz, "volumeSerialNumber", "I"); + volumeInfo_flags = (*env)->GetFieldID(env, clazz, "flags", "I"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$DiskFreeSpace"); + if (clazz == NULL) { + return; + } + diskSpace_bytesAvailable = (*env)->GetFieldID(env, clazz, "freeBytesAvailable", "J"); + diskSpace_totalBytes = (*env)->GetFieldID(env, clazz, "totalNumberOfBytes", "J"); + diskSpace_totalFree = (*env)->GetFieldID(env, clazz, "totalNumberOfFreeBytes", "J"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$Account"); + if (clazz == NULL) { + return; + } + account_domain = (*env)->GetFieldID(env, clazz, "domain", "Ljava/lang/String;"); + account_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;"); + account_use = (*env)->GetFieldID(env, clazz, "use", "I"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$AclInformation"); + if (clazz == NULL) { + return; + } + aclInfo_aceCount = (*env)->GetFieldID(env, clazz, "aceCount", "I"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$CompletionStatus"); + if (clazz == NULL) { + return; + } + completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I"); + completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I"); + completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "I"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$BackupResult"); + if (clazz == NULL) { + return; + } + backupResult_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I"); + backupResult_context = (*env)->GetFieldID(env, clazz, "context", "J"); + + + h = LoadLibrary("kernel32"); + if (h != INVALID_HANDLE_VALUE) { + FindFirstStream_func = + (FindFirstStream_Proc)GetProcAddress(h, "FindFirstStreamW"); + FindNextStream_func = + (FindNextStream_Proc)GetProcAddress(h, "FindNextStreamW"); + CreateSymbolicLink_func = + (CreateSymbolicLinkProc)GetProcAddress(h, "CreateSymbolicLinkW"); + CreateHardLink_func = + (CreateHardLinkProc)GetProcAddress(h, "CreateHardLinkW"); + GetFinalPathNameByHandle_func = + (GetFinalPathNameByHandleProc)GetProcAddress(h, "GetFinalPathNameByHandleW"); + FreeLibrary(h); + } + + h = LoadLibrary("advapi32"); + if (h != INVALID_HANDLE_VALUE) { + ConvertSidToStringSid_func = + (ConvertSidToStringSidProc)GetProcAddress(h, "ConvertSidToStringSidW"); + ConvertStringSidToSid_func = + (ConvertStringSidToSidProc)GetProcAddress(h, "ConvertStringSidToSidW"); + GetLengthSid_func = + (GetLengthSidProc)GetProcAddress(h, "GetLengthSid"); + FreeLibrary(h); + } + +} + +JNIEXPORT jstring JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_FormatMessage(JNIEnv* env, jclass this, jint errorCode) { + WCHAR message[255]; + + DWORD len = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + (DWORD)errorCode, + 0, + &message[0], + 255, + NULL); + + + if (len == 0) { + return NULL; + } else { + return (*env)->NewString(env, (const jchar *)message, (jsize)wcslen(message)); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_LocalFree(JNIEnv* env, jclass this, jlong address) +{ + HLOCAL hMem = (HLOCAL)jlong_to_ptr(address); + LocalFree(hMem); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_CreateFile0(JNIEnv* env, jclass this, + jlong address, jint dwDesiredAccess, jint dwShareMode, jlong sdAddress, + jint dwCreationDisposition, jint dwFlagsAndAttributes) +{ + HANDLE handle; + LPCWSTR lpFileName = jlong_to_ptr(address); + + SECURITY_ATTRIBUTES securityAttributes; + LPSECURITY_ATTRIBUTES lpSecurityAttributes; + PSECURITY_DESCRIPTOR lpSecurityDescriptor = jlong_to_ptr(sdAddress); + + + if (lpSecurityDescriptor == NULL) { + lpSecurityAttributes = NULL; + } else { + securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + securityAttributes.lpSecurityDescriptor = lpSecurityDescriptor; + securityAttributes.bInheritHandle = FALSE; + lpSecurityAttributes = &securityAttributes; + } + + handle = CreateFileW(lpFileName, + (DWORD)dwDesiredAccess, + (DWORD)dwShareMode, + lpSecurityAttributes, + (DWORD)dwCreationDisposition, + (DWORD)dwFlagsAndAttributes, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + throwWindowsException(env, GetLastError()); + } + return ptr_to_jlong(handle); +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_DeviceIoControlSetSparse(JNIEnv* env, jclass this, + jlong handle) +{ + DWORD bytesReturned; + HANDLE h = (HANDLE)jlong_to_ptr(handle); + if (DeviceIoControl(h, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &bytesReturned, NULL) == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_DeviceIoControlGetReparsePoint(JNIEnv* env, jclass this, + jlong handle, jlong bufferAddress, jint bufferSize) +{ + DWORD bytesReturned; + HANDLE h = (HANDLE)jlong_to_ptr(handle); + LPVOID outBuffer = (LPVOID)jlong_to_ptr(bufferAddress); + + if (DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, outBuffer, (DWORD)bufferSize, + &bytesReturned, NULL) == 0) + { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_DeleteFile0(JNIEnv* env, jclass this, jlong address) +{ + LPCWSTR lpFileName = jlong_to_ptr(address); + if (DeleteFileW(lpFileName) == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_CreateDirectory0(JNIEnv* env, jclass this, + jlong address, jlong sdAddress) +{ + LPCWSTR lpFileName = jlong_to_ptr(address); + + SECURITY_ATTRIBUTES securityAttributes; + LPSECURITY_ATTRIBUTES lpSecurityAttributes; + PSECURITY_DESCRIPTOR lpSecurityDescriptor = jlong_to_ptr(sdAddress); + + + if (lpSecurityDescriptor == NULL) { + lpSecurityAttributes = NULL; + } else { + securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + securityAttributes.lpSecurityDescriptor = lpSecurityDescriptor; + securityAttributes.bInheritHandle = FALSE; + lpSecurityAttributes = &securityAttributes; + } + + if (CreateDirectoryW(lpFileName, lpSecurityAttributes) == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_RemoveDirectory0(JNIEnv* env, jclass this, jlong address) +{ + LPCWSTR lpFileName = jlong_to_ptr(address); + if (RemoveDirectoryW(lpFileName) == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_CloseHandle(JNIEnv* env, jclass this, + jlong handle) +{ + HANDLE h = (HANDLE)jlong_to_ptr(handle); + CloseHandle(h); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile0(JNIEnv* env, jclass this, + jlong address, jobject obj) +{ + WIN32_FIND_DATAW data; + LPCWSTR lpFileName = jlong_to_ptr(address); + + HANDLE handle = FindFirstFileW(lpFileName, &data); + if (handle != INVALID_HANDLE_VALUE) { + jstring name = (*env)->NewString(env, data.cFileName, wcslen(data.cFileName)); + if (name == NULL) + return; + (*env)->SetLongField(env, obj, findFirst_handle, ptr_to_jlong(handle)); + (*env)->SetObjectField(env, obj, findFirst_name, name); + } else { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile1(JNIEnv* env, jclass this, + jlong pathAddress, jlong dataAddress) +{ + LPCWSTR lpFileName = jlong_to_ptr(pathAddress); + WIN32_FIND_DATAW* data = (WIN32_FIND_DATAW*)jlong_to_ptr(dataAddress); + + HANDLE handle = FindFirstFileW(lpFileName, data); + if (handle == INVALID_HANDLE_VALUE) { + throwWindowsException(env, GetLastError()); + } + return ptr_to_jlong(handle); +} + +JNIEXPORT jstring JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_FindNextFile(JNIEnv* env, jclass this, + jlong handle, jlong dataAddress) +{ + HANDLE h = (HANDLE)jlong_to_ptr(handle); + WIN32_FIND_DATAW* data = (WIN32_FIND_DATAW*)jlong_to_ptr(dataAddress); + + if (FindNextFileW(h, data) != 0) { + return (*env)->NewString(env, data->cFileName, wcslen(data->cFileName)); + } else { + if (GetLastError() != ERROR_NO_MORE_FILES) + throwWindowsException(env, GetLastError()); + return NULL; + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstStream0(JNIEnv* env, jclass this, + jlong address, jobject obj) +{ + MY_WIN32_FIND_STREAM_DATA data; + LPCWSTR lpFileName = jlong_to_ptr(address); + HANDLE handle; + + if (FindFirstStream_func == NULL) { + JNU_ThrowInternalError(env, "Should not get here"); + return; + } + + handle = (*FindFirstStream_func)(lpFileName, FindStreamInfoStandard, &data, 0); + if (handle != INVALID_HANDLE_VALUE) { + jstring name = (*env)->NewString(env, data.cStreamName, wcslen(data.cStreamName)); + if (name == NULL) + return; + (*env)->SetLongField(env, obj, findStream_handle, ptr_to_jlong(handle)); + (*env)->SetObjectField(env, obj, findStream_name, name); + } else { + if (GetLastError() == ERROR_HANDLE_EOF) { + (*env)->SetLongField(env, obj, findStream_handle, ptr_to_jlong(handle)); + } else { + throwWindowsException(env, GetLastError()); + } + } + +} + +JNIEXPORT jstring JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_FindNextStream(JNIEnv* env, jclass this, + jlong handle) +{ + MY_WIN32_FIND_STREAM_DATA data; + HANDLE h = (HANDLE)jlong_to_ptr(handle); + + if (FindNextStream_func == NULL) { + JNU_ThrowInternalError(env, "Should not get here"); + return NULL; + } + + if ((*FindNextStream_func)(h, &data) != 0) { + return (*env)->NewString(env, data.cStreamName, wcslen(data.cStreamName)); + } else { + if (GetLastError() != ERROR_HANDLE_EOF) + throwWindowsException(env, GetLastError()); + return NULL; + } +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_FindClose(JNIEnv* env, jclass this, + jlong handle) +{ + HANDLE h = (HANDLE)jlong_to_ptr(handle); + if (FindClose(h) == 0) { + throwWindowsException(env, GetLastError()); + } +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetFileInformationByHandle(JNIEnv* env, jclass this, + jlong handle, jlong address) +{ + HANDLE h = (HANDLE)jlong_to_ptr(handle); + BY_HANDLE_FILE_INFORMATION* info = + (BY_HANDLE_FILE_INFORMATION*)jlong_to_ptr(address); + if (GetFileInformationByHandle(h, info) == 0) { + throwWindowsException(env, GetLastError()); + } +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_CopyFileEx0(JNIEnv* env, jclass this, + jlong existingAddress, jlong newAddress, jint flags, jlong cancelAddress) +{ + LPCWSTR lpExistingFileName = jlong_to_ptr(existingAddress); + LPCWSTR lpNewFileName = jlong_to_ptr(newAddress); + LPBOOL cancel = (LPBOOL)jlong_to_ptr(cancelAddress); + if (CopyFileExW(lpExistingFileName, lpNewFileName, NULL, NULL, cancel, + (DWORD)flags) == 0) + { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_MoveFileEx0(JNIEnv* env, jclass this, + jlong existingAddress, jlong newAddress, jint flags) +{ + LPCWSTR lpExistingFileName = jlong_to_ptr(existingAddress); + LPCWSTR lpNewFileName = jlong_to_ptr(newAddress); + if (MoveFileExW(lpExistingFileName, lpNewFileName, (DWORD)flags) == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetLogicalDrives(JNIEnv* env, jclass this) +{ + DWORD res = GetLogicalDrives(); + if (res == 0) { + throwWindowsException(env, GetLastError()); + } + return (jint)res; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetFileAttributes0(JNIEnv* env, jclass this, + jlong address) +{ + LPCWSTR lpFileName = jlong_to_ptr(address); + DWORD value = GetFileAttributesW(lpFileName); + + if (value == INVALID_FILE_ATTRIBUTES) { + throwWindowsException(env, GetLastError()); + } + return (jint)value; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_SetFileAttributes0(JNIEnv* env, jclass this, + jlong address, jint value) +{ + LPCWSTR lpFileName = jlong_to_ptr(address); + if (SetFileAttributesW(lpFileName, (DWORD)value) == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetFileAttributesEx0(JNIEnv* env, jclass this, + jlong pathAddress, jlong dataAddress) +{ + LPCWSTR lpFileName = jlong_to_ptr(pathAddress); + WIN32_FILE_ATTRIBUTE_DATA* data = (WIN32_FILE_ATTRIBUTE_DATA*)jlong_to_ptr(dataAddress); + + BOOL res = GetFileAttributesExW(lpFileName, GetFileExInfoStandard, (LPVOID)data); + if (res == 0) + throwWindowsException(env, GetLastError()); +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_SetFileTime(JNIEnv* env, jclass this, + jlong handle, jlong createTime, jlong lastAccessTime, jlong lastWriteTime) +{ + HANDLE h = (HANDLE)jlong_to_ptr(handle); + + if (SetFileTime(h, + (createTime == (jlong)0) ? NULL : (CONST FILETIME *)&createTime, + (lastAccessTime == (jlong)0) ? NULL : (CONST FILETIME *)&lastAccessTime, + (lastWriteTime == (jlong)0) ? NULL : (CONST FILETIME *)&lastWriteTime) == 0) + { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_SetEndOfFile(JNIEnv* env, jclass this, + jlong handle) +{ + HANDLE h = (HANDLE)jlong_to_ptr(handle); + + if (SetEndOfFile(h) == 0) + throwWindowsException(env, GetLastError()); +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetVolumeInformation0(JNIEnv* env, jclass this, + jlong address, jobject obj) +{ + WCHAR volumeName[MAX_PATH+1]; + DWORD volumeSerialNumber; + DWORD maxComponentLength; + DWORD flags; + WCHAR fileSystemName[MAX_PATH+1]; + LPCWSTR lpFileName = jlong_to_ptr(address); + jstring str; + + BOOL res = GetVolumeInformationW(lpFileName, + &volumeName[0], + MAX_PATH+1, + &volumeSerialNumber, + &maxComponentLength, + &flags, + &fileSystemName[0], + MAX_PATH+1); + if (res == 0) { + throwWindowsException(env, GetLastError()); + return; + } + + str = (*env)->NewString(env, (const jchar *)fileSystemName, (jsize)wcslen(fileSystemName)); + if (str == NULL) return; + (*env)->SetObjectField(env, obj, volumeInfo_fsName, str); + + str = (*env)->NewString(env, (const jchar *)volumeName, (jsize)wcslen(volumeName)); + if (str == NULL) return; + (*env)->SetObjectField(env, obj, volumeInfo_volName, str); + + (*env)->SetIntField(env, obj, volumeInfo_volSN, (jint)volumeSerialNumber); + (*env)->SetIntField(env, obj, volumeInfo_flags, (jint)flags); +} + + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetDriveType0(JNIEnv* env, jclass this, jlong address) { + LPCWSTR lpRootPathName = jlong_to_ptr(address); + return (jint)GetDriveTypeW(lpRootPathName); +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetDiskFreeSpaceEx0(JNIEnv* env, jclass this, + jlong address, jobject obj) +{ + ULARGE_INTEGER freeBytesAvailable; + ULARGE_INTEGER totalNumberOfBytes; + ULARGE_INTEGER totalNumberOfFreeBytes; + LPCWSTR lpDirName = jlong_to_ptr(address); + + + BOOL res = GetDiskFreeSpaceExW(lpDirName, + &freeBytesAvailable, + &totalNumberOfBytes, + &totalNumberOfFreeBytes); + if (res == 0) { + throwWindowsException(env, GetLastError()); + return; + } + + (*env)->SetLongField(env, obj, diskSpace_bytesAvailable, + long_to_jlong(freeBytesAvailable.QuadPart)); + (*env)->SetLongField(env, obj, diskSpace_totalBytes, + long_to_jlong(totalNumberOfBytes.QuadPart)); + (*env)->SetLongField(env, obj, diskSpace_totalFree, + long_to_jlong(totalNumberOfFreeBytes.QuadPart)); +} + + +JNIEXPORT jstring JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetVolumePathName0(JNIEnv* env, jclass this, + jlong address) +{ + WCHAR volumeName[MAX_PATH+1]; + LPCWSTR lpFileName = jlong_to_ptr(address); + + + BOOL res = GetVolumePathNameW(lpFileName, + &volumeName[0], + MAX_PATH+1); + if (res == 0) { + throwWindowsException(env, GetLastError()); + return NULL; + } else { + return (*env)->NewString(env, (const jchar *)volumeName, (jsize)wcslen(volumeName)); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_InitializeSecurityDescriptor(JNIEnv* env, jclass this, + jlong address) +{ + PSECURITY_DESCRIPTOR pSecurityDescriptor = + (PSECURITY_DESCRIPTOR)jlong_to_ptr(address); + + if (InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_InitializeAcl(JNIEnv* env, jclass this, + jlong address, jint size) +{ + PACL pAcl = (PACL)jlong_to_ptr(address); + + if (InitializeAcl(pAcl, (DWORD)size, ACL_REVISION) == 0) { + throwWindowsException(env, GetLastError()); + } +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_SetFileSecurity0(JNIEnv* env, jclass this, + jlong pathAddress, jint requestedInformation, jlong descAddress) +{ + LPCWSTR lpFileName = jlong_to_ptr(pathAddress); + PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(descAddress); + DWORD lengthNeeded = 0; + + BOOL res = SetFileSecurityW(lpFileName, + (SECURITY_INFORMATION)requestedInformation, + pSecurityDescriptor); + + if (res == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetFileSecurity0(JNIEnv* env, jclass this, + jlong pathAddress, jint requestedInformation, jlong descAddress, jint nLength) +{ + LPCWSTR lpFileName = jlong_to_ptr(pathAddress); + PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(descAddress); + DWORD lengthNeeded = 0; + + BOOL res = GetFileSecurityW(lpFileName, + (SECURITY_INFORMATION)requestedInformation, + pSecurityDescriptor, + (DWORD)nLength, + &lengthNeeded); + + if (res == 0) { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + return (jint)lengthNeeded; + } else { + throwWindowsException(env, GetLastError()); + return 0; + } + } else { + return (jint)nLength; + } +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetSecurityDescriptorOwner(JNIEnv* env, + jclass this, jlong address) +{ + PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(address); + PSID pOwner; + BOOL bOwnerDefaulted; + + + if (GetSecurityDescriptorOwner(pSecurityDescriptor, &pOwner, &bOwnerDefaulted) == 0) { + throwWindowsException(env, GetLastError()); + } + return ptr_to_jlong(pOwner); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_SetSecurityDescriptorOwner(JNIEnv* env, + jclass this, jlong descAddress, jlong ownerAddress) +{ + PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(descAddress); + PSID pOwner = jlong_to_ptr(ownerAddress); + + if (SetSecurityDescriptorOwner(pSecurityDescriptor, pOwner, FALSE) == 0) { + throwWindowsException(env, GetLastError()); + } +} + + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetSecurityDescriptorDacl(JNIEnv* env, + jclass this, jlong address) +{ + PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(address); + BOOL bDaclPresent; + PACL pDacl; + BOOL bDaclDefaulted; + + if (GetSecurityDescriptorDacl(pSecurityDescriptor, &bDaclPresent, &pDacl, &bDaclDefaulted) == 0) { + throwWindowsException(env, GetLastError()); + return (jlong)0; + } else { + return (bDaclPresent) ? ptr_to_jlong(pDacl) : (jlong)0; + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_SetSecurityDescriptorDacl(JNIEnv* env, + jclass this, jlong descAddress, jlong aclAddress) +{ + PSECURITY_DESCRIPTOR pSecurityDescriptor = (PSECURITY_DESCRIPTOR)jlong_to_ptr(descAddress); + PACL pAcl = (PACL)jlong_to_ptr(aclAddress); + + if (SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, pAcl, FALSE) == 0) { + throwWindowsException(env, GetLastError()); + } +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetAclInformation0(JNIEnv* env, + jclass this, jlong address, jobject obj) +{ + PACL pAcl = (PACL)jlong_to_ptr(address); + ACL_SIZE_INFORMATION acl_size_info; + + if (GetAclInformation(pAcl, (void *) &acl_size_info, sizeof(acl_size_info), AclSizeInformation) == 0) { + throwWindowsException(env, GetLastError()); + } else { + (*env)->SetIntField(env, obj, aclInfo_aceCount, (jint)acl_size_info.AceCount); + } +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetAce(JNIEnv* env, jclass this, jlong address, + jint aceIndex) +{ + PACL pAcl = (PACL)jlong_to_ptr(address); + LPVOID pAce; + + if (GetAce(pAcl, (DWORD)aceIndex, &pAce) == 0) { + throwWindowsException(env, GetLastError()); + return (jlong)0; + } else { + return ptr_to_jlong(pAce); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_AddAccessAllowedAceEx(JNIEnv* env, + jclass this, jlong aclAddress, jint flags, jint mask, jlong sidAddress) +{ + PACL pAcl = (PACL)jlong_to_ptr(aclAddress); + PSID pSid = (PSID)jlong_to_ptr(sidAddress); + + if (AddAccessAllowedAceEx(pAcl, ACL_REVISION, (DWORD)flags, (DWORD)mask, pSid) == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_AddAccessDeniedAceEx(JNIEnv* env, + jclass this, jlong aclAddress, jint flags, jint mask, jlong sidAddress) +{ + PACL pAcl = (PACL)jlong_to_ptr(aclAddress); + PSID pSid = (PSID)jlong_to_ptr(sidAddress); + + if (AddAccessDeniedAceEx(pAcl, ACL_REVISION, (DWORD)flags, (DWORD)mask, pSid) == 0) { + throwWindowsException(env, GetLastError()); + } +} + + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_LookupAccountSid0(JNIEnv* env, + jclass this, jlong address, jobject obj) +{ + WCHAR domain[255]; + WCHAR name[255]; + DWORD domainLen = sizeof(domain); + DWORD nameLen = sizeof(name); + SID_NAME_USE use; + PSID sid = jlong_to_ptr(address); + jstring s; + + if (LookupAccountSidW(NULL, sid, &name[0], &nameLen, &domain[0], &domainLen, &use) == 0) { + throwWindowsException(env, GetLastError()); + return; + } + + s = (*env)->NewString(env, (const jchar *)domain, (jsize)wcslen(domain)); + if (s == NULL) + return; + (*env)->SetObjectField(env, obj, account_domain, s); + + s = (*env)->NewString(env, (const jchar *)name, (jsize)wcslen(name)); + if (s == NULL) + return; + (*env)->SetObjectField(env, obj, account_name, s); + (*env)->SetIntField(env, obj, account_use, (jint)use); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_LookupAccountName0(JNIEnv* env, + jclass this, jlong nameAddress, jlong sidAddress, jint cbSid) +{ + + LPCWSTR accountName = jlong_to_ptr(nameAddress); + PSID sid = jlong_to_ptr(sidAddress); + WCHAR domain[255]; + DWORD domainLen = sizeof(domain); + SID_NAME_USE use; + + if (LookupAccountNameW(NULL, accountName, sid, (LPDWORD)&cbSid, + &domain[0], &domainLen, &use) == 0) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + throwWindowsException(env, GetLastError()); + } + } + + return cbSid; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetLengthSid(JNIEnv* env, + jclass this, jlong address) +{ + PSID sid = jlong_to_ptr(address); + + if (GetLengthSid_func == NULL) { + JNU_ThrowInternalError(env, "Should not get here"); + return 0; + } + return (jint)(*GetLengthSid_func)(sid); +} + + +JNIEXPORT jstring JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_ConvertSidToStringSid(JNIEnv* env, + jclass this, jlong address) +{ + PSID sid = jlong_to_ptr(address); + LPWSTR string; + + if (ConvertSidToStringSid_func == NULL) { + JNU_ThrowInternalError(env, "Should not get here"); + return NULL; + } + + if ((*ConvertSidToStringSid_func)(sid, &string) == 0) { + throwWindowsException(env, GetLastError()); + return NULL; + } else { + jstring s = (*env)->NewString(env, (const jchar *)string, + (jsize)wcslen(string)); + LocalFree(string); + return s; + } +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_ConvertStringSidToSid0(JNIEnv* env, + jclass this, jlong address) +{ + LPWSTR lpStringSid = jlong_to_ptr(address); + PSID pSid; + + if (ConvertStringSidToSid_func == NULL) { + JNU_ThrowInternalError(env, "Should not get here"); + return (jlong)0; + } + + if ((*ConvertStringSidToSid_func)(lpStringSid, &pSid) == 0) + throwWindowsException(env, GetLastError()); + + return ptr_to_jlong(pSid); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetCurrentProcess(JNIEnv* env, jclass this) { + HANDLE hProcess = GetCurrentProcess(); + return ptr_to_jlong(hProcess); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetCurrentThread(JNIEnv* env, jclass this) { + HANDLE hThread = GetCurrentThread(); + return ptr_to_jlong(hThread); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_OpenProcessToken(JNIEnv* env, + jclass this, jlong process, jint desiredAccess) +{ + HANDLE hProcess = (HANDLE)jlong_to_ptr(process); + HANDLE hToken; + + if (OpenProcessToken(hProcess, (DWORD)desiredAccess, &hToken) == 0) + throwWindowsException(env, GetLastError()); + return ptr_to_jlong(hToken); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_OpenThreadToken(JNIEnv* env, + jclass this, jlong thread, jint desiredAccess, jboolean openAsSelf) +{ + HANDLE hThread = (HANDLE)jlong_to_ptr(thread); + HANDLE hToken; + BOOL bOpenAsSelf = (openAsSelf == JNI_TRUE) ? TRUE : FALSE; + + if (OpenThreadToken(hThread, (DWORD)desiredAccess, bOpenAsSelf, &hToken) == 0) { + if (GetLastError() == ERROR_NO_TOKEN) + return (jlong)0; + throwWindowsException(env, GetLastError()); + } + return ptr_to_jlong(hToken); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_DuplicateTokenEx(JNIEnv* env, + jclass this, jlong token, jint desiredAccess) +{ + HANDLE hToken = (HANDLE)jlong_to_ptr(token); + HANDLE resultToken; + BOOL res; + + res = DuplicateTokenEx(hToken, + (DWORD)desiredAccess, + NULL, + SecurityImpersonation, + TokenImpersonation, + &resultToken); + if (res == 0) + throwWindowsException(env, GetLastError()); + return ptr_to_jlong(resultToken); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_SetThreadToken(JNIEnv* env, + jclass this, jlong thread, jlong token) +{ + HANDLE hThread = (HANDLE)jlong_to_ptr(thread); + HANDLE hToken = (HANDLE)jlong_to_ptr(token); + + if (SetThreadToken(hThread, hToken) == 0) + throwWindowsException(env, GetLastError()); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetTokenInformation(JNIEnv* env, + jclass this, jlong token, jint tokenInfoClass, jlong tokenInfo, jint tokenInfoLength) +{ + BOOL res; + DWORD lengthNeeded; + HANDLE hToken = (HANDLE)jlong_to_ptr(token); + LPVOID result = (LPVOID)jlong_to_ptr(tokenInfo); + + res = GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)tokenInfoClass, (LPVOID)result, + tokenInfoLength, &lengthNeeded); + if (res == 0) { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + return (jint)lengthNeeded; + } else { + throwWindowsException(env, GetLastError()); + return 0; + } + } else { + return tokenInfoLength; + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_AdjustTokenPrivileges(JNIEnv* env, + jclass this, jlong token, jlong luid, jint attributes) +{ + TOKEN_PRIVILEGES privs[1]; + HANDLE hToken = (HANDLE)jlong_to_ptr(token); + PLUID pLuid = (PLUID)jlong_to_ptr(luid); + + privs[0].PrivilegeCount = 1; + privs[0].Privileges[0].Luid = *pLuid; + privs[0].Privileges[0].Attributes = (DWORD)attributes; + + if (AdjustTokenPrivileges(hToken, FALSE, &privs[0], 1, NULL, NULL) == 0) + throwWindowsException(env, GetLastError()); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_LookupPrivilegeValue0(JNIEnv* env, + jclass this, jlong name) +{ + LPCWSTR lpName = (LPCWSTR)jlong_to_ptr(name); + PLUID pLuid = LocalAlloc(0, sizeof(LUID)); + + if (pLuid == NULL) { + JNU_ThrowInternalError(env, "Unable to allocate LUID structure"); + } else { + if (LookupPrivilegeValueW(NULL, lpName, pLuid) == 0) + throwWindowsException(env, GetLastError()); + } + return ptr_to_jlong(pLuid); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_BuildTrusteeWithSid(JNIEnv* env, + jclass this, jlong sid) +{ + PSID pSid = (HANDLE)jlong_to_ptr(sid); + PTRUSTEE_W pTrustee = LocalAlloc(0, sizeof(TRUSTEE_W)); + + if (pTrustee == NULL) { + JNU_ThrowInternalError(env, "Unable to allocate TRUSTEE_W structure"); + } else { + BuildTrusteeWithSidW(pTrustee, pSid); + } + return ptr_to_jlong(pTrustee); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetEffectiveRightsFromAcl(JNIEnv* env, + jclass this, jlong acl, jlong trustee) +{ + ACCESS_MASK access; + PACL pAcl = (PACL)jlong_to_ptr(acl); + PTRUSTEE pTrustee = (PTRUSTEE)jlong_to_ptr(trustee); + + if (GetEffectiveRightsFromAcl(pAcl, pTrustee, &access) != ERROR_SUCCESS) { + throwWindowsException(env, GetLastError()); + } + return (jint)access; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_CreateSymbolicLink0(JNIEnv* env, + jclass this, jlong linkAddress, jlong targetAddress, jint flags) +{ + LPCWSTR link = jlong_to_ptr(linkAddress); + LPCWSTR target = jlong_to_ptr(targetAddress); + + if (CreateSymbolicLink_func == NULL) { + JNU_ThrowInternalError(env, "Should not get here"); + return; + } + + /* On Windows 64-bit this appears to succeed even when there is insufficient privileges */ + if ((*CreateSymbolicLink_func)(link, target, (DWORD)flags) == 0) + throwWindowsException(env, GetLastError()); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_CreateHardLink0(JNIEnv* env, + jclass this, jlong newFileAddress, jlong existingFileAddress) +{ + LPCWSTR newFile = jlong_to_ptr(newFileAddress); + LPCWSTR existingFile = jlong_to_ptr(existingFileAddress); + + if (CreateHardLink_func == NULL) { + JNU_ThrowInternalError(env, "Should not get here"); + return; + } + if ((*CreateHardLink_func)(newFile, existingFile, NULL) == 0) + throwWindowsException(env, GetLastError()); +} + +JNIEXPORT jstring JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetFullPathName0(JNIEnv *env, + jclass clz, + jlong pathAddress) +{ + jstring rv = NULL; + WCHAR *lpBuf = NULL; + WCHAR buf[MAX_PATH]; + DWORD len; + LPCWSTR lpFileName = jlong_to_ptr(pathAddress); + + len = GetFullPathNameW(lpFileName, MAX_PATH, buf, NULL); + if (len > 0) { + if (len < MAX_PATH) { + rv = (*env)->NewString(env, buf, len); + } else { + len += 1; /* return length does not include terminator */ + lpBuf = (WCHAR*)malloc(len * sizeof(WCHAR)); + if (lpBuf != NULL) { + len = GetFullPathNameW(lpFileName, len, lpBuf, NULL); + if (len > 0) { + rv = (*env)->NewString(env, lpBuf, len); + } else { + JNU_ThrowInternalError(env, "GetFullPathNameW failed"); + } + free(lpBuf); + } + } + } + if (len == 0) + throwWindowsException(env, GetLastError()); + + return rv; +} + +JNIEXPORT jstring JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env, + jclass this, jlong handle) +{ + jstring rv = NULL; + WCHAR *lpBuf = NULL; + WCHAR path[MAX_PATH]; + HANDLE h = (HANDLE)jlong_to_ptr(handle); + DWORD len; + + if (GetFinalPathNameByHandle_func == NULL) { + JNU_ThrowInternalError(env, "Should not get here"); + return NULL; + } + + len = (*GetFinalPathNameByHandle_func)(h, path, MAX_PATH, 0); + if (len > 0) { + if (len < MAX_PATH) { + rv = (*env)->NewString(env, (const jchar *)path, (jsize)len); + } else { + len += 1; /* return length does not include terminator */ + lpBuf = (WCHAR*)malloc(len * sizeof(WCHAR)); + if (lpBuf != NULL) { + len = (*GetFinalPathNameByHandle_func)(h, lpBuf, len, 0); + if (len > 0) { + rv = (*env)->NewString(env, (const jchar *)lpBuf, (jsize)len); + } else { + JNU_ThrowInternalError(env, "GetFinalPathNameByHandleW failed"); + } + free(lpBuf); + } + } + } + + if (len == 0) + throwWindowsException(env, GetLastError()); + + return rv; +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_CreateIoCompletionPort(JNIEnv* env, jclass this, + jlong fileHandle, jlong existingPort, jint completionKey) +{ + HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(fileHandle), + (HANDLE)jlong_to_ptr(existingPort), + (DWORD)completionKey, + 0); + if (port == NULL) { + throwWindowsException(env, GetLastError()); + } + return ptr_to_jlong(port); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_GetQueuedCompletionStatus0(JNIEnv* env, jclass this, + jlong completionPort, jobject obj) +{ + DWORD bytesTransferred; + DWORD completionKey; + OVERLAPPED *lpOverlapped; + BOOL res; + + res = GetQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort), + &bytesTransferred, + &completionKey, + &lpOverlapped, + INFINITE); + if (res == 0 && lpOverlapped == NULL) { + throwWindowsException(env, GetLastError()); + } else { + DWORD ioResult = (res == 0) ? GetLastError() : 0; + (*env)->SetIntField(env, obj, completionStatus_error, ioResult); + (*env)->SetIntField(env, obj, completionStatus_bytesTransferred, + (jint)bytesTransferred); + (*env)->SetIntField(env, obj, completionStatus_completionKey, + (jint)completionKey); + + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env, jclass this, + jlong completionPort, jint completionKey) +{ + BOOL res; + + res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort), + (DWORD)0, /* dwNumberOfBytesTransferred */ + (DWORD)completionKey, + NULL); /* lpOverlapped */ + if (res == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW(JNIEnv* env, jclass this, + jlong hDirectory, jlong bufferAddress, jint bufferLength, jboolean watchSubTree, jint filter, + jlong bytesReturnedAddress, jlong pOverlapped) +{ + BOOL res; + BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE; + + ((LPOVERLAPPED)jlong_to_ptr(pOverlapped))->hEvent = NULL; + res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory), + (LPVOID)jlong_to_ptr(bufferAddress), + (DWORD)bufferLength, + subtree, + (DWORD)filter, + (LPDWORD)jlong_to_ptr(bytesReturnedAddress), + (LPOVERLAPPED)jlong_to_ptr(pOverlapped), + NULL); + if (res == 0) { + throwWindowsException(env, GetLastError()); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_BackupRead0(JNIEnv* env, jclass this, + jlong hFile, jlong bufferAddress, jint bufferSize, jboolean abort, + jlong context, jobject obj) +{ + BOOL res; + DWORD bytesTransferred; + BOOL a = (abort == JNI_TRUE) ? TRUE : FALSE; + VOID* pContext = (VOID*)jlong_to_ptr(context); + + res = BackupRead((HANDLE)jlong_to_ptr(hFile), + (LPBYTE)jlong_to_ptr(bufferAddress), + (DWORD)bufferSize, + &bytesTransferred, + a, + FALSE, + &pContext); + if (res == 0) { + throwWindowsException(env, GetLastError()); + } else { + (*env)->SetIntField(env, obj, backupResult_bytesTransferred, + bytesTransferred); + (*env)->SetLongField(env, obj, backupResult_context, + ptr_to_jlong(pContext)); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_BackupSeek(JNIEnv* env, jclass this, + jlong hFile, jlong bytesToSeek, jlong context) +{ + BOOL res; + jint lowBytesToSeek = (jint)bytesToSeek; + jint highBytesToSeek = (jint)(bytesToSeek >> 32); + DWORD lowBytesSeeked; + DWORD highBytesSeeked; + VOID* pContext = jlong_to_ptr(context); + + res = BackupSeek((HANDLE)jlong_to_ptr(hFile), + (DWORD)lowBytesToSeek, + (DWORD)highBytesToSeek, + &lowBytesSeeked, + &highBytesSeeked, + &pContext); + if (res == 0) { + throwWindowsException(env, GetLastError()); + } +} diff --git a/jdk/src/windows/native/sun/windows/ShellFolder2.cpp b/jdk/src/windows/native/sun/windows/ShellFolder2.cpp index 3baf5bcf9b9..6799b098218 100644 --- a/jdk/src/windows/native/sun/windows/ShellFolder2.cpp +++ b/jdk/src/windows/native/sun/windows/ShellFolder2.cpp @@ -225,6 +225,34 @@ JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_initIDs FID_folderType = env->GetFieldID(cls, "folderType", "Ljava/lang/String;"); } + +/* +* Class: sun_awt_shell_Win32ShellFolderManager2 +* Method: initializeCom +* Signature: ()V +*/ +JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolderManager2_initializeCom + (JNIEnv* env, jclass cls) +{ + HRESULT hr = ::CoInitialize(NULL); + if (FAILED(hr)) { + char c[64]; + sprintf(c, "Could not initialize COM: HRESULT=0x%08X", hr); + JNU_ThrowInternalError(env, c); + } +} + +/* +* Class: sun_awt_shell_Win32ShellFolderManager2 +* Method: uninitializeCom +* Signature: ()V +*/ +JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolderManager2_uninitializeCom + (JNIEnv* env, jclass cls) +{ + ::CoUninitialize(); +} + static IShellIcon* getIShellIcon(IShellFolder* pIShellFolder) { // http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp HRESULT hres; @@ -239,29 +267,6 @@ static IShellIcon* getIShellIcon(IShellFolder* pIShellFolder) { return (IShellIcon*)NULL; } -// Fixed 6263669 -// -// CoInitialize wrapper -// call CoInitialize to initialize COM in STA mode and check result -// RPC_E_CHANGED_MODE means COM has already been initialized in MTA mode, -// so don't set the flag to call CoUninitialize later - -BOOL CoInit(BOOL& doCoUninit) { // returns TRUE if initialized successfully - switch(::CoInitialize(NULL)) { - case S_OK: - case S_FALSE: - doCoUninit = TRUE; - return TRUE; - break; - case RPC_E_CHANGED_MODE: - doCoUninit = FALSE; - return TRUE; - break; - default: - return FALSE; - } -} - /* * Class: sun_awt_shell_Win32ShellFolder2 @@ -507,10 +512,10 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getAttributes0 /* * Class: sun_awt_shell_Win32ShellFolder2 - * Method: getFileSystemPath + * Method: getFileSystemPath0 * Signature: (I)Ljava/lang/String; */ -JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileSystemPath__I +JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileSystemPath0 (JNIEnv* env, jclass cls, jint csidl) { LPITEMIDLIST relPIDL; @@ -611,18 +616,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_bindToObject if (SUCCEEDED (hr)) { return (jlong)pFolder; } - if (IS_WINVISTA) { - BOOL doCoUninit; - if (CoInit(doCoUninit)) { - hr = pParent->BindToObject(pidl, NULL, IID_IShellFolder, (void**)&pFolder); - if (doCoUninit) { - ::CoUninitialize(); - } - if (SUCCEEDED (hr)) { - return (jlong)pFolder; - } - } - } return 0; } @@ -650,7 +643,10 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation return NULL; } - pParent->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_FORPARSING, &strret); + hres = pParent->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_FORPARSING, &strret); + if (FAILED(hres)) { + return NULL; + } switch (strret.uType) { case STRRET_CSTR : @@ -669,10 +665,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation break; } - BOOL doCoUninit; - if (!CoInit(doCoUninit)) { - return 0; - } IShellLinkW* psl; hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID *)&psl); if (SUCCEEDED(hres)) { @@ -692,10 +684,10 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation } psl->Release(); } - if (doCoUninit) { - ::CoUninitialize(); - } + if (strret.uType == STRRET_WSTR) { + CoTaskMemFree(strret.pOleStr); + } if (SUCCEEDED(hres)) { return (jlong)pidl; } else { @@ -741,7 +733,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_parseDisplayName0 /* * Class: sun_awt_shell_Win32ShellFolder2 * Method: getDisplayNameOf - * Signature: (JJ)Ljava/lang/String; + * Signature: (JJI)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getDisplayNameOf (JNIEnv* env, jclass cls, jlong parentIShellFolder, jlong relativePIDL, jint attrs) @@ -758,7 +750,11 @@ JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getDisplayNameOf if (pParent->GetDisplayNameOf(pidl, attrs, &strret) != S_OK) { return NULL; } - return jstringFromSTRRET(env, pidl, &strret); + jstring result = jstringFromSTRRET(env, pidl, &strret); + if (strret.uType == STRRET_WSTR) { + CoTaskMemFree(strret.pOleStr); + } + return result; } /* @@ -833,10 +829,6 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex } INT index = -1; - BOOL doCoUninit; - if (!CoInit(doCoUninit)) { - return (jint)index; - } HRESULT hres; // http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp @@ -844,9 +836,6 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex hres = pIShellIcon->GetIconOf(pidl, GIL_FORSHELL, &index); } - if (doCoUninit) { - ::CoUninitialize(); - } return (jint)index; } @@ -866,10 +855,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon } HICON hIcon = NULL; - BOOL doCoUninit; - if (!CoInit(doCoUninit)) { - return (jlong)hIcon; - } HRESULT hres; IExtractIconW* pIcon; @@ -894,9 +879,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon } pIcon->Release(); } - if (doCoUninit) { - ::CoUninitialize(); - } return (jlong)hIcon; } @@ -994,14 +976,10 @@ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileChooserB HINSTANCE libComCtl32; HINSTANCE libShell32; - libShell32 = LoadLibrary(TEXT("shell32.dll")); if (libShell32 != NULL) { - long osVersion = GetVersion(); - BOOL isVista = (!(osVersion & 0x80000000) && (LOBYTE(LOWORD(osVersion)) >= 6)); - hBitmap = (HBITMAP)LoadImage(libShell32, - isVista ? TEXT("IDB_TB_SH_DEF_16") : MAKEINTRESOURCE(216), + IS_WINVISTA ? TEXT("IDB_TB_SH_DEF_16") : MAKEINTRESOURCE(216), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); } if (hBitmap == NULL) { @@ -1095,46 +1073,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource } -// Helper functions for workaround COM initialization: - -static HRESULT GetDetailsOfFolder( - IShellFolder2 *folder, - LPCITEMIDLIST pidl, - UINT column, - SHELLDETAILS *psd) -{ - HRESULT hr = folder->GetDetailsOf(pidl, column, psd); - if (IS_WINVISTA && FAILED (hr)) { - BOOL doCoUninit; - if (CoInit(doCoUninit)) { - hr = folder->GetDetailsOf(pidl, column, psd); - if (doCoUninit) { - ::CoUninitialize(); - } - } - } - return hr; -} - -static HRESULT GetDetailsOf( - IShellDetails *details, - LPCITEMIDLIST pidl, - UINT column, - SHELLDETAILS *psd) -{ - HRESULT hr = details->GetDetailsOf(pidl, column, psd); - if (IS_WINVISTA && FAILED (hr)) { - BOOL doCoUninit; - if (CoInit(doCoUninit)) { - hr = details->GetDetailsOf(pidl, column, psd); - if (doCoUninit) { - ::CoUninitialize(); - } - } - } - return hr; -} - /* * Helper function for creating Java column info object */ @@ -1187,7 +1125,7 @@ JNIEXPORT jobjectArray JNICALL int colNum = -1; hr = S_OK; do{ - hr = GetDetailsOfFolder(pIShellFolder2, NULL, ++colNum, &sd); + hr = pIShellFolder2->GetDetailsOf(NULL, ++colNum, &sd); } while (SUCCEEDED (hr)); jobjectArray columns = @@ -1202,7 +1140,7 @@ JNIEXPORT jobjectArray JNICALL colNum = 0; hr = S_OK; while (SUCCEEDED (hr)) { - hr = GetDetailsOfFolder(pIShellFolder2, NULL, colNum, &sd); + hr = pIShellFolder2->GetDetailsOf(NULL, colNum, &sd); if (SUCCEEDED (hr)) { hr = pIShellFolder2->GetDefaultColumnState(colNum, &csFlags); @@ -1232,7 +1170,7 @@ JNIEXPORT jobjectArray JNICALL int colNum = -1; hr = S_OK; do{ - hr = GetDetailsOf(pIShellDetails, NULL, ++colNum, &sd); + hr = pIShellDetails->GetDetailsOf(NULL, ++colNum, &sd); } while (SUCCEEDED (hr)); jobjectArray columns = @@ -1246,7 +1184,7 @@ JNIEXPORT jobjectArray JNICALL colNum = 0; hr = S_OK; while (SUCCEEDED (hr)) { - hr = GetDetailsOf(pIShellDetails, NULL, colNum, &sd); + hr = pIShellDetails->GetDetailsOf(NULL, colNum, &sd); if (SUCCEEDED (hr)) { jobject column = CreateColumnInfo(env, &columnClass, &columnConstructor, @@ -1288,7 +1226,7 @@ JNIEXPORT jobject JNICALL if(SUCCEEDED (hr)) { // The folder exposes IShellFolder2 interface IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown; - hr = GetDetailsOfFolder(pIShellFolder2, pidl, (UINT)columnIdx, &sd); + hr = pIShellFolder2->GetDetailsOf(pidl, (UINT)columnIdx, &sd); pIShellFolder2->Release(); if (SUCCEEDED (hr)) { STRRET strRet = sd.str; @@ -1300,7 +1238,7 @@ JNIEXPORT jobject JNICALL if(SUCCEEDED (hr)) { // The folder exposes IShellDetails interface IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown; - hr = GetDetailsOf(pIShellDetails, pidl, (UINT)columnIdx, &sd); + hr = pIShellDetails->GetDetailsOf(pidl, (UINT)columnIdx, &sd); pIShellDetails->Release(); if (SUCCEEDED (hr)) { STRRET strRet = sd.str; diff --git a/jdk/src/windows/native/sun/windows/awt.rc b/jdk/src/windows/native/sun/windows/awt.rc index 2393b398cfc..7eb4d41afb1 100644 --- a/jdk/src/windows/native/sun/windows/awt.rc +++ b/jdk/src/windows/native/sun/windows/awt.rc @@ -23,7 +23,7 @@ // have any questions. // -#include "afxres.h" +#include "windows.h" // Need 2 defines so macro argument to XSTR will get expanded before quoting. #define XSTR(x) STR(x) diff --git a/jdk/src/windows/resource/version.rc b/jdk/src/windows/resource/version.rc index 61311efabcf..41479562435 100644 --- a/jdk/src/windows/resource/version.rc +++ b/jdk/src/windows/resource/version.rc @@ -23,7 +23,7 @@ // have any questions. // -#include "afxres.h" +#include "windows.h" // Need 2 defines so macro argument to XSTR will get expanded before quoting. #define XSTR(x) STR(x) diff --git a/jdk/test/Makefile b/jdk/test/Makefile index 5435bf0a614..775e7cbc913 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -1,12 +1,44 @@ # -# Makefile to run jtreg +# Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# Makefile to run various jdk tests # # Get OS/ARCH specifics OSNAME = $(shell uname -s) + +# Commands to run on paths to make mixed paths for java on windows +GETMIXEDPATH=echo + +# Location of developer shared files +SLASH_JAVA = /java + +# Platform specific settings ifeq ($(OSNAME), SunOS) PLATFORM = solaris - JCT_PLATFORM = solaris ARCH = $(shell uname -p) ifeq ($(ARCH), i386) ARCH=i586 @@ -14,97 +46,403 @@ ifeq ($(OSNAME), SunOS) endif ifeq ($(OSNAME), Linux) PLATFORM = linux - JCT_PLATFORM = linux ARCH = $(shell uname -m) ifeq ($(ARCH), i386) ARCH=i586 endif endif -ifeq ($(OSNAME), Windows_NT) + +# Cannot trust uname output +ifneq ($(PROCESSOR_IDENTIFIER), ) PLATFORM = windows - JCT_PLATFORM = win32 - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64) - ARCH=ia64 + SLASH_JAVA = J: + # A variety of ways to say X64 arch :^( + PROC_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) + PROC_ARCH:=$(subst x86,X86,$(PROC_ARCH)) + PROC_ARCH:=$(subst x64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst AMD64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst amd64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst EM64T,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst em64t,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst intel64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst Intel64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst INTEL64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst ia64,IA64,$(PROC_ARCH)) + ifeq ($(PROC_ARCH),IA64) + ARCH = ia64 else - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),AMD64) - ARCH=x64 + ifeq ($(PROC_ARCH),X64) + ARCH = x64 else - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),EM64T) - ARCH=x64 - else - ARCH=i586 - endif + ARCH = i586 endif endif + EXESUFFIX = .exe + # These need to be different depending on MKS or CYGWIN + ifeq ($(findstring cygdrive,$(shell (cd C:/ && pwd))), ) + GETMIXEDPATH=dosname -s + else + GETMIXEDPATH=cygpath -m -s + endif endif +# Utilities used +CD = cd +CP = cp +ECHO = echo +MKDIR = mkdir +ZIP = zip + # Root of this test area (important to use full paths in some places) TEST_ROOT := $(shell pwd) -# Default bundle of all test results (passed or not) -JPRT_ARCHIVE_BUNDLE=$(TEST_ROOT)/JPRT_ARCHIVE_BUNDLE.zip - -# Default home for JTREG -ifeq ($(PLATFORM), windows) - JT_HOME = J:/svc/jct-tools3.2.2_02 - JTREG_KEY_OPTION=-k:!ignore +# Root of all test results +ifdef ALT_OUTPUTDIR + ABS_OUTPUTDIR = $(ALT_OUTPUTDIR) else - JT_HOME = /java/svc/jct-tools3.2.2_02 - JTREG_KEY_OPTION=-k:\!ignore + ABS_OUTPUTDIR = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) +endif +ABS_BUILD_ROOT = $(ABS_OUTPUTDIR) +ABS_TEST_OUTPUT_DIR := $(ABS_BUILD_ROOT)/testoutput + +# Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test) +ifndef PRODUCT_HOME + # Try to use j2sdk-image if it exists + ABS_JDK_IMAGE = $(ABS_BUILD_ROOT)/j2sdk-image + PRODUCT_HOME := \ + $(shell \ + if [ -d $(ABS_JDK_IMAGE) ] ; then \ + $(ECHO) "$(ABS_JDK_IMAGE)"; \ + else \ + $(ECHO) "$(ABS_BUILD_ROOT)" ; \ + fi) + PRODUCT_HOME := $(PRODUCT_HOME) endif -# Default JTREG to run -JTREG = $(JT_HOME)/$(JCT_PLATFORM)/bin/jtreg +# Expect JPRT to set JPRT_PRODUCT_ARGS (e.g. -server etc.) +# Should be passed into 'java' only. +ifdef JPRT_PRODUCT_ARGS + JAVA_ARGS = $(JPRT_PRODUCT_ARGS) +endif -# Default JDK to test -JAVA_HOME = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) +# Expect JPRT to set JPRT_PRODUCT_VM_ARGS (e.g. -Xcomp etc.) +# Should be passed into anything running the vm (java, javac, javadoc, ...). +ifdef JPRT_PRODUCT_VM_ARGS + JAVA_VM_ARGS = $(JPRT_PRODUCT_VM_ARGS) +endif -# The test directories to run -DEFAULT_TESTDIRS = demo/jvmti/gctest demo/jvmti/hprof -TESTDIRS = $(DEFAULT_TESTDIRS) +# Expect JPRT to set JPRT_ARCHIVE_BUNDLE (path to zip bundle for results) +ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip +ifdef JPRT_ARCHIVE_BUNDLE + ARCHIVE_BUNDLE = $(JPRT_ARCHIVE_BUNDLE) +endif -# Root of all test results -JTREG_OUTPUT_DIR = $(TEST_ROOT)/o_$(PLATFORM)-$(ARCH) +# How to create the test bundle (pass or fail, we want to create this) +# Follow command with ";$(BUNDLE_UP_AND_EXIT)", so it always gets executed. +ZIP_UP_RESULTS = ( $(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)` \ + && $(CD) $(ABS_TEST_OUTPUT_DIR) \ + && $(ZIP) -q -r $(ARCHIVE_BUNDLE) . ) +BUNDLE_UP_AND_EXIT = ( exitCode=$$? && $(ZIP_UP_RESULTS) && exit $${exitCode} ) -# Export this setting and pass it in. -#JAVA_TOOL_OPTIONS = -Djava.awt.headless=true -#export JAVA_TOOL_OPTIONS +################################################################ -# Default make rule -all: clean check tests $(JPRT_ARCHIVE_BUNDLE) - @echo "Testing completed successfully" +# Default make rule (runs jtreg_tests) +all: jtreg_tests + @$(ECHO) "Testing completed successfully" -# Chaeck to make sure these directories exist -check: $(JT_HOME) $(JAVA_HOME) $(JTREG) - -# Run the tests -tests: FRC - @echo "Using export JAVA_TOOL_OPTIONS=$(JAVA_TOOL_OPTIONS)" - @rm -f -r $(JTREG_OUTPUT_DIR) - @mkdir -p $(JTREG_OUTPUT_DIR) - $(JTREG) -a -v:fail,error \ - $(JTREG_KEY_OPTION) \ - -r:$(JTREG_OUTPUT_DIR)/JTreport \ - -w:$(JTREG_OUTPUT_DIR)/JTwork \ - -jdk:$(JAVA_HOME) \ - $(JAVA_TOOL_OPTIONS:%=-vmoption:%) \ - $(JAVA_ARGS:%=-vmoption:%) \ - $(TESTDIRS) - -# Bundle up the results -$(JPRT_ARCHIVE_BUNDLE): FRC - @rm -f $@ - @mkdir -p $(@D) - ( cd $(JTREG_OUTPUT_DIR) && zip -q -r $@ . ) +# Prep for output +prep: clean + @$(MKDIR) -p $(ABS_TEST_OUTPUT_DIR) + @$(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)` # Cleanup clean: - rm -f -r $(JTREG_OUTPUT_DIR) - rm -f $(JPRT_ARCHIVE_BUNDLE) + $(RM) -r $(ABS_TEST_OUTPUT_DIR) + $(RM) $(ARCHIVE_BUNDLE) -# Used to force a target rules to run -FRC: +################################################################ + +# jtreg tests + +# Expect JT_HOME to be set for jtreg tests. (home for jtreg) +JT_HOME = $(SLASH_JAVA)/re/jtreg/4.0/promoted/latest/binaries/jtreg +ifdef JPRT_JTREG_HOME + JT_HOME = $(JPRT_JTREG_HOME) +endif + +# Expect JPRT to set TESTDIRS to the jtreg test dirs +ifndef TESTDIRS + TESTDIRS = demo/jvmti/gctest demo/jvmti/hprof +endif + +# Default JTREG to run (win32 script works for everybody) +JTREG = $(JT_HOME)/win32/bin/jtreg + +jtreg_tests: prep $(JT_HOME) $(PRODUCT_HOME) $(JTREG) + $(RM) $(JTREG).orig + cp $(JTREG) $(JTREG).orig + $(RM) $(JTREG) + sed -e 's@-J\*@-J-*@' $(JTREG).orig > $(JTREG) + chmod a+x $(JTREG) + ( JT_HOME=$(shell $(GETMIXEDPATH) "$(JT_HOME)"); \ + export JT_HOME; \ + $(shell $(GETMIXEDPATH) "$(JTREG)") \ + -a -v:fail,error \ + -ignore:quiet \ + $(EXTRA_JTREG_OPTIONS) \ + -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport \ + -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTwork \ + -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \ + $(JAVA_ARGS:%=-javaoptions:%) \ + $(JAVA_VM_ARGS:%=-vmoption:%) \ + $(TESTDIRS) \ + ) ; $(BUNDLE_UP_AND_EXIT) + +PHONY_LIST += jtreg_tests + +################################################################ + +# packtest + +# Expect JPRT to set JPRT_PACKTEST_HOME. +PACKTEST_HOME = /net/jprt-web.sfbay.sun.com/jprt/allproducts/packtest +ifdef JPRT_PACKTEST_HOME + PACKTEST_HOME = $(JPRT_PACKTEST_HOME) +endif + +packtest: prep $(PACKTEST_HOME)/ptest $(PRODUCT_HOME) + ( $(CD) $(PACKTEST_HOME) && \ + $(PACKTEST_HOME)/ptest \ + -t "$(PRODUCT_HOME)" \ + $(PACKTEST_STRESS_OPTION) \ + $(EXTRA_PACKTEST_OPTIONS) \ + -W $(ABS_TEST_OUTPUT_DIR) \ + $(JAVA_ARGS:%=-J %) \ + $(JAVA_VM_ARGS:%=-J %) \ + ) ; $(BUNDLE_UP_AND_EXIT) + +packtest_stress: PACKTEST_STRESS_OPTION=-s +packtest_stress: packtest + +PHONY_LIST += packtest packtest_stress + +################################################################ + +# vmsqe tests + +# Expect JPRT to set JPRT_VMSQE_HOME. +VMSQE_HOME = /java/sqe/comp/vm/testbase/sqe/vm/current/build/latest/vm +ifdef JPRT_VMSQE_HOME + VMSQE_HOME = $(JPRT_VMSQE_HOME) +endif + +# Expect JPRT to set JPRT_RUNVMSQE_HOME. +RUNVMSQE_HOME = /net/jprt-web.sfbay.sun.com/jprt/allproducts/runvmsqe +ifdef JPRT_RUNVMSQE_HOME + RUNVMSQE_HOME = $(JPRT_RUNVMSQE_HOME) +endif + +# Expect JPRT to set JPRT_TONGA3_HOME. +TONGA3_HOME = /java/sqe//tools/gtee/harness/tonga +ifdef JPRT_TONGA3_HOME + TONGA3_HOME = $(JPRT_TONGA3_HOME) +endif + +RUNVMSQE_BIN = $(RUNVMSQE_HOME)/bin/runvmsqe + +vmsqe_tests: prep $(VMSQE_HOME)/vm $(TONGA3_HOME) $(RUNVMSQE_BIN) $(PRODUCT_HOME) + $(RM) -r $(ABS_TEST_OUTPUT_DIR)/vmsqe + ( $(CD) $(ABS_TEST_OUTPUT_DIR) && \ + $(RUNVMSQE_BIN) \ + -jdk "$(PRODUCT_HOME)" \ + -o "$(ABS_TEST_OUTPUT_DIR)/vmsqe" \ + -testbase "$(VMSQE_HOME)/vm" \ + -tonga "$(TONGA3_HOME)" \ + -tongajdk "$(ALT_BOOTDIR)" \ + $(JAVA_ARGS) \ + $(JAVA_VM_ARGS) \ + $(RUNVMSQE_TEST_OPTION) \ + $(EXTRA_RUNVMSQE_OPTIONS) \ + ) ; $(BUNDLE_UP_AND_EXIT) + +vmsqe_jdwp: RUNVMSQE_TEST_OPTION=-jdwp +vmsqe_jdwp: vmsqe_tests + +vmsqe_jdi: RUNVMSQE_TEST_OPTION=-jdi +vmsqe_jdi: vmsqe_tests + +vmsqe_jdb: RUNVMSQE_TEST_OPTION=-jdb +vmsqe_jdb: vmsqe_tests + +vmsqe_quick-jdi: RUNVMSQE_TEST_OPTION=-quick-jdi +vmsqe_quick-jdi: vmsqe_tests + +vmsqe_sajdi: RUNVMSQE_TEST_OPTION=-sajdi +vmsqe_sajdi: vmsqe_tests + +vmsqe_jvmti: RUNVMSQE_TEST_OPTION=-jvmti +vmsqe_jvmti: vmsqe_tests + +vmsqe_hprof: RUNVMSQE_TEST_OPTION=-hprof +vmsqe_hprof: vmsqe_tests + +vmsqe_monitoring: RUNVMSQE_TEST_OPTION=-monitoring +vmsqe_monitoring: vmsqe_tests + +PHONY_LIST += vmsqe_jdwp vmsqe_jdi vmsqe_jdb vmsqe_quick-jdi vmsqe_sajdi \ + vmsqe_jvmti vmsqe_hprof vmsqe_monitoring vmsqe_tests + +################################################################ + +# jck tests + +JCK_WORK_DIR = $(ABS_TEST_OUTPUT_DIR)/JCKwork +JCK_REPORT_DIR = $(ABS_TEST_OUTPUT_DIR)/JCKreport +JCK_PROPERTIES = $(ABS_TEST_OUTPUT_DIR)/jck.properties +JCK_CONFIG = $(ABS_TEST_OUTPUT_DIR)/jck.config + +JCK_JAVA_EXE = $(PRODUCT_HOME)/bin/java$(EXESUFFIX) + +JCK_JAVATEST_JAR = $(JCK_HOME)/lib/javatest.jar +JCK_JAVATEST = $(ALT_BOOTDIR)/bin/java -jar $(JCK_JAVATEST_JAR) + +$(JCK_CONFIG): $(TEST_ROOT)/JCK-$(JCK_BUNDLE_NAME)-$(JCK_RELEASE)-base.jti + $(RM) $@ + $(MKDIR) -p $(@D) + $(CP) $< $@ + +$(JCK_PROPERTIES): $(PRODUCT_HOME) $(JCK_JAVA_EXE) + $(RM) $@ + $(MKDIR) -p $(@D) + $(ECHO) "jck.env.compiler.compRefExecute.cmdAsFile=$(JCK_JAVA_EXE)" >> $@ + $(ECHO) "jck.env.compiler.compRefExecute.systemRoot=$(SYSTEMROOT)" >> $@ + $(ECHO) "jck.env.compiler.testCompile.testCompileAPImultiJVM.cmdAsFile=$(JCK_JAVA_EXE)" >> $@ + $(ECHO) "jck.tests.tests=$(JCK_BUNDLE_TESTDIRS)" >> $@ + +jck_tests: prep $(JCK_HOME) $(JCK_PROPERTIES) $(JCK_CONFIG) $(JCK_JAVATEST_JAR) + $(MKDIR) -p $(JCK_WORK_DIR) + ( $(JCK_JAVATEST) \ + -verbose:commands,non-pass \ + -testSuite $(JCK_HOME) \ + -workDir $(JCK_WORK_DIR) \ + -config $(JCK_CONFIG) \ + -set -file $(JCK_PROPERTIES) \ + -runtests \ + -writeReport $(JCK_REPORT_DIR) \ + ) ; $(BUNDLE_UP_AND_EXIT) + +PHONY_LIST += jck_tests + +################################################################ + +# jck6 tests + +JCK6_RELEASE = 6b +JCK6_DEFAULT_HOME = $(SLASH_JAVA)/re/jck/$(JCK6_RELEASE)/archive/fcs/binaries + +# Expect JPRT to set JPRT_JCK6COMPILER_HOME. +JCK6COMPILER_HOME = $(JCK6_DEFAULT_HOME)/JCK-compiler-$(JCK6_RELEASE) +ifdef JPRT_JCK6COMPILER_HOME + JCK6COMPILER_HOME = $(JPRT_JCK6COMPILER_HOME) +endif + +# Expect JPRT to set JPRT_JCK6RUNTIME_HOME. +JCK6RUNTIME_HOME = $(JCK6_DEFAULT_HOME)/JCK-runtime-$(JCK6_RELEASE) +ifdef JPRT_JCK6RUNTIME_HOME + JCK6RUNTIME_HOME = $(JPRT_JCK6RUNTIME_HOME) +endif + +# Expect JPRT to set JPRT_JCK6DEVTOOLS_HOME. +JCK6DEVTOOLS_HOME = $(JCK6_DEFAULT_HOME)/JCK-devtools-$(JCK6_RELEASE) +ifdef JPRT_JCK6DEVTOOLS_HOME + JCK6DEVTOOLS_HOME = $(JPRT_JCK6DEVTOOLS_HOME) +endif + +jck6_tests: JCK_HOME=$(JCK6_HOME) +jck6_tests: JCK_RELEASE=$(JCK6_RELEASE) +jck6_tests: jck_tests + +jck6compiler: JCK6_HOME=$(JCK6COMPILER_HOME) +jck6compiler: JCK_BUNDLE_NAME=compiler +jck6compiler: jck6_tests + +jck6compiler_lang: JCK_BUNDLE_TESTDIRS=lang +jck6compiler_lang: jck6compiler + +jck6runtime: JCK6_HOME=$(JCK6RUNTIME_HOME) +jck6runtime: JCK_BUNDLE_NAME=runtime +jck6runtime: jck6_tests + +jck6runtime_lang: JCK_BUNDLE_TESTDIRS=lang +jck6runtime_lang: jck6runtime + +jck6devtools: JCK6_HOME=$(JCK6DEVTOOLS_HOME) +jck6devtools: JCK_BUNDLE_NAME=devtools +jck6devtools: jck6_tests + +jck6devtools_lang: JCK_BUNDLE_TESTDIRS=lang +jck6devtools_lang: jck6devtools + +PHONY_LIST += jck6compiler jck6runtime jck6devtools jck6_tests \ + jck6compiler_lang jck6runtime_lang jck6devtools_lang + +################################################################ + +# jck7 tests + +JCK7_RELEASE = 7 +JCK7_DEFAULT_HOME = $(SLASH_JAVA)/re/jck/$(JCK7_RELEASE)/archive/fcs/binaries + +# Expect JPRT to set JPRT_JCK7COMPILER_HOME. +JCK7COMPILER_HOME = $(JCK7_DEFAULT_HOME)/JCK-compiler-$(JCK7_RELEASE) +ifdef JPRT_JCK7COMPILER_HOME + JCK7COMPILER_HOME = $(JPRT_JCK7COMPILER_HOME) +endif + +# Expect JPRT to set JPRT_JCK7RUNTIME_HOME. +JCK7RUNTIME_HOME = $(JCK7_DEFAULT_HOME)/JCK-runtime-$(JCK7_RELEASE) +ifdef JPRT_JCK7RUNTIME_HOME + JCK7RUNTIME_HOME = $(JPRT_JCK7RUNTIME_HOME) +endif + +# Expect JPRT to set JPRT_JCK7DEVTOOLS_HOME. +JCK7DEVTOOLS_HOME = $(JCK7_DEFAULT_HOME)/JCK-devtools-$(JCK7_RELEASE) +ifdef JPRT_JCK7DEVTOOLS_HOME + JCK7DEVTOOLS_HOME = $(JPRT_JCK7DEVTOOLS_HOME) +endif + +jck7_tests: JCK_HOME=$(JCK7_HOME) +jck7_tests: JCK_RELEASE=$(JCK7_RELEASE) +jck7_tests: jck_tests + +jck7compiler: JCK7_HOME=$(JCK7COMPILER_HOME) +jck7compiler: JCK_BUNDLE_NAME=compiler +jck7compiler: jck7_tests + +jck7compiler_lang: JCK_BUNDLE_TESTDIRS=lang +jck7compiler_lang: jck7compiler + +jck7runtime: JCK7_HOME=$(JCK7RUNTIME_HOME) +jck7runtime: JCK_BUNDLE_NAME=runtime +jck7runtime: jck7_tests + +jck7runtime_lang: JCK_BUNDLE_TESTDIRS=lang +jck7runtime_lang: jck7runtime + +jck7devtools: JCK7_HOME=$(JCK7DEVTOOLS_HOME) +jck7devtools: JCK_BUNDLE_NAME=devtools +jck7devtools: jck7_tests + +jck7devtools_lang: JCK_BUNDLE_TESTDIRS=lang +jck7devtools_lang: jck7devtools + +PHONY_LIST += jck7compiler jck7runtime jck7devtools jck7_tests \ + jck7compiler_lang jck7runtime_lang jck7devtools_lang + +################################################################ # Phony targets (e.g. these are not filenames) -.PHONY: all tests clean check +.PHONY: all clean prep $(PHONY_LIST) + +################################################################ diff --git a/jdk/test/com/sun/java/swing/plaf/gtk/Test6635110.java b/jdk/test/com/sun/java/swing/plaf/gtk/Test6635110.java new file mode 100644 index 00000000000..c82cf126893 --- /dev/null +++ b/jdk/test/com/sun/java/swing/plaf/gtk/Test6635110.java @@ -0,0 +1,65 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6635110 + @summary GTK icons should not throw NPE when called by non-GTK UI + @author Peter Zhelezniakov + @run main Test6635110 +*/ + +import com.sun.java.swing.plaf.gtk.GTKLookAndFeel; +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import javax.swing.plaf.basic.*; + + +public class Test6635110 implements Runnable { + + static final int WIDTH = 160; + static final int HEIGHT = 80; + final BufferedImage IMAGE = + new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB); + + @Override public void run() { + JMenu menu = new JMenu("menu"); + menu.setUI(new BasicMenuUI()); + paint(menu); + + JToolBar tb = new JToolBar(); + tb.setFloatable(true); + tb.setUI(new BasicToolBarUI()); + paint(tb); + } + + void paint(Component c) { + c.setSize(WIDTH, HEIGHT); + c.paint(IMAGE.getGraphics()); + } + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new GTKLookAndFeel()); + SwingUtilities.invokeAndWait(new Test6635110()); + } +} diff --git a/jdk/test/com/sun/jmx/snmp/SnmpOidHashCode.java b/jdk/test/com/sun/jmx/snmp/SnmpOidHashCode.java index 907d00913f4..4a815de0386 100644 --- a/jdk/test/com/sun/jmx/snmp/SnmpOidHashCode.java +++ b/jdk/test/com/sun/jmx/snmp/SnmpOidHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,8 @@ * @build SnmpOidHashCode * @run main SnmpOidHashCode */ -import com.sun.jmx.snmp.SnmpOid; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; public class SnmpOidHashCode { public static final String[] oids = { @@ -57,16 +58,81 @@ public class SnmpOidHashCode { ".39."+0xFFFFFFFFL }; + // We use an SnmpOidBuilder in order to adapt this test case to a + // configuration where the SNMP packages are not present in rt.jar. + // + public static final class SnmpOidBuilder { + public static final String SNMP_OID_CLASS_NAME = + "com.sun.jmx.snmp.SnmpOid"; + private static final Class<?> SNMP_OID_CLASS; + private static final Constructor<?> SNMP_OID_CTOR; + static { + Class<?> snmpOidClass; + try { + snmpOidClass = + Class.forName(SNMP_OID_CLASS_NAME, true, null); + } catch (ClassNotFoundException x) { + snmpOidClass = null; + System.err.println("WARNING: can't load "+SNMP_OID_CLASS_NAME); + } catch (NoClassDefFoundError x) { + snmpOidClass = null; + System.err.println("WARNING: can't load "+SNMP_OID_CLASS_NAME); + } + SNMP_OID_CLASS = snmpOidClass; + if (SNMP_OID_CLASS != null) { + try { + SNMP_OID_CTOR = snmpOidClass.getConstructor(String.class); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } else { + SNMP_OID_CTOR = null; + } + } + + public static boolean isSnmpPresent() { + System.out.println(SnmpOidHashCode.class.getName()+ + ": Testing for SNMP Packages..."); + return SNMP_OID_CLASS != null; + } + + public static Object newSnmpOid(String oid) + throws InstantiationException, + IllegalAccessException, + InvocationTargetException { + return SNMP_OID_CTOR.newInstance(oid); + } + + } + + private static Object newSnmpOid(String oid) throws Exception { + try { + return SnmpOidBuilder.newSnmpOid(oid); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception)cause; + if (cause instanceof Error) throw (Error)cause; + throw x; + } + } + public static void main(String args[]) { + if (!SnmpOidBuilder.isSnmpPresent()) { + System.err.println("WARNING: "+ + SnmpOidBuilder.SNMP_OID_CLASS_NAME+" not present."); + System.err.println(SnmpOidHashCode.class.getName()+ + ": test skipped."); + return; + } try { int errCount=0; int collisions=0; for (int i=0;i<oids.length;i++) { System.out.println("Testing " + oids[i]); - final SnmpOid o1 = new SnmpOid(oids[i]); + final Object o1 = newSnmpOid(oids[i]); final int startCount=errCount; for (int j=0;j<oids.length;j++) { - final SnmpOid o2 = new SnmpOid(oids[j]); + final Object o2 = newSnmpOid(oids[j]); if (o1.equals(o2)) { if (!(oids[i].equals(oids[j]))) { System.err.println("OIDs differ but " + diff --git a/jdk/test/com/sun/jmx/snmp/TimeTicksWrapping.java b/jdk/test/com/sun/jmx/snmp/TimeTicksWrapping.java index 23a87b662f4..0776052c53f 100644 --- a/jdk/test/com/sun/jmx/snmp/TimeTicksWrapping.java +++ b/jdk/test/com/sun/jmx/snmp/TimeTicksWrapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,33 +29,158 @@ * @build TimeTicksWrapping * @run main TimeTicksWrapping */ -import com.sun.jmx.snmp.SnmpTimeticks; -import com.sun.jmx.snmp.SnmpUnsignedInt; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; public class TimeTicksWrapping { + // We use an SnmpTimeticksBuilder in order to adapt this test case to a + // configuration where the SNMP packages are not present in rt.jar. + // + public static final class SnmpTimeticksBuilder { + public static final long MAX_VALUE = 0x0ffffffffL; + public static final String SNMP_TIME_TICKS_CLASS_NAME = + "com.sun.jmx.snmp.SnmpTimeticks"; + private static final Class<?> SNMP_TIME_TICKS_CLASS; + private static final Constructor<?> SNMP_long_CTOR; + private static final Constructor<?> SNMP_LONG_CTOR; + private static final Method SNMP_LONG_VALUE; + static { + Class<?> snmpTimeTicksClass; + try { + snmpTimeTicksClass = + Class.forName(SNMP_TIME_TICKS_CLASS_NAME, true, null); + } catch (ClassNotFoundException x) { + snmpTimeTicksClass = null; + System.err.println("WARNING: can't load "+ + SNMP_TIME_TICKS_CLASS_NAME); + } catch (NoClassDefFoundError x) { + snmpTimeTicksClass = null; + System.err.println("WARNING: can't load "+ + SNMP_TIME_TICKS_CLASS_NAME); + } + SNMP_TIME_TICKS_CLASS = snmpTimeTicksClass; + if (SNMP_TIME_TICKS_CLASS != null) { + try { + SNMP_long_CTOR = + SNMP_TIME_TICKS_CLASS.getConstructor(long.class); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } else { + SNMP_long_CTOR = null; + } + if (SNMP_TIME_TICKS_CLASS != null) { + try { + SNMP_LONG_CTOR = + SNMP_TIME_TICKS_CLASS.getConstructor(Long.class); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } else { + SNMP_LONG_CTOR = null; + } + if (SNMP_TIME_TICKS_CLASS != null) { + try { + SNMP_LONG_VALUE = + SNMP_TIME_TICKS_CLASS.getMethod("longValue"); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } else { + SNMP_LONG_VALUE = null; + } + + } + + private final Object timeticks; + + public SnmpTimeticksBuilder(long ticks) throws Exception { + timeticks = newSnmpTimeticks(ticks); + } + public SnmpTimeticksBuilder(Long ticks) throws Exception { + timeticks = newSnmpTimeticks(ticks); + } + public long longValue() throws Exception { + return longValue(timeticks); + } + + public static boolean isSnmpPresent() { + System.out.println(TimeTicksWrapping.class.getName()+ + ": Testing for SNMP Packages..."); + return SNMP_TIME_TICKS_CLASS != null; + } + + private static Object newSnmpTimeticks(long time) + throws Exception { + try { + return SNMP_long_CTOR.newInstance(time); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception) cause; + if (cause instanceof Error) throw (Error) cause; + throw x; + } + } + + private static Object newSnmpTimeticks(Long time) + throws Exception { + try { + return SNMP_LONG_CTOR.newInstance(time); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception) cause; + if (cause instanceof Error) throw (Error) cause; + throw x; + } + } + + private static long longValue(Object o) + throws Exception { + try { + return ((Long)SNMP_LONG_VALUE.invoke(o)).longValue(); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception) cause; + if (cause instanceof Error) throw (Error) cause; + throw x; + } + } + + } + public static final long[] oks = { 0L, 1L, (long)Integer.MAX_VALUE, (long)Integer.MAX_VALUE*2, (long)Integer.MAX_VALUE*2+1L, (long)Integer.MAX_VALUE*2+2L, (long)Integer.MAX_VALUE*3, - SnmpUnsignedInt.MAX_VALUE, SnmpUnsignedInt.MAX_VALUE+1L, - SnmpUnsignedInt.MAX_VALUE*3-1L, Long.MAX_VALUE + SnmpTimeticksBuilder.MAX_VALUE, SnmpTimeticksBuilder.MAX_VALUE+1L, + SnmpTimeticksBuilder.MAX_VALUE*3-1L, Long.MAX_VALUE }; public static final long[] kos = { -1L, (long)Integer.MIN_VALUE, (long)Integer.MIN_VALUE*2, (long)Integer.MIN_VALUE*2-1L, (long)Integer.MIN_VALUE*3, - -SnmpUnsignedInt.MAX_VALUE, -(SnmpUnsignedInt.MAX_VALUE+1L), - -(SnmpUnsignedInt.MAX_VALUE*3-1L), Long.MIN_VALUE + -SnmpTimeticksBuilder.MAX_VALUE, -(SnmpTimeticksBuilder.MAX_VALUE+1L), + -(SnmpTimeticksBuilder.MAX_VALUE*3-1L), Long.MIN_VALUE }; + public static void main(String args[]) { + if (!SnmpTimeticksBuilder.isSnmpPresent()) { + System.err.println("WARNING: "+ + SnmpTimeticksBuilder.SNMP_TIME_TICKS_CLASS_NAME+ + " not present."); + System.err.println(TimeTicksWrapping.class.getName()+ + ": test skipped."); + return; + } try { - SnmpTimeticks t; + SnmpTimeticksBuilder t = null; for (int i=0;i<oks.length;i++) { final long t1,t2,t3; - t1 = (new SnmpTimeticks(oks[i])).longValue(); - t2 = (new SnmpTimeticks(new Long(oks[i]))).longValue(); + t1 = (new SnmpTimeticksBuilder(oks[i])).longValue(); + t2 = (new SnmpTimeticksBuilder(new Long(oks[i]))).longValue(); t3 = oks[i]%0x0100000000L; if (t1 != t3) throw new Exception("Value should have wrapped: " + @@ -64,16 +189,16 @@ public class TimeTicksWrapping { throw new Exception("Value should have wrapped: " + "Long("+oks[i]+") expected: " + t3); - if (t1 > SnmpUnsignedInt.MAX_VALUE) + if (t1 > SnmpTimeticksBuilder.MAX_VALUE) throw new Exception("Value should have wrapped " + "for " + oks[i] + ": " + t1 + " exceeds max: " + - SnmpUnsignedInt.MAX_VALUE); - if (t2 > SnmpUnsignedInt.MAX_VALUE) + SnmpTimeticksBuilder.MAX_VALUE); + if (t2 > SnmpTimeticksBuilder.MAX_VALUE) throw new Exception("Value should have wrapped " + "for " + oks[i] + ": " + t2 + " exceeds max: " + - SnmpUnsignedInt.MAX_VALUE); + SnmpTimeticksBuilder.MAX_VALUE); if (t1 < 0) throw new Exception("Value should have wrapped: " + @@ -90,14 +215,14 @@ public class TimeTicksWrapping { for (int i=0;i<kos.length;i++) { try { - t = new SnmpTimeticks(kos[i]); + t = new SnmpTimeticksBuilder(kos[i]); throw new Exception("Value should have been rejected: " + kos[i]); } catch (IllegalArgumentException x) { // OK! } try { - t = new SnmpTimeticks(new Long(kos[i])); + t = new SnmpTimeticksBuilder(new Long(kos[i])); throw new Exception("Value should have been rejected: " + "Long("+kos[i]+")"); } catch (IllegalArgumentException x) { diff --git a/jdk/test/java/awt/FontClass/FontAccess.java b/jdk/test/java/awt/FontClass/FontAccess.java new file mode 100644 index 00000000000..3e965059ef7 --- /dev/null +++ b/jdk/test/java/awt/FontClass/FontAccess.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6785424 + * @summary Test no SecurityException searching for a font. + * @run main FontAccess + * + * This can only test the specific bug if run on something like + * Windows Citrix Server where SystemDirectory and WindowsDirectory + * are different locations. + */ + +import java.awt.*; +import java.awt.image.*; + +public class FontAccess { + + public static void main(String[] args) { + System.setSecurityManager(new SecurityManager()); + Font f = new Font("Verdana", Font.PLAIN, 12); + BufferedImage bi = new BufferedImage(1,1,1); + Graphics2D g = bi.createGraphics(); + g.setFont(f); + System.out.println(g.getFontMetrics()); + } +} diff --git a/jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java b/jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java index f8a98ea3216..b220ec5cc01 100644 --- a/jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java +++ b/jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java @@ -15,6 +15,10 @@ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. */ /* diff --git a/jdk/test/java/awt/GraphicsEnvironment/PreferLocaleFonts.java b/jdk/test/java/awt/GraphicsEnvironment/PreferLocaleFonts.java new file mode 100644 index 00000000000..3d8cb5934f5 --- /dev/null +++ b/jdk/test/java/awt/GraphicsEnvironment/PreferLocaleFonts.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6752638 + * @summary Test no NPE calling preferLocaleFonts() on custom GE. + * @run main PreferLocaleFonts + */ + +import java.util.*; +import java.awt.*; +import java.awt.image.*; + +public class PreferLocaleFonts extends GraphicsEnvironment { + + public static void main(String args[]) { +(new PreferLocaleFonts()).preferLocaleFonts(); + } + public PreferLocaleFonts() { + super(); + } + public Graphics2D createGraphics(BufferedImage image) { + return null; + } + public String[] getAvailableFontFamilyNames(Locale locale) { + return null; + } + public String[] getAvailableFontFamilyNames() { + return null; + } + public Font[] getAllFonts() { + return null; + } + public GraphicsDevice getDefaultScreenDevice() throws HeadlessException { + return null; + } + public GraphicsDevice[] getScreenDevices() throws HeadlessException { + return null; + } +} + diff --git a/jdk/test/java/awt/font/LineBreakMeasurer/FRCTest.java b/jdk/test/java/awt/font/LineBreakMeasurer/FRCTest.java new file mode 100644 index 00000000000..d65037e2ec3 --- /dev/null +++ b/jdk/test/java/awt/font/LineBreakMeasurer/FRCTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2008-9 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6448405 6519513 6745225 + * @summary static HashMap cache in LineBreakMeasurer can grow wihout bounds + * @run main/othervm/timeout=600 -client -Xms16m -Xmx16m FRCTest + */ +import java.awt.*; +import java.awt.image.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.text.*; +import java.util.Hashtable; + +public class FRCTest { + + static AttributedString vanGogh = new AttributedString( + "Many people believe that Vincent van Gogh painted his best works " + + "during the two-year period he spent in Provence. Here is where he " + + "painted The Starry Night--which some consider to be his greatest " + + "work of all. However, as his artistic brilliance reached new " + + "heights in Provence, his physical and mental health plummeted. ", + new Hashtable()); + + public static void main(String[] args) { + + // First test the behaviour of Graphics2D.getFontRenderContext(); + BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bi.createGraphics(); + AffineTransform g2dTx = new AffineTransform(2,0,2,0,1,1); + g2d.setTransform(g2dTx); + AffineTransform frcTx = g2d.getFontRenderContext().getTransform(); + AffineTransform frcExpected = new AffineTransform(2,0,2,0,0,0); + if (!frcTx.equals(frcExpected)) { + throw new RuntimeException("FRC Tx may have translate?"); + } + + // Now test that using different translates with LBM is OK + // This test doesn't prove a lot since showing a leak really + // requires a basher test that can run for a long time. + for (int x=0;x<100;x++) { + for (int y=0;y<100;y++) { + AttributedCharacterIterator aci = vanGogh.getIterator(); + AffineTransform tx = AffineTransform.getTranslateInstance(x, y); + FontRenderContext frc = new FontRenderContext(tx, false, false); + LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc); + lbm.setPosition(aci.getBeginIndex()); + while (lbm.getPosition() < aci.getEndIndex()) { + lbm.nextLayout(100f); + } + } + } + + for (int x=0;x<25;x++) { + for (int y=0;y<25;y++) { + AttributedCharacterIterator aci = vanGogh.getIterator(); + double rot = Math.random()*.4*Math.PI - .2*Math.PI; + AffineTransform tx = AffineTransform.getRotateInstance(rot); + FontRenderContext frc = new FontRenderContext(tx, false, false); + LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc); + lbm.setPosition(aci.getBeginIndex()); + while (lbm.getPosition() < aci.getEndIndex()) { + lbm.nextLayout(100f); + } + } + } + } +} diff --git a/jdk/test/java/beans/Beans/6669869/TestDesignTime.java b/jdk/test/java/beans/Beans/6669869/TestDesignTime.java new file mode 100644 index 00000000000..e78142a2b90 --- /dev/null +++ b/jdk/test/java/beans/Beans/6669869/TestDesignTime.java @@ -0,0 +1,52 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6669869 + * @summary Tests DesignTime property in different application contexts + * @author Sergey Malenkov + */ + +import java.beans.Beans; +import sun.awt.SunToolkit; + +public class TestDesignTime implements Runnable { + public static void main(String[] args) throws InterruptedException { + if (Beans.isDesignTime()) { + throw new Error("unexpected DesignTime property"); + } + Beans.setDesignTime(!Beans.isDesignTime()); + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new TestDesignTime()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + if (Beans.isDesignTime()) { + throw new Error("shared DesignTime property"); + } + } +} diff --git a/jdk/test/java/beans/Beans/6669869/TestGuiAvailable.java b/jdk/test/java/beans/Beans/6669869/TestGuiAvailable.java new file mode 100644 index 00000000000..7144b6fad3b --- /dev/null +++ b/jdk/test/java/beans/Beans/6669869/TestGuiAvailable.java @@ -0,0 +1,53 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6669869 + * @summary Tests GuiAvailable property in different application contexts + * @author Sergey Malenkov + */ + +import java.awt.GraphicsEnvironment; +import java.beans.Beans; +import sun.awt.SunToolkit; + +public class TestGuiAvailable implements Runnable { + public static void main(String[] args) throws InterruptedException { + if (Beans.isGuiAvailable() == GraphicsEnvironment.isHeadless()) { + throw new Error("unexpected GuiAvailable property"); + } + Beans.setGuiAvailable(!Beans.isGuiAvailable()); + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new TestGuiAvailable()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + if (Beans.isGuiAvailable() == GraphicsEnvironment.isHeadless()) { + throw new Error("shared GuiAvailable property"); + } + } +} diff --git a/jdk/test/java/io/File/GetXSpace.java b/jdk/test/java/io/File/GetXSpace.java index a2855e7b372..345c3384668 100644 --- a/jdk/test/java/io/File/GetXSpace.java +++ b/jdk/test/java/io/File/GetXSpace.java @@ -24,6 +24,7 @@ /** * @test * @bug 4057701 6286712 6364377 + * @ignore until 6492634 and 6501010 is fixed * @run build GetXSpace * @run shell GetXSpace.sh * @summary Basic functionality of File.get-X-Space methods. diff --git a/jdk/test/java/lang/ClassLoader/deadlock/Alice.java b/jdk/test/java/lang/ClassLoader/deadlock/Alice.java new file mode 100644 index 00000000000..9fae5e411a8 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/deadlock/Alice.java @@ -0,0 +1,29 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package comSA; + +public class Alice extends comSB.SupAlice { + static { + System.out.println("comSA.Alice loaded"); + } +} diff --git a/jdk/test/java/lang/ClassLoader/deadlock/Bob.java b/jdk/test/java/lang/ClassLoader/deadlock/Bob.java new file mode 100644 index 00000000000..ca0c279ec91 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/deadlock/Bob.java @@ -0,0 +1,29 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package comSB; + +public class Bob extends comSA.SupBob { + static { + System.out.println("comSB.Bob loaded"); + } +} diff --git a/jdk/test/java/lang/ClassLoader/deadlock/DelegatingLoader.java b/jdk/test/java/lang/ClassLoader/deadlock/DelegatingLoader.java new file mode 100644 index 00000000000..def58c9e53c --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/deadlock/DelegatingLoader.java @@ -0,0 +1,93 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.*; +import java.lang.reflect.*; + +public class DelegatingLoader extends URLClassLoader { + + private DelegatingLoader delLoader; + private String[] delClasses; + + static { + boolean supportParallel = false; + try { + Class c = Class.forName("java.lang.ClassLoader"); + Method m = c.getDeclaredMethod("registerAsParallelCapable", + new Class[0]); + m.setAccessible(true); + Object result = (Boolean) m.invoke(null); + if (result instanceof Boolean) { + supportParallel = ((Boolean) result).booleanValue(); + } else { + // Should never happen + System.out.println("Error: ClassLoader.registerAsParallelCapable() did not return a boolean!"); + System.exit(1); + } + } catch (NoSuchMethodException nsme) { + System.out.println("No ClassLoader.registerAsParallelCapable() API"); + } catch (NoSuchMethodError nsme2) { + System.out.println("No ClassLoader.registerAsParallelCapable() API"); + } catch (Exception ex) { + ex.printStackTrace(); + // Exit immediately to indicate an error + System.exit(1); + } + System.out.println("Parallel ClassLoader registration: " + + supportParallel); + } + + public DelegatingLoader(URL urls[]) { + super(urls); + System.out.println("DelegatingLoader using URL " + urls[0]); + } + + public void setDelegate(String[] delClasses, DelegatingLoader delLoader) { + this.delClasses = delClasses; + this.delLoader = delLoader; + } + + public Class loadClass(String className, boolean resolve) + throws ClassNotFoundException { + for (int i = 0; i < delClasses.length; i++) { + if (delClasses[i].equals(className)) { + Starter.log("Delegating class loading for " + className); + try { + Thread.sleep(500); + } catch (InterruptedException ie) { + return null; + } + return delLoader.loadClass(className, resolve); + } + } + + Starter.log("Loading local class " + className); +// synchronized (getClassLoadingLock(className)) { + return super.loadClass(className, resolve); +// } + } +} diff --git a/jdk/test/java/lang/ClassLoader/deadlock/Starter.java b/jdk/test/java/lang/ClassLoader/deadlock/Starter.java new file mode 100644 index 00000000000..c23edb92d31 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/deadlock/Starter.java @@ -0,0 +1,105 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.net.MalformedURLException; +import java.net.URL; + +public class Starter implements Runnable { + + private String id; + private DelegatingLoader dl; + private String startClass; + + private static DelegatingLoader saLoader, sbLoader; + + public static void log(String line) { + System.out.println(line); + } + + public static void main(String[] args) { + URL[] urlsa = new URL[1]; + URL[] urlsb = new URL[1]; + try { + String testDir = System.getProperty("test.classes", "."); + String sep = System.getProperty("file.separator"); + urlsa[0] = new URL("file://" + testDir + sep + "SA" + sep); + urlsb[0] = new URL("file://" + testDir + sep + "SB" + sep); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + // Set up Classloader delegation hierarchy + saLoader = new DelegatingLoader(urlsa); + sbLoader = new DelegatingLoader(urlsb); + + String[] saClasses = { "comSA.SupBob", "comSA.Alice" }; + String[] sbClasses = { "comSB.SupAlice", "comSB.Bob" }; + + saLoader.setDelegate(sbClasses, sbLoader); + sbLoader.setDelegate(saClasses, saLoader); + + // test one-way delegate + String testType = args[0]; + if (testType.equals("one-way")) { + test("comSA.Alice", "comSA.SupBob"); + } else if (testType.equals("cross")) { + // test cross delegate + test("comSA.Alice", "comSB.Bob"); + } else { + System.out.println("ERROR: unsupported - " + testType); + } + } + + private static void test(String clsForSA, String clsForSB) { + Starter ia = new Starter("SA", saLoader, clsForSA); + Starter ib = new Starter("SB", sbLoader, clsForSB); + new Thread(ia).start(); + new Thread(ib).start(); + } + + public static void sleep() { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + log("Thread interrupted"); + } + } + + private Starter(String id, DelegatingLoader dl, String startClass) { + this.id = id; + this.dl = dl; + this.startClass = startClass; + } + + public void run() { + log("Spawned thread " + id + " running"); + try { + // To mirror the WAS deadlock, need to ensure class load + // is routed via the VM. + Class.forName(startClass, true, dl); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + log("Thread " + id + " terminating"); + } +} diff --git a/jdk/test/java/lang/ClassLoader/deadlock/SupAlice.java b/jdk/test/java/lang/ClassLoader/deadlock/SupAlice.java new file mode 100644 index 00000000000..4b04580e01b --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/deadlock/SupAlice.java @@ -0,0 +1,29 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package comSB; + +public class SupAlice { + static { + System.out.println("comSB.SupAlice loaded"); + } +} diff --git a/jdk/test/java/lang/ClassLoader/deadlock/SupBob.java b/jdk/test/java/lang/ClassLoader/deadlock/SupBob.java new file mode 100644 index 00000000000..05cfde319fd --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/deadlock/SupBob.java @@ -0,0 +1,29 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package comSA; + +public class SupBob { + static { + System.out.println("comSA.SupBob loaded"); + } +} diff --git a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh new file mode 100644 index 00000000000..5c1a1aeb653 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh @@ -0,0 +1,105 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# +# @test +# @bug 4735126 +# @summary (cl) ClassLoader.loadClass locks all instances in chain +# when delegating +# +# @run shell/timeout=10 TestCrossDelegate.sh + +# if running by hand on windows, change TESTSRC and TESTCLASSES to "." +if [ "${TESTSRC}" = "" ] ; then + TESTSRC=`pwd` +fi +if [ "${TESTCLASSES}" = "" ] ; then + TESTCLASSES=`pwd` +fi + +# if running by hand on windows, change this to appropriate value +if [ "${TESTJAVA}" = "" ] ; then + echo "TESTJAVA not set. Test cannot execute." + echo "FAILED!!!" + exit 1 +fi +echo TESTSRC=${TESTSRC} +echo TESTCLASSES=${TESTCLASSES} +echo TESTJAVA=${TESTJAVA} +echo "" + +# set platform-specific variables +OS=`uname -s` +case "$OS" in + SunOS ) + FS="/" + ;; + Linux ) + FS="/" + ;; + Windows* ) + FS="\\" + ;; +esac + +# compile test +${TESTJAVA}${FS}bin${FS}javac \ + -d ${TESTCLASSES} \ + ${TESTSRC}${FS}Starter.java ${TESTSRC}${FS}DelegatingLoader.java + +STATUS=$? +if [ ${STATUS} -ne 0 ] +then + exit ${STATUS} +fi + +# set up test +${TESTJAVA}${FS}bin${FS}javac \ + -d ${TESTCLASSES}${FS} \ + ${TESTSRC}${FS}Alice.java ${TESTSRC}${FS}SupBob.java \ + ${TESTSRC}${FS}Bob.java ${TESTSRC}${FS}SupAlice.java + +cd ${TESTCLASSES} +DIRS="SA SB" +for dir in $DIRS +do + if [ -d ${dir} ]; then + rm -rf ${dir} + fi + mkdir ${dir} + mv com${dir} ${dir} +done + +# run test +${TESTJAVA}${FS}bin${FS}java \ + -verbose:class -XX:+TraceClassLoading -cp . \ + -Dtest.classes=${TESTCLASSES} \ + Starter cross +# -XX:+UnlockDiagnosticVMOptions -XX:+UnsyncloadClass \ + +# save error status +STATUS=$? + +# clean up +rm -rf ${TESTCLASSES}${FS}SA ${TESTCLASSES}${FS}SB + +# return +exit ${STATUS} diff --git a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh new file mode 100644 index 00000000000..1f6a08ff342 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh @@ -0,0 +1,105 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# +# @test +# @bug 4735126 +# @summary (cl) ClassLoader.loadClass locks all instances in chain +# when delegating +# +# @run shell/timeout=10 TestOneWayDelegate.sh + +# if running by hand on windows, change TESTSRC and TESTCLASSES to "." +if [ "${TESTSRC}" = "" ] ; then + TESTSRC=`pwd` +fi +if [ "${TESTCLASSES}" = "" ] ; then + TESTCLASSES=`pwd` +fi + +# if running by hand on windows, change this to appropriate value +if [ "${TESTJAVA}" = "" ] ; then + echo "TESTJAVA not set. Test cannot execute." + echo "FAILED!!!" + exit 1 +fi +echo TESTSRC=${TESTSRC} +echo TESTCLASSES=${TESTCLASSES} +echo TESTJAVA=${TESTJAVA} +echo "" + +# set platform-specific variables +OS=`uname -s` +case "$OS" in + SunOS ) + FS="/" + ;; + Linux ) + FS="/" + ;; + Windows* ) + FS="\\" + ;; +esac + +# compile test +${TESTJAVA}${FS}bin${FS}javac \ + -d ${TESTCLASSES} \ + ${TESTSRC}${FS}Starter.java ${TESTSRC}${FS}DelegatingLoader.java + +STATUS=$? +if [ ${STATUS} -ne 0 ] +then + exit ${STATUS} +fi + +# set up test +${TESTJAVA}${FS}bin${FS}javac \ + -d ${TESTCLASSES}${FS} \ + ${TESTSRC}${FS}Alice.java ${TESTSRC}${FS}SupBob.java \ + ${TESTSRC}${FS}Bob.java ${TESTSRC}${FS}SupAlice.java + +cd ${TESTCLASSES} +DIRS="SA SB" +for dir in $DIRS +do + if [ -d ${dir} ]; then + rm -rf ${dir} + fi + mkdir ${dir} + mv com${dir} ${dir} +done + +# run test +${TESTJAVA}${FS}bin${FS}java \ + -verbose:class -XX:+TraceClassLoading -cp . \ + -Dtest.classes=${TESTCLASSES} \ + Starter one-way +# -XX:+UnlockDiagnosticVMOptions -XX:+UnsyncloadClass \ + +# save error status +STATUS=$? + +# clean up +rm -rf ${TESTCLASSES}${FS}SA ${TESTCLASSES}${FS}SB + +# return +exit ${STATUS} diff --git a/jdk/test/java/lang/Integer/ValueOf.java b/jdk/test/java/lang/Integer/ValueOf.java new file mode 100644 index 00000000000..c6f47f571ee --- /dev/null +++ b/jdk/test/java/lang/Integer/ValueOf.java @@ -0,0 +1,55 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6807702 + * @summary Basic test for Integer.valueOf + * @run main ValueOf + * @run main/othervm -esa -XX:+AggressiveOpts ValueOf + */ + +public class ValueOf { + + // test Integer.valueOf over this range (inclusive) + private static final int TEST_LOW = -1024; + private static final int TEST_HIGH = 24576; + + public static void main(String[] args) { + int i = TEST_LOW; + while (i <= TEST_HIGH) { + // check that valueOf stores i + if (Integer.valueOf(i).intValue() != i) + throw new RuntimeException(); + + // check that the same object is returned for integral values + // in the range -128 to 127 (inclusive) + if (i >= -128 && i <= 127) { + if (Integer.valueOf(i) != Integer.valueOf(i)) + throw new RuntimeException(); + } + + i++; + } + } +} diff --git a/jdk/test/java/lang/String/ToLowerCase.java b/jdk/test/java/lang/String/ToLowerCase.java index 84d5d5af208..5d43b45ee06 100644 --- a/jdk/test/java/lang/String/ToLowerCase.java +++ b/jdk/test/java/lang/String/ToLowerCase.java @@ -72,7 +72,7 @@ public class ToLowerCase { // I-dot tests (Turkish and Azeri) test("\u0130", turkish, "i"); test("\u0130", az, "i"); - test("\u0130", Locale.US, "i"); + test("\u0130", Locale.US, "i\u0307"); // Remove dot_above in the sequence I + dot_above (Turkish and Azeri) test("I\u0307", turkish, "i"); diff --git a/jdk/test/java/lang/Thread/StartOOMTest.java b/jdk/test/java/lang/Thread/StartOOMTest.java index dd8b519453e..260d0929703 100644 --- a/jdk/test/java/lang/Thread/StartOOMTest.java +++ b/jdk/test/java/lang/Thread/StartOOMTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 6379235 + * @ignore until 6721694 is fixed * @run main/othervm -server -Xmx32m -Xms32m -Xss256m StartOOMTest * @summary ThreadGroup accounting mistake possible with failure of Thread.start() */ diff --git a/jdk/test/java/lang/reflect/Method/InheritedMethods.java b/jdk/test/java/lang/reflect/Method/InheritedMethods.java index 943767fb85f..7b54f7b1edc 100644 --- a/jdk/test/java/lang/reflect/Method/InheritedMethods.java +++ b/jdk/test/java/lang/reflect/Method/InheritedMethods.java @@ -23,6 +23,7 @@ /* @test @bug 4471738 + @ignore until 6825739 fixed @summary Failure to properly traverse class hierarchy in Class.getMethod() */ diff --git a/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java b/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java index 834e7431eb6..1755d0170dc 100644 --- a/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java +++ b/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4460583 4470470 4840199 6419424 6710579 6596323 + * @bug 4460583 4470470 4840199 6419424 6710579 6596323 6824135 * @summary Comprehensive test of asynchronous closing and interruption * @author Mark Reinhold */ diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java new file mode 100644 index 00000000000..995c00ffd1e --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java @@ -0,0 +1,81 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.channels.AsynchronousChannelGroup; +import java.util.concurrent.*; + +/** + * Test that arbitrary tasks can be submitted to a channel group's thread pool. + */ + +public class AsExecutor { + + public static void main(String[] args) throws Exception { + // create channel groups + ThreadFactory factory = new PrivilegedThreadFactory(); + AsynchronousChannelGroup group1 = AsynchronousChannelGroup + .withFixedThreadPool(5, factory); + AsynchronousChannelGroup group2 = AsynchronousChannelGroup + .withCachedThreadPool(Executors.newCachedThreadPool(factory), 0); + + try { + // execute simple tasks + testSimpleTask(group1); + testSimpleTask(group2); + + // install security manager and test again + System.setSecurityManager( new SecurityManager() ); + testSimpleTask(group1); + testSimpleTask(group2); + + // attempt to execute tasks that run with only frames from boot + // class loader on the stack. + testAttackingTask(group1); + testAttackingTask(group2); + } finally { + group1.shutdown(); + group2.shutdown(); + } + } + + static void testSimpleTask(AsynchronousChannelGroup group) throws Exception { + Executor executor = (Executor)group; + final CountDownLatch latch = new CountDownLatch(1); + executor.execute(new Runnable() { + public void run() { + latch.countDown(); + } + }); + latch.await(); + } + + static void testAttackingTask(AsynchronousChannelGroup group) throws Exception { + Executor executor = (Executor)group; + Attack task = new Attack(); + executor.execute(task); + task.waitUntilDone(); + if (!task.failedDueToSecurityException()) + throw new RuntimeException("SecurityException expected"); + } + +} diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Attack.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Attack.java new file mode 100644 index 00000000000..491926c86f4 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Attack.java @@ -0,0 +1,63 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.net.*; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; + +/** + * A task that attempts to attack the current host. + */ + +public class Attack implements Runnable { + private final CountDownLatch latch = new CountDownLatch(1); + private volatile boolean failedDueToSecurityException; + + public void Attack() { + // check class is on boot class path + if (Attack.class.getClassLoader() != null) + throw new RuntimeException("Attack class not on boot class path"); + } + + @Override + public void run() { + try { + new Socket("127.0.0.1", 9999).close(); + throw new RuntimeException("Connected (not expected)"); + } catch (IOException e) { + throw new RuntimeException("IOException (not expected)"); + } catch (SecurityException e) { + failedDueToSecurityException = true; + } finally { + latch.countDown(); + } + } + + public void waitUntilDone() throws InterruptedException { + latch.await(); + } + + public boolean failedDueToSecurityException() { + return failedDueToSecurityException; + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/BadProperties.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/BadProperties.java new file mode 100644 index 00000000000..7c109b1fe19 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/BadProperties.java @@ -0,0 +1,41 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousChannelGroup + * @build BadProperties + * @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.threadFactory BadProperties + * @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.threadFactory=Missing BadProperties + * @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.initialSize BadProperties + * @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.initialSize=NaN BadProperties + */ + +import java.nio.channels.AsynchronousSocketChannel; +import java.io.IOException; + +public class BadProperties { + public static void main(String[] args) throws IOException { + AsynchronousSocketChannel.open(); + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Basic.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Basic.java new file mode 100644 index 00000000000..f26ed171d71 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Basic.java @@ -0,0 +1,259 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousChannelGroup + * @build Basic + * @run main/othervm -XX:-UseVMInterruptibleIO Basic + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import java.io.IOException; + +public class Basic { + static final Random rand = new Random(); + static final ThreadFactory threadFactory = new ThreadFactory() { + @Override + public Thread newThread(final Runnable r) { + return new Thread(r); + }}; + + + public static void main(String[] args) throws Exception { + shutdownTests(); + shutdownNowTests(); + afterShutdownTests(); + miscTests(); + } + + static void shutdownTests() throws Exception { + System.out.println("-- test shutdown --"); + + // test shutdown with no channels in groups + for (int i=0; i<500; i++) { + ExecutorService pool = null; + AsynchronousChannelGroup group; + if (rand.nextBoolean()) { + pool = Executors.newCachedThreadPool(); + group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(5)); + } else { + int nThreads = 1 + rand.nextInt(8); + group = AsynchronousChannelGroup.withFixedThreadPool(nThreads, threadFactory); + } + group.shutdown(); + if (!group.isShutdown()) + throw new RuntimeException("Group should be shutdown"); + // group should terminate quickly + boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS); + if (!terminated) + throw new RuntimeException("Group should have terminated"); + if (pool != null && !pool.isTerminated()) + throw new RuntimeException("Executor should have terminated"); + } + + // shutdown with channel in group + for (int i=0; i<500; i++) { + ExecutorService pool = null; + AsynchronousChannelGroup group; + if (rand.nextBoolean()) { + pool = Executors.newCachedThreadPool(); + group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(10)); + } else { + int nThreads = 1 + rand.nextInt(8); + group = AsynchronousChannelGroup.withFixedThreadPool(nThreads, threadFactory); + } + // create channel that is bound to group + AsynchronousChannel ch; + switch (rand.nextInt(3)) { + case 0 : ch = AsynchronousSocketChannel.open(group); break; + case 1 : ch = AsynchronousServerSocketChannel.open(group); break; + case 2 : ch = AsynchronousDatagramChannel.open(null, group); break; + default : throw new AssertionError(); + } + group.shutdown(); + if (!group.isShutdown()) + throw new RuntimeException("Group should be shutdown"); + + // last channel so should terminate after this channel is closed + ch.close(); + + // group should terminate quickly + boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS); + if (!terminated) + throw new RuntimeException("Group should have terminated"); + if (pool != null && !pool.isTerminated()) + throw new RuntimeException("Executor should have terminated"); + } + } + + static void shutdownNowTests() throws Exception { + System.out.println("-- test shutdownNow --"); + + for (int i=0; i< 10; i++) { + ExecutorService pool = null; + AsynchronousChannelGroup group; + if (rand.nextBoolean()) { + pool = Executors.newCachedThreadPool(); + group = AsynchronousChannelGroup + .withCachedThreadPool(pool, rand.nextInt(5)); + } else { + int nThreads = 1 + rand.nextInt(8); + group = AsynchronousChannelGroup + .withFixedThreadPool(nThreads, threadFactory); + } + + // I/O in progress + AsynchronousChannel ch; + if (rand.nextBoolean()) { + AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel + .open(group).bind(new InetSocketAddress(0)); + listener.accept(); + ch = listener; + } else { + AsynchronousDatagramChannel adc = + AsynchronousDatagramChannel.open(null, group); + adc.receive(ByteBuffer.allocate(100)); + ch = adc; + } + + // forceful shutdown + group.shutdownNow(); + + // shutdownNow is required to close all channels + if (ch.isOpen()) + throw new RuntimeException("Channel should be closed"); + + boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS); + if (!terminated) + throw new RuntimeException("Group should have terminated"); + if (pool != null && !pool.isTerminated()) + throw new RuntimeException("Executor should have terminated"); + } + } + + // test creating channels in group after group is shutdown + static void afterShutdownTests() throws Exception { + System.out.println("-- test operations after group is shutdown --"); + AsynchronousChannelGroup group = + AsynchronousChannelGroup.withFixedThreadPool(1, threadFactory); + + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group); + AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open(group); + + // initiate accept + listener.bind(new InetSocketAddress(0)); + Future<AsynchronousSocketChannel> result = listener.accept(); + + // shutdown group + group.shutdown(); + if (!group.isShutdown()) + throw new RuntimeException("Group should be shutdown"); + + // attempt to create another channel + try { + AsynchronousSocketChannel.open(group); + throw new RuntimeException("ShutdownChannelGroupException expected"); + } catch (ShutdownChannelGroupException x) { + } + try { + AsynchronousServerSocketChannel.open(group); + throw new RuntimeException("ShutdownChannelGroupException expected"); + } catch (ShutdownChannelGroupException x) { + } + + // attempt to create another channel by connecting. This should cause + // the accept operation to fail. + InetAddress lh = InetAddress.getLocalHost(); + int port = ((InetSocketAddress)listener.getLocalAddress()).getPort(); + InetSocketAddress isa = new InetSocketAddress(lh, port); + ch.connect(isa).get(); + try { + result.get(); + throw new RuntimeException("Connection was accepted"); + } catch (ExecutionException x) { + Throwable cause = x.getCause(); + if (!(cause instanceof IOException)) + throw new RuntimeException("Cause should be IOException"); + cause = cause.getCause(); + if (!(cause instanceof ShutdownChannelGroupException)) + throw new RuntimeException("IOException cause should be ShutdownChannelGroupException"); + } + + // initiate another accept even though channel group is shutdown. + Future<AsynchronousSocketChannel> res = listener.accept(); + try { + res.get(3, TimeUnit.SECONDS); + throw new RuntimeException("TimeoutException expected"); + } catch (TimeoutException x) { + } + // connect to the listener which should cause the accept to complete + AsynchronousSocketChannel.open().connect(isa); + try { + res.get(); + throw new RuntimeException("Connection was accepted"); + } catch (ExecutionException x) { + Throwable cause = x.getCause(); + if (!(cause instanceof IOException)) + throw new RuntimeException("Cause should be IOException"); + cause = cause.getCause(); + if (!(cause instanceof ShutdownChannelGroupException)) + throw new RuntimeException("IOException cause should be ShutdownChannelGroupException"); + } + + // group should *not* terminate as channels are open + boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS); + if (terminated) + throw new RuntimeException("Group should not have terminated"); + + // close channel; group should terminate quickly + ch.close(); + listener.close(); + terminated = group.awaitTermination(3, TimeUnit.SECONDS); + if (!terminated) + throw new RuntimeException("Group should have terminated"); + } + + static void miscTests() throws Exception { + System.out.println("-- miscellenous tests --"); + try { + AsynchronousChannelGroup.withFixedThreadPool(1, null); + throw new RuntimeException("NPE expected"); + } catch (NullPointerException x) { + } + try { + AsynchronousChannelGroup.withFixedThreadPool(0, threadFactory); + throw new RuntimeException("IAE expected"); + } catch (IllegalArgumentException e) { + } + try { + AsynchronousChannelGroup.withCachedThreadPool(null, 0); + throw new RuntimeException("NPE expected"); + } catch (NullPointerException x) { + } + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java new file mode 100644 index 00000000000..b116245ceaf --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java @@ -0,0 +1,140 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousChannelGroup + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.concurrent.*; +import java.io.IOException; + +/** + * This test verifies that a channel or channel group can be closed from a + * completion handler when there are no threads available to handle I/O events. + */ + +public class GroupOfOne { + + public static void main(String[] args) throws Exception { + // create listener to accept connections + final AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open() + .bind(new InetSocketAddress(0)); + listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() { + public void completed(AsynchronousSocketChannel ch, Void att) { + listener.accept(null, this); + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + + int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); + SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port); + + test(sa, true, false); + test(sa, false, true); + test(sa, true, true); + } + + static void test(SocketAddress sa, + final boolean closeChannel, + final boolean shutdownGroup) + throws Exception + { + // group with 1 thread + final AsynchronousChannelGroup group = AsynchronousChannelGroup + .withFixedThreadPool(1, new ThreadFactory() { + @Override + public Thread newThread(final Runnable r) { + return new Thread(r); + }}); + final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group); + + // the latch counts down when: + // 1. The read operation fails (expected) + // 2. the close/shutdown completes + final CountDownLatch latch = new CountDownLatch(2); + + ch.connect(sa, null, new CompletionHandler<Void,Void>() { + public void completed(Void result, Void att) { + System.out.println("Connected"); + + // initiate I/O operation that does not complete (successfully) + ByteBuffer buf = ByteBuffer.allocate(100); + ch.read(buf, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer bytesRead, Void att) { + throw new RuntimeException(); + } + public void failed(Throwable exc, Void att) { + if (!(exc instanceof AsynchronousCloseException)) + throw new RuntimeException(exc); + System.out.println("Read failed (expected)"); + latch.countDown(); + } + public void cancelled(Void att) { + throw new RuntimeException(); + } + }); + + // close channel or shutdown group + try { + if (closeChannel) { + System.out.print("Close channel ..."); + ch.close(); + System.out.println(" done."); + } + if (shutdownGroup) { + System.out.print("Shutdown group ..."); + group.shutdownNow(); + System.out.println(" done."); + } + latch.countDown(); + } catch (IOException e) { + throw new RuntimeException(); + } + } + public void failed(Throwable exc, Void att) { + throw new RuntimeException(exc); + } + public void cancelled(Void att) { + throw new RuntimeException(); + } + }); + + latch.await(); + + // clean-up + group.shutdown(); + boolean terminated = group.awaitTermination(5, TimeUnit.SECONDS); + if (!terminated) + throw new RuntimeException("Group did not terminate"); + + System.out.println("TEST OKAY"); + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java new file mode 100644 index 00000000000..f41c12c807f --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java @@ -0,0 +1,166 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousChannelGroup + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +/** + * Tests that the completion handler is invoked by a thread with + * the expected identity. + */ + +public class Identity { + static final Random rand = new Random(); + static final CountDownLatch done = new CountDownLatch(1); + static final AtomicBoolean failed = new AtomicBoolean(false); + + static void fail(String msg) { + failed.set(true); + done.countDown(); + throw new RuntimeException(msg); + } + + // thread-local identifies the thread + private static final ThreadLocal<Integer> myGroup = + new ThreadLocal<Integer>() { + @Override protected Integer initialValue() { + return Integer.valueOf(-1); + } + }; + + // creates a ThreadFactory that constructs groups with the given identity + static final ThreadFactory createThreadFactory(final int groupId) { + return new ThreadFactory() { + @Override + public Thread newThread(final Runnable r) { + Thread t = new Thread(new Runnable() { + public void run() { + myGroup.set(groupId); + r.run(); + }}); + t.setDaemon(true); + return t; + } + }; + } + + public static void main(String[] args) throws Exception { + // create listener to accept connections + final AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open() + .bind(new InetSocketAddress(0)); + listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() { + public void completed(final AsynchronousSocketChannel ch, Void att) { + listener.accept(null, this); + + final ByteBuffer buf = ByteBuffer.allocate(100); + ch.read(buf, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer bytesRead, Void att) { + buf.clear(); + ch.read(buf, null, this); + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); + SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port); + + // create 3-10 channels, each in its own group + final int groupCount = 3 + rand.nextInt(8); + final AsynchronousSocketChannel[] channel = new AsynchronousSocketChannel[groupCount]; + for (int i=0; i<groupCount; i++) { + ThreadFactory factory = createThreadFactory(i); + AsynchronousChannelGroup group; + if (rand.nextBoolean()) { + int nThreads = 1 + rand.nextInt(10); + group = AsynchronousChannelGroup.withFixedThreadPool(nThreads, factory); + } else { + ExecutorService pool = Executors.newCachedThreadPool(factory); + group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(5)); + } + + // create channel in group and connect it to the server + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group); + ch.connect(sa).get(); + channel[i] = ch; + } + + // randomly write to each channel, ensuring that the completion handler + // is always invoked by a thread with the right identity. + final AtomicInteger writeCount = new AtomicInteger(100); + channel[0].write(getBuffer(), 0, new CompletionHandler<Integer,Integer>() { + public void completed(Integer bytesWritten, Integer groupId) { + if (bytesWritten != 1) + fail("Expected 1 byte to be written"); + if (!myGroup.get().equals(groupId)) + fail("Handler invoked by thread with the wrong identity"); + if (writeCount.decrementAndGet() > 0) { + int id = rand.nextInt(groupCount); + channel[id].write(getBuffer(), id, this); + } else { + done.countDown(); + } + } + public void failed(Throwable exc, Integer groupId) { + fail(exc.getMessage()); + } + public void cancelled(Integer groupId) { + fail("I/O operation was cancelled"); + } + }); + + // wait until + done.await(); + if (failed.get()) + throw new RuntimeException("Test failed - see log for details"); + } + + static ByteBuffer getBuffer() { + ByteBuffer buf; + if (rand.nextBoolean()) { + buf = ByteBuffer.allocateDirect(1); + } else { + buf = ByteBuffer.allocate(1); + } + buf.put((byte)0); + buf.flip(); + return buf; + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/PrivilegedThreadFactory.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/PrivilegedThreadFactory.java new file mode 100644 index 00000000000..e2c4575c72d --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/PrivilegedThreadFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.util.concurrent.ThreadFactory; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * The "privileged" ThreadFactory used by the AsExecutor test. + */ + +public class PrivilegedThreadFactory implements ThreadFactory { + public void PrivilegedThreadPoolFactory() { + // check class is on boot class path + if (PrivilegedThreadFactory.class.getClassLoader() != null) + throw new RuntimeException("PrivilegedThreadFactory class not on boot class path"); + } + + @Override + public Thread newThread(final Runnable r) { + return AccessController.doPrivileged(new PrivilegedAction<Thread>() { + @Override + public Thread run() { + Thread t = new Thread(r); + t.setDaemon(true); + return t; + } + }); + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java new file mode 100644 index 00000000000..567321e3008 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java @@ -0,0 +1,133 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousChannelGroup + * @build Restart + * @run main/othervm -XX:-UseVMInterruptibleIO Restart + */ + +import java.nio.channels.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.io.IOException; + +/** + * Exercise replacement of threads in the thread pool when completion handlers + * terminate due to errors or runtime exceptions. + */ + +public class Restart { + static final Random rand = new Random(); + + public static void main(String[] args) throws Exception { + // thread group for thread pools + final ThreadGroup tg = new ThreadGroup("test"); + + // keep track of the number of threads that terminate + final AtomicInteger exceptionCount = new AtomicInteger(0); + final Thread.UncaughtExceptionHandler ueh = + new Thread.UncaughtExceptionHandler() { + public void uncaughtException(Thread t, Throwable e) { + exceptionCount.incrementAndGet(); + } + }; + ThreadFactory factory = new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(tg, r); + t.setUncaughtExceptionHandler(ueh); + return t; + } + }; + + // group with fixed thread pool + int nThreads = 1 + rand.nextInt(4); + AsynchronousChannelGroup group = + AsynchronousChannelGroup.withFixedThreadPool(nThreads, factory); + testRestart(group, 100); + group.shutdown(); + + // group with custom thread pool + ExecutorService pool = Executors.newCachedThreadPool(factory); + group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(5)); + testRestart(group, 100); + group.shutdown(); + + // give time for threads to terminate + Thread.sleep(3000); + int actual = exceptionCount.get(); + if (actual != 200) + throw new RuntimeException(actual + " exceptions, expected: " + 200); + } + + static void testRestart(AsynchronousChannelGroup group, int count) + throws Exception + { + AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open(group) + .bind(new InetSocketAddress(0)); + + for (int i=0; i<count; i++) { + final CountDownLatch latch = new CountDownLatch(1); + + listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() { + public void completed(AsynchronousSocketChannel ch, Void att) { + try { + ch.close(); + } catch (IOException ignore) { } + + latch.countDown(); + + // throw error or runtime exception + if (rand.nextBoolean()) { + throw new Error(); + } else { + throw new RuntimeException(); + } + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + + // establish loopback connection which should cause completion + // handler to be invoked. + int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + InetAddress lh = InetAddress.getLocalHost(); + ch.connect(new InetSocketAddress(lh, port)).get(); + ch.close(); + + // wait for handler to be invoked + latch.await(); + } + + // clean-up + listener.close(); + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java new file mode 100644 index 00000000000..f615c3c5063 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java @@ -0,0 +1,120 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousChannelGroup + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.concurrent.*; +import java.io.IOException; + +public class Unbounded { + // number of concurrent completion handlers + static final int CONCURRENCY_COUNT = 512; + + public static void main(String[] args) throws Exception { + // all accepted connections are added to a queue + final ArrayBlockingQueue<AsynchronousSocketChannel> queue = + new ArrayBlockingQueue<AsynchronousSocketChannel>(CONCURRENCY_COUNT); + + // create listener to accept connections + final AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open() + .bind(new InetSocketAddress(0)); + listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() { + public void completed(AsynchronousSocketChannel ch, Void att) { + queue.add(ch); + listener.accept(null, this); + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + System.out.println("Listener created."); + + // establish lots of connections + int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); + SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port); + AsynchronousSocketChannel[] channels = + new AsynchronousSocketChannel[CONCURRENCY_COUNT]; + for (int i=0; i<CONCURRENCY_COUNT; i++) { + int attempts = 0; + for (;;) { + try { + channels[i] = AsynchronousSocketChannel.open(); + channels[i].connect(sa).get(); + break; + } catch (IOException x) { + // probably resource issue so back off and retry + if (++attempts >= 3) + throw x; + Thread.sleep(50); + } + } + } + System.out.println("All connection established."); + + // the barrier where all threads (plus the main thread) wait + final CyclicBarrier barrier = new CyclicBarrier(CONCURRENCY_COUNT+1); + + // initiate a read operation on each channel. + for (int i=0; i<CONCURRENCY_COUNT; i++) { + ByteBuffer buf = ByteBuffer.allocateDirect(100); + channels[i].read( buf, channels[i], + new CompletionHandler<Integer,AsynchronousSocketChannel>() { + public void completed(Integer bytesRead, AsynchronousSocketChannel ch) { + try { + ch.close(); + barrier.await(); + } catch (Exception x) { + throw new AssertionError(x); + } + } + public void failed(Throwable exc, AsynchronousSocketChannel ch) { + } + public void cancelled(AsynchronousSocketChannel ch) { + } + }); + } + System.out.println("All read operations outstanding."); + + // write data to each of the accepted connections + int remaining = CONCURRENCY_COUNT; + while (remaining > 0) { + AsynchronousSocketChannel ch = queue.take(); + ch.write(ByteBuffer.wrap("welcome".getBytes())).get(); + ch.close(); + remaining--; + } + + // wait for all threads to reach the barrier + System.out.println("Waiting for all threads to reach barrier"); + barrier.await(); + listener.close(); + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/run_any_task.sh b/jdk/test/java/nio/channels/AsynchronousChannelGroup/run_any_task.sh new file mode 100644 index 00000000000..97f4f968a76 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/run_any_task.sh @@ -0,0 +1,52 @@ +# +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 4607272 +# @summary Unit test for AsynchronousChannelGrou#execute +# @build AsExecutor PrivilegedThreadFactory Attack +# @run shell run_any_task.sh + +# if TESTJAVA isn't set then we assume an interactive run. + +if [ -z "$TESTJAVA" ]; then + TESTSRC=. + TESTCLASSES=. + JAVA=java + JAR=jar +else + JAVA="${TESTJAVA}/bin/java" + JAR="${TESTJAVA}/bin/jar" +fi + +echo "Creating JAR file ..." +$JAR -cf "${TESTCLASSES}/Privileged.jar" \ + -C "${TESTCLASSES}" PrivilegedThreadFactory.class \ + -C "${TESTCLASSES}" PrivilegedThreadFactory\$1.class \ + -C "${TESTCLASSES}" Attack.class + +echo "Running test ..." +$JAVA -XX:-UseVMInterruptibleIO \ + -Xbootclasspath/a:"${TESTCLASSES}/Privileged.jar" \ + -classpath "${TESTCLASSES}" \ + AsExecutor diff --git a/jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java b/jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java new file mode 100644 index 00000000000..5ed3d83a90d --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java @@ -0,0 +1,448 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4527345 + * @summary Unit test for AsynchronousDatagramChannel + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +public class Basic { + + public static void main(String[] args) throws Exception { + doReceiveTests(); + doReadTests(); + doSendTests(); + doWriteTests(); + doCancelTests(); + doMulticastTests(); + } + + // basic receive tests + static void doReceiveTests() throws Exception { + final byte[] msg = "hello".getBytes(); + + AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open() + .bind(new InetSocketAddress(0)); + int port = ((InetSocketAddress)(ch.getLocalAddress())).getPort(); + InetAddress rh = InetAddress.getLocalHost(); + final SocketAddress sa = new InetSocketAddress(rh, port); + + DatagramChannel sender = DatagramChannel.open(); + ByteBuffer dst = ByteBuffer.allocateDirect(100); + + // Test: datagram packet received immediately + sender.send(ByteBuffer.wrap(msg), sa); + dst.clear(); + ch.receive(dst).get(1, TimeUnit.SECONDS); + if (dst.flip().remaining() != msg.length) + throw new RuntimeException("Unexpected number of bytes read"); + + // Test: datagram packet not received immediately + dst.clear(); + final CountDownLatch latch = new CountDownLatch(1); + ch.receive(dst, null, new CompletionHandler<SocketAddress,Void>() { + public void completed(SocketAddress source, Void att) { + latch.countDown(); + } + public void failed (Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + Thread.sleep(2000); + sender.send(ByteBuffer.wrap(msg), sa); + latch.await(2, TimeUnit.SECONDS); // wait for completion handler + + // Test: timeout + dst.clear(); + final AtomicReference<Throwable> exception = new AtomicReference<Throwable>(); + ch.receive(dst, 2, TimeUnit.SECONDS, null, new CompletionHandler<SocketAddress,Void>() { + public void completed(SocketAddress source, Void att) { + } + public void failed (Throwable exc, Void att) { + exception.set(exc); + } + public void cancelled(Void att) { + } + }); + Throwable result; + while ((result = exception.get()) == null) { + Thread.sleep(100); + } + if (!(result instanceof InterruptedByTimeoutException)) + throw new RuntimeException("InterruptedByTimeoutException expected"); + + // AsynchronousCloseException + dst = ByteBuffer.allocateDirect(100); + exception.set(null); + ch.receive(dst, null, new CompletionHandler<SocketAddress,Void>() { + public void completed(SocketAddress source, Void att) { + } + public void failed (Throwable exc, Void att) { + exception.set(exc); + } + public void cancelled(Void att) { + } + }); + ch.close(); + while ((result = exception.get()) == null) { + Thread.sleep(100); + } + if (!(result instanceof AsynchronousCloseException)) + throw new RuntimeException("AsynchronousCloseException expected"); + + // done + sender.close(); + } + + // basic read tests + static void doReadTests() throws Exception { + final byte[] msg = "hello".getBytes(); + + AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open() + .bind(new InetSocketAddress(0)); + int port = ((InetSocketAddress)(ch.getLocalAddress())).getPort(); + InetAddress lh = InetAddress.getLocalHost(); + final SocketAddress sa = new InetSocketAddress(lh, port); + + DatagramChannel sender = DatagramChannel.open(); + ByteBuffer dst = ByteBuffer.allocateDirect(100); + + // Test: not connected + try { + ch.read(dst); + throw new RuntimeException("NotYetConnectedException expected"); + } catch (NotYetConnectedException e) { + } + + // connect the channel + sender.bind(new InetSocketAddress(0)); + ch.connect(new InetSocketAddress(lh, + ((InetSocketAddress)(sender.getLocalAddress())).getPort())); + + // Test: datagram packet received immediately + sender.send(ByteBuffer.wrap(msg), sa); + dst.clear(); + ch.read(dst).get(1, TimeUnit.SECONDS); + if (dst.flip().remaining() != msg.length) + throw new RuntimeException("Unexpected number of bytes read"); + + // Test: datagram packet not received immediately + dst.clear(); + final CountDownLatch l1 = new CountDownLatch(1); + ch.read(dst, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer bytesRead, Void att) { + l1.countDown(); + } + public void failed (Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + Thread.sleep(2000); + sender.send(ByteBuffer.wrap(msg), sa); + l1.await(2, TimeUnit.SECONDS); + + // Test: timeout + dst.clear(); + final AtomicReference<Throwable> exception = new AtomicReference<Throwable>(); + ch.read(dst, 2, TimeUnit.SECONDS, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer bytesRead, Void att) { + } + public void failed (Throwable exc, Void att) { + exception.set(exc); + } + public void cancelled(Void att) { + } + }); + Throwable result; + while ((result = exception.get()) == null) { + Thread.sleep(100); + } + if (!(result instanceof InterruptedByTimeoutException)) + throw new RuntimeException("InterruptedByTimeoutException expected"); + + // AsynchronousCloseException + dst.clear(); + exception.set(null); + ch.read(dst, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer bytesRead, Void att) { + } + public void failed (Throwable exc, Void att) { + exception.set(exc); + } + public void cancelled(Void att) { + } + }); + ch.close(); + while ((result = exception.get()) == null) { + Thread.sleep(100); + } + if (!(result instanceof AsynchronousCloseException)) + throw new RuntimeException("AsynchronousCloseException expected"); + + // done + sender.close(); + } + + // basic send tests + static void doSendTests() throws Exception { + final byte[] msg = "hello".getBytes(); + + DatagramChannel reader = DatagramChannel.open() + .bind(new InetSocketAddress(0)); + int port = ((InetSocketAddress)(reader.getLocalAddress())).getPort(); + InetAddress rh = InetAddress.getLocalHost(); + SocketAddress sa = new InetSocketAddress(rh, port); + + AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open(); + + // Test: send datagram packet to reader + int bytesSent = ch.send(ByteBuffer.wrap(msg), sa).get(); + if (bytesSent != msg.length) + throw new RuntimeException("Unexpected number of bytes sent"); + + // check received + ByteBuffer dst = ByteBuffer.allocateDirect(100); + reader.receive(dst); + dst.flip(); + if (dst.remaining() != msg.length) + throw new RuntimeException("Unexpected number of bytes received"); + + // Test: send datagram packet to reader and check completion handler + // is invoked + final CountDownLatch l2 = new CountDownLatch(1); + ch.send(ByteBuffer.wrap(msg), sa, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer bytesSent, Void att) { + if (bytesSent != msg.length) + throw new RuntimeException("Unexpected number of bytes received"); + l2.countDown(); + } + public void failed (Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + l2.await(5, TimeUnit.SECONDS); + + // check received + dst.clear(); + reader.receive(dst); + dst.flip(); + if (dst.remaining() != msg.length) + throw new RuntimeException("Unexpected number of bytes received"); + + // Test: check that failed method is invoked + ch.close(); + final CountDownLatch l3 = new CountDownLatch(1); + ch.send(ByteBuffer.wrap(msg), sa, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer bytesSent, Void att) { + throw new RuntimeException("completed method invoked"); + } + public void failed (Throwable exc, Void att) { + if (exc instanceof ClosedChannelException) { + l3.countDown(); + } else { + throw new RuntimeException(exc); + } + } + public void cancelled(Void att) { + } + }); + l3.await(5, TimeUnit.SECONDS); + + // done + reader.close(); + } + + // basic write tests + static void doWriteTests() throws Exception { + final byte[] msg = "hello".getBytes(); + + DatagramChannel reader = DatagramChannel.open() + .bind(new InetSocketAddress(0)); + int port = ((InetSocketAddress)(reader.getLocalAddress())).getPort(); + InetAddress rh = InetAddress.getLocalHost(); + SocketAddress sa = new InetSocketAddress(rh, port); + + AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open(); + + // Test: unconnected + try { + ch.write(ByteBuffer.wrap(msg)).get(); + throw new RuntimeException("NotYetConnectedException expected"); + } catch (NotYetConnectedException e) { + } + + // Test: connect, and write datagram + ch.connect(sa); + int bytesSent = ch.write(ByteBuffer.wrap(msg)).get(); + if (bytesSent != msg.length) + throw new RuntimeException("Unexpected number of bytes sent"); + + // check received + ByteBuffer dst = ByteBuffer.allocateDirect(100); + reader.receive(dst); + dst.flip(); + if (dst.remaining() != msg.length) + throw new RuntimeException("Unexpected number of bytes received"); + + // Test: write datagram and check completion handler is invoked + final CountDownLatch l2 = new CountDownLatch(1); + ch.write(ByteBuffer.wrap(msg), null, new CompletionHandler<Integer,Void>() { + public void completed(Integer bytesSent, Void att) { + if (bytesSent != msg.length) + throw new RuntimeException("Unexpected number of bytes received"); + l2.countDown(); + } + public void failed (Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + l2.await(5, TimeUnit.SECONDS); + + // check received + dst.clear(); + reader.receive(dst); + dst.flip(); + if (dst.remaining() != msg.length) + throw new RuntimeException("Unexpected number of bytes received"); + + // done + ch.close(); + reader.close(); + } + + static void cancelAndCheck(Future<?> result, CountDownLatch latch) + throws InterruptedException + { + boolean cancelled = result.cancel(false); + if (!cancelled) + throw new RuntimeException("Not cancelled"); + if (!result.isDone()) + throw new RuntimeException("Should be done"); + try { + result.get(); + throw new RuntimeException("Result not expected"); + } catch (CancellationException e) { + // expected + } catch (ExecutionException e) { + throw new RuntimeException("Should not fail"); + } + + // make sure that completion handler is invoked + latch.await(); + } + + // basic cancel tests + static void doCancelTests() throws Exception { + InetAddress lh = InetAddress.getLocalHost(); + + // timed and non-timed receive + for (int i=0; i<2; i++) { + AsynchronousDatagramChannel ch = + AsynchronousDatagramChannel.open().bind(new InetSocketAddress(0)); + final CountDownLatch latch = new CountDownLatch(1); + long timeout = (i == 0) ? 0L : 60L; + Future<SocketAddress> remote = ch + .receive(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, null, + new CompletionHandler<SocketAddress,Void>() { + public void completed(SocketAddress source, Void att) { + } + public void failed (Throwable exc, Void att) { + } + public void cancelled(Void att) { + latch.countDown(); + } + }); + cancelAndCheck(remote, latch); + ch.close(); + } + + // timed and non-timed read + for (int i=0; i<2; i++) { + AsynchronousDatagramChannel ch = + AsynchronousDatagramChannel.open().bind(new InetSocketAddress(0)); + ch.connect(new InetSocketAddress(lh, + ((InetSocketAddress)(ch.getLocalAddress())).getPort())); + final CountDownLatch latch = new CountDownLatch(1); + long timeout = (i == 0) ? 0L : 60L; + Future<Integer> result = ch + .read(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, null, + new CompletionHandler<Integer,Void>() { + public void completed(Integer bytesRead, Void att) { + } + public void failed (Throwable exc, Void att) { + } + public void cancelled(Void att) { + latch.countDown(); + } + }); + cancelAndCheck(result, latch); + ch.close(); + } + } + + // basic multicast test + static void doMulticastTests() throws Exception { + final byte[] msg = "hello".getBytes(); + + AsynchronousDatagramChannel ch = AsynchronousDatagramChannel + .open(StandardProtocolFamily.INET, null) + .setOption(StandardSocketOption.SO_REUSEADDR, true) + .bind(new InetSocketAddress(0)); + + InetAddress lh = InetAddress.getLocalHost(); + int port = ((InetSocketAddress)(ch.getLocalAddress())).getPort(); + + // join group + InetAddress group = InetAddress.getByName("225.4.5.6"); + NetworkInterface interf = NetworkInterface.getByInetAddress(lh); + MembershipKey key = ch.join(group, interf); + + // check key + if (key.channel() != ch) + throw new RuntimeException("Not the expected channel"); + + // send message to group + DatagramChannel sender = DatagramChannel.open(); + sender.send(ByteBuffer.wrap(msg), new InetSocketAddress(group, port)); + sender.close(); + + // check message received + ByteBuffer dst = ByteBuffer.allocate(200); + SocketAddress source = ch.receive(dst).get(2, TimeUnit.SECONDS); + if (!((InetSocketAddress)source).getAddress().equals(lh)) + throw new RuntimeException("Unexpected source"); + + // done + ch.close(); + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java b/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java new file mode 100644 index 00000000000..5ffb42c0b8b --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java @@ -0,0 +1,585 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousFileChannel + */ + +import java.nio.file.*; +import java.nio.channels.*; +import java.nio.ByteBuffer; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; +import static java.nio.file.StandardOpenOption.*; + +public class Basic { + + private static final Random rand = new Random(); + + public static void main(String[] args) throws IOException { + // create temporary file + File blah = File.createTempFile("blah", null); + blah.deleteOnExit(); + + final AsynchronousFileChannel ch = AsynchronousFileChannel + .open(blah.toPath(), READ, WRITE); + + // run tests + testUsingCompletionHandlers(ch); + testUsingWaitOnResult(ch); + testLocking(ch); + testInterruptHandlerThread(ch); + + // close channel and invoke test that expects channel to be closed + ch.close(); + testClosedChannel(ch); + + // these tests open the file themselves + testCustomThreadPool(blah.toPath()); + testAsynchronousClose(blah.toPath()); + testCancel(blah.toPath()); + testTruncate(blah.toPath()); + } + + /* + * Generate buffer with random contents + * Writes buffer to file using a CompletionHandler to consume the result + * of each write operation + * Reads file to EOF to a new buffer using a CompletionHandler to consume + * the result of each read operation + * Compares buffer contents + */ + static void testUsingCompletionHandlers(AsynchronousFileChannel ch) + throws IOException + { + System.out.println("testUsingCompletionHandlers"); + + ch.truncate(0L); + + // generate buffer with random elements and write it to file + ByteBuffer src = genBuffer(); + writeFully(ch, src, 0L); + + // read to EOF or buffer is full + ByteBuffer dst = (rand.nextBoolean()) ? + ByteBuffer.allocateDirect(src.capacity()) : + ByteBuffer.allocate(src.capacity()); + readAll(ch, dst, 0L); + + // check buffers are the same + src.flip(); + dst.flip(); + if (!src.equals(dst)) { + throw new RuntimeException("Contents differ"); + } + } + + /* + * Generate buffer with random contents + * Writes buffer to file, invoking the Future's get method to wait for + * each write operation to complete + * Reads file to EOF to a new buffer, invoking the Future's get method to + * wait for each write operation to complete + * Compares buffer contents + */ + static void testUsingWaitOnResult(AsynchronousFileChannel ch) + throws IOException + { + System.out.println("testUsingWaitOnResult"); + + ch.truncate(0L); + + // generate buffer + ByteBuffer src = genBuffer(); + + // write buffer completely to file + long position = 0L; + while (src.hasRemaining()) { + Future<Integer> result = ch.write(src, position); + try { + int n = result.get(); + // update position + position += n; + } catch (ExecutionException x) { + throw new RuntimeException(x.getCause()); + } catch (InterruptedException x) { + throw new RuntimeException(x); + } + } + + // read file into new buffer + ByteBuffer dst = (rand.nextBoolean()) ? + ByteBuffer.allocateDirect(src.capacity()) : + ByteBuffer.allocate(src.capacity()); + position = 0L; + int n; + do { + Future<Integer> result = ch.read(dst, position); + try { + n = result.get(); + + // update position + if (n > 0) position += n; + } catch (ExecutionException x) { + throw new RuntimeException(x.getCause()); + } catch (InterruptedException x) { + throw new RuntimeException(x); + } + } while (n > 0); + + // check buffers are the same + src.flip(); + dst.flip(); + if (!src.equals(dst)) { + throw new RuntimeException("Contents differ"); + } + } + + // exercise lock methods + static void testLocking(AsynchronousFileChannel ch) + throws IOException + { + System.out.println("testLocking"); + + // test 1 - acquire lock and check that tryLock throws + // OverlappingFileLockException + FileLock fl; + try { + fl = ch.lock().get(); + } catch (ExecutionException x) { + throw new RuntimeException(x); + } catch (InterruptedException x) { + throw new RuntimeException("Should not be interrupted"); + } + if (!fl.acquiredBy().equals(ch)) + throw new RuntimeException("FileLock#acquiredBy returned incorrect channel"); + try { + ch.tryLock(); + throw new RuntimeException("OverlappingFileLockException expected"); + } catch (OverlappingFileLockException x) { + } + fl.release(); + + // test 2 - acquire try and check that lock throws OverlappingFileLockException + fl = ch.tryLock(); + if (fl == null) + throw new RuntimeException("Unable to acquire lock"); + try { + ch.lock(null, new CompletionHandler<FileLock,Void> () { + public void completed(FileLock result, Void att) { + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + throw new RuntimeException("OverlappingFileLockException expected"); + } catch (OverlappingFileLockException x) { + } + fl.release(); + } + + // interrupt should not close channel + static void testInterruptHandlerThread(final AsynchronousFileChannel ch) { + System.out.println("testInterruptHandlerThread"); + + ByteBuffer buf = ByteBuffer.allocateDirect(100); + final CountDownLatch latch = new CountDownLatch(1); + + ch.read(buf, 0L, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer result, Void att) { + try { + Thread.currentThread().interrupt(); + long size = ch.size(); + latch.countDown(); + } catch (IOException x) { + x.printStackTrace(); + } + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + + // wait for handler to complete + await(latch); + } + + // invoke method on closed channel + static void testClosedChannel(AsynchronousFileChannel ch) { + System.out.println("testClosedChannel"); + + if (ch.isOpen()) + throw new RuntimeException("Channel should be closed"); + + ByteBuffer buf = ByteBuffer.allocateDirect(100); + + // check read fails with ClosedChannelException + try { + ch.read(buf, 0L).get(); + throw new RuntimeException("ExecutionException expected"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof ClosedChannelException)) + throw new RuntimeException("Cause of ClosedChannelException expected"); + } catch (InterruptedException x) { + } + + // check write fails with ClosedChannelException + try { + ch.write(buf, 0L).get(); + throw new RuntimeException("ExecutionException expected"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof ClosedChannelException)) + throw new RuntimeException("Cause of ClosedChannelException expected"); + } catch (InterruptedException x) { + } + + // check lock fails with ClosedChannelException + try { + ch.lock().get(); + throw new RuntimeException("ExecutionException expected"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof ClosedChannelException)) + throw new RuntimeException("Cause of ClosedChannelException expected"); + } catch (InterruptedException x) { + } + } + + + // exercise custom thread pool + static void testCustomThreadPool(Path file) throws IOException { + System.out.println("testCustomThreadPool"); + + // records threads that are created + final List<Thread> threads = new ArrayList<Thread>(); + + ThreadFactory threadFactory = new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setDaemon(true); + synchronized (threads) { + threads.add(t); + } + return t; + } + }; + + // exercise tests with varied number of threads + for (int nThreads=1; nThreads<=5; nThreads++) { + synchronized (threads) { + threads.clear(); + } + ExecutorService executor = Executors.newFixedThreadPool(nThreads, threadFactory); + Set<StandardOpenOption> opts = EnumSet.of(WRITE); + AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, opts, executor); + try { + for (int i=0; i<10; i++) { + // do I/O operation to see which thread invokes the completion handler + final AtomicReference<Thread> invoker = new AtomicReference<Thread>(); + final CountDownLatch latch = new CountDownLatch(1); + + ch.write(genBuffer(), 0L, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer result, Void att) { + invoker.set(Thread.currentThread()); + latch.countDown(); + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + await(latch); + + // check invoker + boolean found = false; + synchronized (threads) { + for (Thread t: threads) { + if (t == invoker.get()) { + found = true; + break; + } + } + } + if (!found) + throw new RuntimeException("Invoker thread not found"); + } + } finally { + ch.close(); + } + } + } + + // exercise asynchronous close + static void testAsynchronousClose(Path file) throws IOException { + System.out.println("testAsynchronousClose"); + + // create file + AsynchronousFileChannel ch = AsynchronousFileChannel + .open(file, WRITE, TRUNCATE_EXISTING); + long size = 0L; + do { + ByteBuffer buf = genBuffer(); + int n = buf.remaining(); + writeFully(ch, buf, size); + size += n; + } while (size < (50L * 1024L * 1024L)); + + ch.close(); + + ch = AsynchronousFileChannel.open(file, WRITE, SYNC); + + // randomize number of writers, buffer size, and positions + + int nwriters = 1 + rand.nextInt(8); + ByteBuffer[] buf = new ByteBuffer[nwriters]; + long[] position = new long[nwriters]; + for (int i=0; i<nwriters; i++) { + buf[i] = genBuffer(); + position[i] = rand.nextInt((int)size); + } + + // initiate I/O + Future[] result = new Future[nwriters]; + for (int i=0; i<nwriters; i++) { + result[i] = ch.write(buf[i], position[i]); + } + + // close file + ch.close(); + + // write operations should complete or fail with AsynchronousCloseException + for (int i=0; i<nwriters; i++) { + try { + result[i].get(); + } catch (ExecutionException x) { + Throwable cause = x.getCause(); + if (!(cause instanceof AsynchronousCloseException)) + throw new RuntimeException(cause); + } catch (CancellationException x) { + throw new RuntimeException(x); // should not happen + } catch (InterruptedException x) { + throw new RuntimeException(x); // should not happen + } + } + } + + // exercise cancel method + static void testCancel(Path file) throws IOException { + System.out.println("testCancel"); + + for (int i=0; i<2; i++) { + boolean mayInterruptIfRunning = (i == 0) ? false : true; + + // open with SYNC option to improve chances that write will not + // complete immediately + AsynchronousFileChannel ch = AsynchronousFileChannel + .open(file, WRITE, SYNC); + + // start write operation + final CountDownLatch latch = new CountDownLatch(1); + Future<Integer> res = ch.write(genBuffer(), 0L, null, + new CompletionHandler<Integer,Void>() { + public void completed(Integer result, Void att) { + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + latch.countDown(); + } + }); + + // cancel operation + boolean cancelled = res.cancel(mayInterruptIfRunning); + + // check post-conditions + if (!res.isDone()) + throw new RuntimeException("isDone should return true"); + if (res.isCancelled() != cancelled) + throw new RuntimeException("isCancelled not consistent"); + try { + res.get(); + if (!cancelled) + throw new RuntimeException("CancellationException expected"); + } catch (CancellationException x) { + // expected + } catch (ExecutionException x) { + throw new RuntimeException(x); + } catch (InterruptedException x) { + throw new RuntimeException(x); + } + try { + res.get(1, TimeUnit.SECONDS); + throw new RuntimeException("CancellationException expected"); + } catch (CancellationException x) { + // expected + } catch (ExecutionException x) { + throw new RuntimeException(x); + } catch (TimeoutException x) { + throw new RuntimeException(x); + } catch (InterruptedException x) { + throw new RuntimeException(x); + } + + // check that cancelled method is invoked + if (cancelled) + await(latch); + + ch.close(); + } + } + + // exercise truncate method + static void testTruncate(Path file) throws IOException { + System.out.println("testTruncate"); + + // basic tests + AsynchronousFileChannel ch = AsynchronousFileChannel + .open(file, CREATE, WRITE, TRUNCATE_EXISTING); + try { + writeFully(ch, genBuffer(), 0L); + long size = ch.size(); + + // attempt to truncate to a size greater than the current size + if (ch.truncate(size + 1L).size() != size) + throw new RuntimeException("Unexpected size after truncation"); + + // truncate file + if (ch.truncate(size - 1L).size() != (size - 1L)) + throw new RuntimeException("Unexpected size after truncation"); + + // invalid size + try { + ch.truncate(-1L); + throw new RuntimeException("IllegalArgumentException expected"); + } catch (IllegalArgumentException e) { } + + } finally { + ch.close(); + } + + // channel is closed + try { + ch.truncate(0L); + throw new RuntimeException("ClosedChannelException expected"); + } catch (ClosedChannelException e) { } + + // channel is read-only + ch = AsynchronousFileChannel.open(file, READ); + try { + try { + ch.truncate(0L); + throw new RuntimeException("NonWritableChannelException expected"); + } catch (NonWritableChannelException e) { } + } finally { + ch.close(); + } + } + + // returns ByteBuffer with random bytes + static ByteBuffer genBuffer() { + int size = 1024 + rand.nextInt(16000); + byte[] buf = new byte[size]; + boolean useDirect = rand.nextBoolean(); + if (useDirect) { + ByteBuffer bb = ByteBuffer.allocateDirect(buf.length); + bb.put(buf); + bb.flip(); + return bb; + } else { + return ByteBuffer.wrap(buf); + } + } + + // writes all remaining bytes in the buffer to the given channel at the + // given position + static void writeFully(final AsynchronousFileChannel ch, + final ByteBuffer src, + long position) + { + final CountDownLatch latch = new CountDownLatch(1); + + // use position as attachment + ch.write(src, position, position, new CompletionHandler<Integer,Long>() { + public void completed(Integer result, Long position) { + int n = result; + if (src.hasRemaining()) { + long p = position + n; + ch.write(src, p, p, this); + } else { + latch.countDown(); + } + } + public void failed(Throwable exc, Long position) { + } + public void cancelled(Long position) { + } + }); + + // wait for writes to complete + await(latch); + } + + static void readAll(final AsynchronousFileChannel ch, + final ByteBuffer dst, + long position) + { + final CountDownLatch latch = new CountDownLatch(1); + + // use position as attachment + ch.read(dst, position, position, new CompletionHandler<Integer,Long>() { + public void completed(Integer result, Long position) { + int n = result; + if (n > 0) { + long p = position + n; + ch.read(dst, p, p, this); + } else { + latch.countDown(); + } + } + public void failed(Throwable exc, Long position) { + } + public void cancelled(Long position) { + } + }); + + // wait for reads to complete + await(latch); + } + + static void await(CountDownLatch latch) { + // wait until done + boolean done = false; + while (!done) { + try { + latch.await(); + done = true; + } catch (InterruptedException x) { } + } + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java b/jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java new file mode 100644 index 00000000000..9f9025dd232 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java @@ -0,0 +1,67 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for java.nio.channels.AsynchronousFileChannel + * @build CustomThreadPool MyThreadFactory + * @run main/othervm -Djava.nio.channels.DefaultThreadPool.threadFactory=MyThreadFactory CustomThreadPool + */ + +import java.io.File; +import static java.nio.file.StandardOpenOption.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.concurrent.atomic.AtomicReference; + +public class CustomThreadPool { + + public static void main(String[] args) throws Exception { + File blah = File.createTempFile("blah", null); + blah.deleteOnExit(); + AsynchronousFileChannel ch = + AsynchronousFileChannel.open(blah.toPath(), READ, WRITE); + ByteBuffer src = ByteBuffer.wrap("Scooby Snacks".getBytes()); + + final AtomicReference<Thread> invoker = new AtomicReference<Thread>(); + ch.write(src, 0, invoker, + new CompletionHandler<Integer,AtomicReference<Thread>>() { + public void completed(Integer result, AtomicReference<Thread> invoker) { + invoker.set(Thread.currentThread()); + } + public void failed(Throwable exc, AtomicReference<Thread> invoker) { + } + public void cancelled(AtomicReference<Thread> invoker) { + } + }); + Thread t; + while ((t = invoker.get()) == null) { + Thread.sleep(100); + } + ch.close(); + + // check handler was run by known thread + if (!MyThreadFactory.created(t)) + throw new RuntimeException("Handler invoked by unknown thread"); + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java b/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java new file mode 100644 index 00000000000..38c0f7d0c6e --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java @@ -0,0 +1,340 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousFileChannel#lock method + */ + +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.file.*; +import static java.nio.file.StandardOpenOption.*; +import java.nio.channels.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Random; +import java.util.concurrent.*; + +public class Lock { + + static final Random rand = new Random(); + + public static void main(String[] args) throws Exception { + if (args.length > 0 && args[0].equals("-lockslave")) { + int port = Integer.parseInt(args[1]); + runLockSlave(port); + System.exit(0); + } + + LockSlaveMirror slave = startLockSlave(); + try { + + // create temporary file + File blah = File.createTempFile("blah", null); + blah.deleteOnExit(); + + testLockProtocol(blah, slave); + testAsyncClose(blah, slave); + + } finally { + slave.shutdown(); + } + } + + // test locking protocol + static void testLockProtocol(File file, LockSlaveMirror slave) + throws Exception + { + FileLock fl; + + // slave VM opens file and acquires exclusive lock + slave.open(file.getPath()).lock(); + + AsynchronousFileChannel ch = AsynchronousFileChannel + .open(file.toPath(), READ, WRITE); + + // this VM tries to acquire lock + // (lock should not be acquire until released by slave VM) + Future<FileLock> result = ch.lock(); + try { + result.get(2, TimeUnit.SECONDS); + throw new RuntimeException("Timeout expected"); + } catch (TimeoutException x) { + } + + // slave VM releases lock + slave.unlock(); + + // this VM should now acquire lock + fl = result.get(); + fl.release(); + + // slave VM acquires lock on range + slave.lock(0, 10, false); + + // this VM acquires lock on non-overlapping range + fl = ch.lock(10, 10, false, null, null).get(); + fl.release(); + + // done + ch.close(); + slave.close(); + } + + // test close of channel with outstanding lock operation + static void testAsyncClose(File file, LockSlaveMirror slave) throws Exception { + // slave VM opens file and acquires exclusive lock + slave.open(file.getPath()).lock(); + + for (int i=0; i<100; i++) { + AsynchronousFileChannel ch = AsynchronousFileChannel + .open(file.toPath(), READ, WRITE); + + // try to lock file (should not complete because file is locked by slave) + Future<FileLock> result = ch.lock(); + try { + result.get(rand.nextInt(100), TimeUnit.MILLISECONDS); + throw new RuntimeException("Timeout expected"); + } catch (TimeoutException x) { + } + + // close channel with lock operation outstanding + ch.close(); + + // operation should complete with AsynchronousCloseException + try { + result.get(); + throw new RuntimeException("ExecutionException expected"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof AsynchronousCloseException)) { + x.getCause().printStackTrace(); + throw new RuntimeException("AsynchronousCloseException expected"); + } + } + } + + slave.close(); + } + + // starts a "lock slave" in another process, returning a mirror object to + // control the slave + static LockSlaveMirror startLockSlave() throws Exception { + ServerSocketChannel ssc = ServerSocketChannel.open() + .bind(new InetSocketAddress(0)); + int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort(); + + String sep = FileSystems.getDefault().getSeparator(); + + String command = System.getProperty("java.home") + + sep + "bin" + sep + "java Lock -lockslave " + port; + Process p = Runtime.getRuntime().exec(command); + IOHandler.handle(p.getInputStream()); + IOHandler.handle(p.getErrorStream()); + + // wait for slave to connect + SocketChannel sc = ssc.accept(); + return new LockSlaveMirror(sc); + } + + // commands that the slave understands + static final String OPEN_CMD = "open"; + static final String CLOSE_CMD = "close"; + static final String LOCK_CMD = "lock"; + static final String UNLOCK_CMD = "unlock"; + static final char TERMINATOR = ';'; + + // provides a proxy to a "lock slave" + static class LockSlaveMirror { + private final SocketChannel sc; + + LockSlaveMirror(SocketChannel sc) { + this.sc = sc; + } + + private void sendCommand(String cmd, String... params) + throws IOException + { + for (String s: params) { + cmd += " " + s; + } + cmd += TERMINATOR; + + ByteBuffer buf = Charset.defaultCharset().encode(cmd); + while (buf.hasRemaining()) { + sc.write(buf); + } + + // wait for ack + buf = ByteBuffer.allocate(1); + int n = sc.read(buf); + if (n != 1) + throw new RuntimeException("Reply expected"); + if (buf.get(0) != TERMINATOR) + throw new RuntimeException("Terminated expected"); + } + + LockSlaveMirror open(String file) throws IOException { + sendCommand(OPEN_CMD, file); + return this; + } + + void close() throws IOException { + sendCommand(CLOSE_CMD); + } + + LockSlaveMirror lock() throws IOException { + sendCommand(LOCK_CMD); + return this; + } + + + LockSlaveMirror lock(long position, long size, boolean shared) + throws IOException + { + sendCommand(LOCK_CMD, position + "," + size + "," + shared); + return this; + } + + LockSlaveMirror unlock() throws IOException { + sendCommand(UNLOCK_CMD); + return this; + } + + void shutdown() throws IOException { + sc.close(); + } + } + + // Helper class to direct process output to the parent System.out + static class IOHandler implements Runnable { + private final InputStream in; + + IOHandler(InputStream in) { + this.in = in; + } + + static void handle(InputStream in) { + IOHandler handler = new IOHandler(in); + Thread thr = new Thread(handler); + thr.setDaemon(true); + thr.start(); + } + + public void run() { + try { + byte b[] = new byte[100]; + for (;;) { + int n = in.read(b); + if (n < 0) return; + for (int i=0; i<n; i++) { + System.out.print((char)b[i]); + } + } + } catch (IOException ioe) { } + } + } + + // slave process that responds to simple commands a socket connection + static void runLockSlave(int port) throws Exception { + + // establish connection to parent + SocketChannel sc = SocketChannel.open(new InetSocketAddress(port)); + ByteBuffer buf = ByteBuffer.allocateDirect(1024); + + FileChannel fc = null; + FileLock fl = null; + try { + for (;;) { + + // read command (ends with ";") + buf.clear(); + int n, last = 0; + do { + n = sc.read(buf); + if (n < 0) + return; + if (n == 0) + throw new AssertionError(); + last += n; + } while (buf.get(last-1) != TERMINATOR); + + // decode into command and optional parameter + buf.flip(); + String s = Charset.defaultCharset().decode(buf).toString(); + int sp = s.indexOf(" "); + String cmd = (sp < 0) ? s.substring(0, s.length()-1) : + s.substring(0, sp); + String param = (sp < 0) ? "" : s.substring(sp+1, s.length()-1); + + // execute + if (cmd.equals(OPEN_CMD)) { + if (fc != null) + throw new RuntimeException("File already open"); + fc = FileChannel.open(Paths.get(param),READ, WRITE); + } + if (cmd.equals(CLOSE_CMD)) { + if (fc == null) + throw new RuntimeException("No file open"); + fc.close(); + fc = null; + fl = null; + } + if (cmd.equals(LOCK_CMD)) { + if (fl != null) + throw new RuntimeException("Already holding lock"); + + if (param.length() == 0) { + fl = fc.lock(); + } else { + String[] values = param.split(","); + if (values.length != 3) + throw new RuntimeException("Lock parameter invalid"); + long position = Long.parseLong(values[0]); + long size = Long.parseLong(values[1]); + boolean shared = Boolean.parseBoolean(values[2]); + fl = fc.lock(position, size, shared); + } + } + + if (cmd.equals(UNLOCK_CMD)) { + if (fl == null) + throw new RuntimeException("Not holding lock"); + fl.release(); + fl = null; + } + + // send reply + byte[] reply = { TERMINATOR }; + n = sc.write(ByteBuffer.wrap(reply)); + } + + } finally { + sc.close(); + if (fc != null) fc.close(); + } + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousFileChannel/MyThreadFactory.java b/jdk/test/java/nio/channels/AsynchronousFileChannel/MyThreadFactory.java new file mode 100644 index 00000000000..fe6f00c25b1 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/MyThreadFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.util.concurrent.ThreadFactory; +import java.util.*; + +public class MyThreadFactory implements ThreadFactory { + + private static final Set<Thread> threads = new HashSet<Thread>(); + + static boolean created(Thread t) { + synchronized (threads) { + return threads.contains(t); + } + } + + public MyThreadFactory() { + } + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setDaemon(true); + synchronized (threads) { + threads.add(t); + } + return t; + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java new file mode 100644 index 00000000000..e0965fb6e74 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java @@ -0,0 +1,136 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousServerSocketChannel + * @run main/timeout=180 Basic + */ + +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicReference; + +public class Basic { + + public static void main(String[] args) throws Exception { + testBind(); + testAccept(); + } + + static void testBind() throws Exception { + System.out.println("-- bind --"); + + AsynchronousServerSocketChannel ch = AsynchronousServerSocketChannel.open(); + if (ch.getLocalAddress() != null) + throw new RuntimeException("Local address should be 'null'"); + ch.bind(new InetSocketAddress(0), 20); + + // check local address after binding + InetSocketAddress local = (InetSocketAddress)ch.getLocalAddress(); + if (local.getPort() == 0) + throw new RuntimeException("Unexpected port"); + if (!local.getAddress().isAnyLocalAddress()) + throw new RuntimeException("Not bound to a wildcard address"); + + // try to re-bind + try { + ch.bind(new InetSocketAddress(0)); + throw new RuntimeException("AlreadyBoundException expected"); + } catch (AlreadyBoundException x) { + } + ch.close(); + + // check ClosedChannelException + ch = AsynchronousServerSocketChannel.open(); + ch.close(); + try { + ch.bind(new InetSocketAddress(0)); + throw new RuntimeException("ClosedChannelException expected"); + } catch (ClosedChannelException x) { + } + } + + static void testAccept() throws Exception { + System.out.println("-- accept --"); + + final AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0)); + + InetAddress lh = InetAddress.getLocalHost(); + int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); + final InetSocketAddress isa = new InetSocketAddress(lh, port); + + // establish a few loopback connections + for (int i=0; i<100; i++) { + SocketChannel sc = SocketChannel.open(isa); + AsynchronousSocketChannel ch = listener.accept().get(); + sc.close(); + ch.close(); + } + + final AtomicReference<Throwable> exception = new AtomicReference<Throwable>(); + + // start accepting + listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() { + public void completed(AsynchronousSocketChannel ch, Void att) { + try { + ch.close(); + } catch (IOException ignore) { } + } + public void failed(Throwable exc, Void att) { + exception.set(exc); + } + public void cancelled(Void att) { + } + }); + + // check AcceptPendingException + try { + listener.accept(); + throw new RuntimeException("AcceptPendingException expected"); + } catch (AcceptPendingException x) { + } + + // asynchronous close + listener.close(); + while (exception.get() == null) + Thread.sleep(100); + if (!(exception.get() instanceof AsynchronousCloseException)) + throw new RuntimeException("AsynchronousCloseException expected"); + + // once closed when a further attemt should throw ClosedChannelException + try { + listener.accept().get(); + throw new RuntimeException("ExecutionException expected"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof ClosedChannelException)) + throw new RuntimeException("Cause of ClosedChannelException expected"); + } catch (InterruptedException x) { + } + + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java new file mode 100644 index 00000000000..86c76cf1dda --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java @@ -0,0 +1,76 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousServerServerSocketChannel + * @build WithSecurityManager + * @run main/othervm WithSecurityManager allow + * @run main/othervm WithSecurityManager deny + */ + +import java.nio.file.Paths; +import java.nio.channels.*; +import java.net.*; +import java.util.concurrent.*; + +public class WithSecurityManager { + public static void main(String[] args) throws Exception { + boolean allow = false; + String policy = (args[0].equals("allow")) ? "java.policy.allow" : + "java.policy.deny"; + + String testSrc = System.getProperty("test.src"); + if (testSrc == null) + testSrc = "."; + + System.setProperty("java.security.policy", + Paths.get(testSrc).resolve(policy).toString()); + System.setSecurityManager(new SecurityManager()); + + AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0)); + + InetAddress lh = InetAddress.getLocalHost(); + int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); + + // establish and accept connection + SocketChannel sc = SocketChannel.open(new InetSocketAddress(lh, port)); + Future<AsynchronousSocketChannel> result = listener.accept(); + + if (allow) { + // no security exception + result.get().close(); + } else { + try { + result.get(); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof SecurityException)) + throw new RuntimeException("SecurityException expected"); + } + } + + sc.close(); + listener.close(); + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.allow b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.allow new file mode 100644 index 00000000000..73da4b089ec --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.allow @@ -0,0 +1,3 @@ +grant { + permission java.net.SocketPermission "*:1024-", "accept,connect,resolve"; +}; diff --git a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.deny b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.deny new file mode 100644 index 00000000000..00b9cb0685d --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.deny @@ -0,0 +1,3 @@ +grant { + permission java.net.SocketPermission "*:1024-", "connect,resolve"; +}; diff --git a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java new file mode 100644 index 00000000000..8b140f17bbf --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java @@ -0,0 +1,805 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousSocketChannel + * @run main/timeout=600 Basic + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import static java.net.StandardSocketOption.*; +import java.net.*; +import java.util.Random; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.io.IOException; + +public class Basic { + static final Random rand = new Random(); + + public static void main(String[] args) throws Exception { + testBind(); + testSocketOptions(); + testConnect(); + testCloseWhenPending(); + testCancel(); + testRead1(); + testRead2(); + testRead3(); + testWrite1(); + testWrite2(); + testTimeout(); + testShutdown(); + } + + static class Server { + private final ServerSocketChannel ssc; + private final InetSocketAddress address; + + Server() throws IOException { + ssc = ServerSocketChannel.open().bind(new InetSocketAddress(0)); + + InetAddress lh = InetAddress.getLocalHost(); + int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort(); + address = new InetSocketAddress(lh, port); + } + + InetSocketAddress address() { + return address; + } + + SocketChannel accept() throws IOException { + return ssc.accept(); + } + + void close() { + try { + ssc.close(); + } catch (IOException ignore) { } + } + + } + + static void testBind() throws Exception { + System.out.println("-- bind --"); + + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + if (ch.getLocalAddress() != null) + throw new RuntimeException("Local address should be 'null'"); + ch.bind(new InetSocketAddress(0)); + + // check local address after binding + InetSocketAddress local = (InetSocketAddress)ch.getLocalAddress(); + if (local.getPort() == 0) + throw new RuntimeException("Unexpected port"); + if (!local.getAddress().isAnyLocalAddress()) + throw new RuntimeException("Not bound to a wildcard address"); + + // try to re-bind + try { + ch.bind(new InetSocketAddress(0)); + throw new RuntimeException("AlreadyBoundException expected"); + } catch (AlreadyBoundException x) { + } + ch.close(); + + // check ClosedChannelException + ch = AsynchronousSocketChannel.open(); + ch.close(); + try { + ch.bind(new InetSocketAddress(0)); + throw new RuntimeException("ClosedChannelException expected"); + } catch (ClosedChannelException x) { + } + } + + static void testSocketOptions() throws Exception { + System.out.println("-- socket options --"); + + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open() + .setOption(SO_RCVBUF, 128*1024) + .setOption(SO_SNDBUF, 128*1024) + .setOption(SO_REUSEADDR, true) + .bind(new InetSocketAddress(0)); + + // default values + if ((Boolean)ch.getOption(SO_KEEPALIVE)) + throw new RuntimeException("Default of SO_KEEPALIVE should be 'false'"); + if ((Boolean)ch.getOption(TCP_NODELAY)) + throw new RuntimeException("Default of TCP_NODELAY should be 'false'"); + + // set and check + if (!(Boolean)ch.setOption(SO_KEEPALIVE, true).getOption(SO_KEEPALIVE)) + throw new RuntimeException("SO_KEEPALIVE did not change"); + if (!(Boolean)ch.setOption(TCP_NODELAY, true).getOption(TCP_NODELAY)) + throw new RuntimeException("SO_KEEPALIVE did not change"); + + // read others (can't check as actual value is implementation dependent) + ch.getOption(SO_RCVBUF); + ch.getOption(SO_SNDBUF); + + ch.close(); + } + + static void testConnect() throws Exception { + System.out.println("-- connect --"); + + Server server = new Server(); + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + + // check local address + if (ch.getLocalAddress() == null) + throw new RuntimeException("Not bound to local address"); + + // check remote address + InetSocketAddress remote = (InetSocketAddress)ch.getRemoteAddress(); + if (remote.getPort() != server.address().getPort()) + throw new RuntimeException("Connected to unexpected port"); + if (!remote.getAddress().equals(server.address().getAddress())) + throw new RuntimeException("Connected to unexpected address"); + + // try to connect again + try { + ch.connect(server.address()).get(); + throw new RuntimeException("AlreadyConnectedException expected"); + } catch (AlreadyConnectedException x) { + } + ch.close(); + + // check that connect fails with ClosedChannelException) + ch = AsynchronousSocketChannel.open(); + ch.close(); + try { + ch.connect(server.address()).get(); + throw new RuntimeException("ExecutionException expected"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof ClosedChannelException)) + throw new RuntimeException("Cause of ClosedChannelException expected"); + } + final AtomicReference<Throwable> connectException = + new AtomicReference<Throwable>(); + ch.connect(server.address(), null, new CompletionHandler<Void,Void>() { + public void completed(Void result, Void att) { + } + public void failed(Throwable exc, Void att) { + connectException.set(exc); + } + public void cancelled(Void att) { + } + }); + while (connectException.get() == null) { + Thread.sleep(100); + } + if (!(connectException.get() instanceof ClosedChannelException)) + throw new RuntimeException("ClosedChannelException expected"); + + System.out.println("-- connect to non-existent host --"); + + // test failure + InetAddress badHost = InetAddress.getByName("1.2.3.4"); + if (!badHost.isReachable(10*1000)) { + + ch = AsynchronousSocketChannel.open(); + try { + ch.connect(new InetSocketAddress(badHost, 9876)).get(); + throw new RuntimeException("Connection should not be established"); + } catch (ExecutionException x) { + } + if (ch.isOpen()) + throw new RuntimeException("Channel should be closed"); + } + + server.close(); + } + + static void testCloseWhenPending() throws Exception { + System.out.println("-- asynchronous close when connecting --"); + + AsynchronousSocketChannel ch; + + // asynchronous close while connecting + InetAddress rh = InetAddress.getByName("1.2.3.4"); + if (!rh.isReachable(3000)) { + InetSocketAddress isa = new InetSocketAddress(rh, 1234); + + ch = AsynchronousSocketChannel.open(); + Future<Void> result = ch.connect(isa); + + // give time to initiate the connect (SYN) + Thread.sleep(50); + + // close + ch.close(); + + // check that AsynchronousCloseException is thrown + try { + result.get(); + throw new RuntimeException("Should not connect"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof AsynchronousCloseException)) + throw new RuntimeException(x); + } + } + + System.out.println("-- asynchronous close when reading --"); + + Server server = new Server(); + ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + + ByteBuffer dst = ByteBuffer.allocateDirect(100); + Future<Integer> result = ch.read(dst); + + // attempt a second read - should fail with ReadPendingException + ByteBuffer buf = ByteBuffer.allocateDirect(100); + try { + ch.read(buf); + throw new RuntimeException("ReadPendingException expected"); + } catch (ReadPendingException x) { + } + + // close channel (should cause initial read to complete) + ch.close(); + + // check that AsynchronousCloseException is thrown + try { + result.get(); + throw new RuntimeException("Should not read"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof AsynchronousCloseException)) + throw new RuntimeException(x); + } + + System.out.println("-- asynchronous close when writing --"); + + ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + + final AtomicReference<Throwable> writeException = + new AtomicReference<Throwable>(); + + // write bytes to fill socket buffer + ch.write(genBuffer(), ch, new CompletionHandler<Integer,AsynchronousSocketChannel>() { + public void completed(Integer result, AsynchronousSocketChannel ch) { + ch.write(genBuffer(), ch, this); + } + public void failed(Throwable x, AsynchronousSocketChannel ch) { + writeException.set(x); + } + public void cancelled(AsynchronousSocketChannel ch) { + } + }); + + // give time for socket buffer to fill up. + Thread.sleep(5*1000); + + // attempt a concurrent write - should fail with WritePendingException + try { + ch.write(genBuffer()); + throw new RuntimeException("WritePendingException expected"); + } catch (WritePendingException x) { + } + + // close channel - should cause initial write to complete + ch.close(); + + // wait for exception + while (writeException.get() == null) { + Thread.sleep(100); + } + if (!(writeException.get() instanceof AsynchronousCloseException)) + throw new RuntimeException("AsynchronousCloseException expected"); + + server.close(); + } + + static void testCancel() throws Exception { + System.out.println("-- cancel --"); + + Server server = new Server(); + + for (int i=0; i<2; i++) { + boolean mayInterruptIfRunning = (i == 0) ? false : true; + + // establish loopback connection + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + SocketChannel peer = server.accept(); + + // start read operation + final CountDownLatch latch = new CountDownLatch(1); + ByteBuffer buf = ByteBuffer.allocate(1); + Future<Integer> res = ch.read(buf, null, + new CompletionHandler<Integer,Void>() { + public void completed(Integer result, Void att) { + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + latch.countDown(); + } + }); + + // cancel operation + boolean cancelled = res.cancel(mayInterruptIfRunning); + + // check post-conditions + if (!res.isDone()) + throw new RuntimeException("isDone should return true"); + if (res.isCancelled() != cancelled) + throw new RuntimeException("isCancelled not consistent"); + try { + res.get(); + throw new RuntimeException("CancellationException expected"); + } catch (CancellationException x) { + } + try { + res.get(1, TimeUnit.SECONDS); + throw new RuntimeException("CancellationException expected"); + } catch (CancellationException x) { + } + + // check that completion handler executed. + latch.await(); + + ch.close(); + peer.close(); + } + + server.close(); + } + + static void testRead1() throws Exception { + System.out.println("-- read (1) --"); + + Server server = new Server(); + final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + + // read with 0 bytes remaining should complete immediately + ByteBuffer buf = ByteBuffer.allocate(1); + buf.put((byte)0); + int n = ch.read(buf).get(); + if (n != 0) + throw new RuntimeException("0 expected"); + + // write bytes and close connection + SocketChannel sc = server.accept(); + ByteBuffer src = genBuffer(); + sc.setOption(StandardSocketOption.SO_SNDBUF, src.remaining()); + while (src.hasRemaining()) + sc.write(src); + sc.close(); + + // reads should complete immediately + final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity() + 100); + final CountDownLatch latch = new CountDownLatch(1); + ch.read(dst, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer result, Void att) { + int n = result; + if (n > 0) { + ch.read(dst, null, this); + } else { + latch.countDown(); + } + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + + latch.await(); + + // check buffers + src.flip(); + dst.flip(); + if (!src.equals(dst)) { + throw new RuntimeException("Contents differ"); + } + + // close channel + ch.close(); + + // check read fails with ClosedChannelException + try { + ch.read(dst).get(); + throw new RuntimeException("ExecutionException expected"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof ClosedChannelException)) + throw new RuntimeException("Cause of ClosedChannelException expected"); + } + + server.close(); + } + + static void testRead2() throws Exception { + System.out.println("-- read (2) --"); + + Server server = new Server(); + + final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + SocketChannel sc = server.accept(); + + ByteBuffer src = genBuffer(); + + // read until the buffer is full + final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity()); + final CountDownLatch latch = new CountDownLatch(1); + ch.read(dst, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer result, Void att) { + if (dst.hasRemaining()) { + ch.read(dst, null, this); + } else { + latch.countDown(); + } + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + + // trickle the writing + do { + int rem = src.remaining(); + int size = (rem <= 100) ? rem : 50 + rand.nextInt(rem - 100); + ByteBuffer buf = ByteBuffer.allocate(size); + for (int i=0; i<size; i++) + buf.put(src.get()); + buf.flip(); + Thread.sleep(50 + rand.nextInt(1500)); + while (buf.hasRemaining()) + sc.write(buf); + } while (src.hasRemaining()); + + // wait until ascynrhonous reading has completed + latch.await(); + + // check buffers + src.flip(); + dst.flip(); + if (!src.equals(dst)) { + throw new RuntimeException("Contents differ"); + } + + sc.close(); + ch.close(); + server.close(); + } + + // exercise scattering read + static void testRead3() throws Exception { + System.out.println("-- read (3) --"); + + Server server = new Server(); + final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + SocketChannel sc = server.accept(); + + ByteBuffer[] dsts = new ByteBuffer[3]; + for (int i=0; i<dsts.length; i++) { + dsts[i] = ByteBuffer.allocateDirect(100); + } + + // scattering read that completes ascynhronously + final CountDownLatch latch = new CountDownLatch(1); + ch.read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, null, + new CompletionHandler<Long,Void>() { + public void completed(Long result, Void att) { + long n = result; + if (n <= 0) + throw new RuntimeException("No bytes read"); + latch.countDown(); + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + + // write some bytes + sc.write(genBuffer()); + + // read should now complete + latch.await(); + + // write more bytes + sc.write(genBuffer()); + + // read should complete immediately + for (int i=0; i<dsts.length; i++) { + dsts[i].rewind(); + } + long n = ch + .read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, null, null).get(); + if (n <= 0) + throw new RuntimeException("No bytes read"); + + ch.close(); + sc.close(); + server.close(); + } + + static void testWrite1() throws Exception { + System.out.println("-- write (1) --"); + + Server server = new Server(); + final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + SocketChannel sc = server.accept(); + + // write with 0 bytes remaining should complete immediately + ByteBuffer buf = ByteBuffer.allocate(1); + buf.put((byte)0); + int n = ch.write(buf).get(); + if (n != 0) + throw new RuntimeException("0 expected"); + + // write all bytes and close connection when done + final ByteBuffer src = genBuffer(); + ch.write(src, null, new CompletionHandler<Integer,Void>() { + public void completed(Integer result, Void att) { + if (src.hasRemaining()) { + ch.write(src, null, this); + } else { + try { + ch.close(); + } catch (IOException ignore) { } + } + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + + // read to EOF or buffer full + ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity() + 100); + do { + n = sc.read(dst); + } while (n > 0); + sc.close(); + + // check buffers + src.flip(); + dst.flip(); + if (!src.equals(dst)) { + throw new RuntimeException("Contents differ"); + } + + // check write fails with ClosedChannelException + try { + ch.read(dst).get(); + throw new RuntimeException("ExecutionException expected"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof ClosedChannelException)) + throw new RuntimeException("Cause of ClosedChannelException expected"); + } + + server.close(); + } + + // exercise gathering write + static void testWrite2() throws Exception { + System.out.println("-- write (2) --"); + + Server server = new Server(); + final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + SocketChannel sc = server.accept(); + + // write buffers (should complete immediately) + ByteBuffer[] srcs = genBuffers(1); + long n = ch + .write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, null, null).get(); + if (n <= 0) + throw new RuntimeException("No bytes written"); + + // set to true to signal that no more buffers should be written + final AtomicBoolean continueWriting = new AtomicBoolean(true); + + // number of bytes written + final AtomicLong bytesWritten = new AtomicLong(n); + + // write until socket buffer is full so as to create the conditions + // for when a write does not complete immediately + srcs = genBuffers(1); + ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, null, + new CompletionHandler<Long,Void>() { + public void completed(Long result, Void att) { + long n = result; + if (n <= 0) + throw new RuntimeException("No bytes written"); + bytesWritten.addAndGet(n); + if (continueWriting.get()) { + ByteBuffer[] srcs = genBuffers(8); + ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, + null, this); + } + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + + // give time for socket buffer to fill up. + Thread.sleep(5*1000); + + // signal handler to stop further writing + continueWriting.set(false); + + // read until done + ByteBuffer buf = ByteBuffer.allocateDirect(4096); + long total = 0L; + do { + n = sc.read(buf); + if (n <= 0) + throw new RuntimeException("No bytes read"); + buf.rewind(); + total += n; + } while (total < bytesWritten.get()); + + ch.close(); + sc.close(); + server.close(); + } + + static void testShutdown() throws Exception { + System.out.println("-- shutdown--"); + + Server server = new Server(); + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + SocketChannel sc = server.accept(); + + ByteBuffer buf = ByteBuffer.allocateDirect(1000); + int n; + + // check read + ch.shutdownInput(); + n = ch.read(buf).get(); + if (n != -1) + throw new RuntimeException("-1 expected"); + // check full with full buffer + buf.put(new byte[100]); + n = ch.read(buf).get(); + if (n != -1) + throw new RuntimeException("-1 expected"); + + // check write + ch.shutdownOutput(); + try { + ch.write(buf).get(); + throw new RuntimeException("ClosedChannelException expected"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof ClosedChannelException)) + throw new RuntimeException("ClosedChannelException expected"); + } + + sc.close(); + ch.close(); + server.close(); + } + + static void testTimeout() throws Exception { + Server server = new Server(); + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); + ch.connect(server.address()).get(); + + System.out.println("-- timeout when reading --"); + + // this read should timeout + ByteBuffer dst = ByteBuffer.allocate(512); + try { + ch.read(dst, 3, TimeUnit.SECONDS, null, null).get(); + throw new RuntimeException("Read did not timeout"); + } catch (ExecutionException x) { + if (!(x.getCause() instanceof InterruptedByTimeoutException)) + throw new RuntimeException("InterruptedByTimeoutException expected"); + } + + // after a timeout then further reading should throw unspecified runtime exception + boolean exceptionThrown = false; + try { + ch.read(dst); + } catch (RuntimeException x) { + exceptionThrown = true; + } + if (!exceptionThrown) + throw new RuntimeException("RuntimeException expected after timeout."); + + + System.out.println("-- timeout when writing --"); + + final AtomicReference<Throwable> writeException = new AtomicReference<Throwable>(); + + final long timeout = 5; + final TimeUnit unit = TimeUnit.SECONDS; + + // write bytes to fill socket buffer + ch.write(genBuffer(), timeout, unit, ch, + new CompletionHandler<Integer,AsynchronousSocketChannel>() + { + public void completed(Integer result, AsynchronousSocketChannel ch) { + ch.write(genBuffer(), timeout, unit, ch, this); + } + public void failed(Throwable exc, AsynchronousSocketChannel ch) { + writeException.set(exc); + } + public void cancelled(AsynchronousSocketChannel ch) { + } + }); + + // wait for exception + while (writeException.get() == null) { + Thread.sleep(100); + } + if (!(writeException.get() instanceof InterruptedByTimeoutException)) + throw new RuntimeException("InterruptedByTimeoutException expected"); + + // after a timeout then further writing should throw unspecified runtime exception + exceptionThrown = false; + try { + ch.write(genBuffer()); + } catch (RuntimeException x) { + exceptionThrown = true; + } + if (!exceptionThrown) + throw new RuntimeException("RuntimeException expected after timeout."); + + ch.close(); + } + + // returns ByteBuffer with random bytes + static ByteBuffer genBuffer() { + int size = 1024 + rand.nextInt(16000); + byte[] buf = new byte[size]; + rand.nextBytes(buf); + boolean useDirect = rand.nextBoolean(); + if (useDirect) { + ByteBuffer bb = ByteBuffer.allocateDirect(buf.length); + bb.put(buf); + bb.flip(); + return bb; + } else { + return ByteBuffer.wrap(buf); + } + } + + // return ByteBuffer[] with random bytes + static ByteBuffer[] genBuffers(int max) { + int len = 1; + if (max > 1) + len += rand.nextInt(max); + ByteBuffer[] bufs = new ByteBuffer[len]; + for (int i=0; i<len; i++) + bufs[i] = genBuffer(); + return bufs; + } +} diff --git a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Leaky.java b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Leaky.java new file mode 100644 index 00000000000..3ac18211c58 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Leaky.java @@ -0,0 +1,104 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Unit test for AsynchronousSocketChannel + * @run main/othervm -XX:+DisableExplicitGC -mx64m Leaky + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.concurrent.Future; + +/** + * Heap buffers must be substituted with direct buffers when doing I/O. This + * test creates a scenario on Windows that challenges the per-thread buffer + * cache and quickly leads to an OutOfMemoryError if temporary buffers are + * not returned to the native heap. + */ + +public class Leaky { + + static final int K = 1024; + + static class Connection { + private final AsynchronousSocketChannel client; + private final SocketChannel peer; + private final ByteBuffer dst; + private Future<Integer> readResult; + + Connection() throws Exception { + ServerSocketChannel ssc = + ServerSocketChannel.open().bind(new InetSocketAddress(0)); + InetAddress lh = InetAddress.getLocalHost(); + int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort(); + SocketAddress remote = new InetSocketAddress(lh, port); + client = AsynchronousSocketChannel.open(); + client.connect(remote).get(); + peer = ssc.accept(); + ssc.close(); + dst = ByteBuffer.allocate(K*K); + } + + void startRead() { + dst.clear(); + readResult = client.read(dst); + } + + void write() throws Exception { + peer.write(ByteBuffer.wrap("X".getBytes())); + } + + void finishRead() throws Exception { + readResult.get(); + } + } + + public static void main(String[] args) throws Exception { + + final int CONNECTION_COUNT = 10; + Connection[] connections = new Connection[CONNECTION_COUNT]; + for (int i=0; i<CONNECTION_COUNT; i++) { + connections[i] = new Connection(); + } + + for (int i=0; i<1024; i++) { + // initiate reads + for (Connection conn: connections) { + conn.startRead(); + } + + // write data so that the read can complete + for (Connection conn: connections) { + conn.write(); + } + + // complete read + for (Connection conn: connections) { + conn.finishRead(); + } + } + } +} diff --git a/jdk/test/java/nio/channels/Channels/Basic2.java b/jdk/test/java/nio/channels/Channels/Basic2.java new file mode 100644 index 00000000000..46a1b028cca --- /dev/null +++ b/jdk/test/java/nio/channels/Channels/Basic2.java @@ -0,0 +1,172 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4607272 + * @summary Test Channels methods for interoperability between streams and + * asynchronous byte channels + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Random; + +public class Basic2 { + + static final Random rand = new Random(); + + public static void main(String[] args) throws Exception { + // establish loopback connection + AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0)); + int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); + InetSocketAddress isa = + new InetSocketAddress(InetAddress.getLocalHost(), port); + AsynchronousSocketChannel ch1 = AsynchronousSocketChannel.open(); + ch1.connect(isa).get(); + AsynchronousSocketChannel ch2 = listener.accept().get(); + + // start thread to write to stream + Writer writer = new Writer(Channels.newOutputStream(ch1)); + Thread writerThread = new Thread(writer); + writerThread.start(); + + // start thread to read from stream + Reader reader = new Reader(Channels.newInputStream(ch2)); + Thread readerThread = new Thread(reader); + readerThread.start(); + + // wait for threads to complete + writerThread.join(); + readerThread.join(); + + // check that reader received what we expected + if (reader.total() != writer.total()) + throw new RuntimeException("Unexpected number of bytes read"); + if (reader.hash() != writer.hash()) + throw new RuntimeException("Hash incorrect for bytes read"); + + // channels should be closed + if (ch1.isOpen() || ch2.isOpen()) + throw new RuntimeException("Channels should be closed"); + } + + static class Reader implements Runnable { + private final InputStream in; + private volatile int total; + private volatile int hash; + + Reader(InputStream in) { + this.in = in; + } + + public void run() { + try { + int n; + do { + // random offset/len + byte[] buf = new byte[128 + rand.nextInt(128)]; + int len, off; + if (rand.nextBoolean()) { + len = buf.length; + off = 0; + n = in.read(buf); + } else { + len = 1 + rand.nextInt(64); + off = rand.nextInt(64); + n = in.read(buf, off, len); + } + if (n > len) + throw new RuntimeException("Too many bytes read"); + if (n > 0) { + total += n; + for (int i=0; i<n; i++) { + int value = buf[off + i]; + hash = hash ^ value; + } + } + } while (n > 0); + in.close(); + + } catch (IOException x) { + x.printStackTrace(); + } + } + + int total() { return total; } + int hash() { return hash; } + } + + static class Writer implements Runnable { + private final OutputStream out; + private final int total; + private volatile int hash; + + Writer(OutputStream out) { + this.out = out; + this.total = 50*1000 + rand.nextInt(50*1000); + } + + public void run() { + hash = 0; + int rem = total; + try { + do { + byte[] buf = new byte[1 + rand.nextInt(rem)]; + int off, len; + + // write random bytes + if (rand.nextBoolean()) { + off = 0; + len = buf.length; + } else { + off = rand.nextInt(buf.length); + int r = buf.length - off; + len = (r <= 1) ? 1 : (1 + rand.nextInt(r)); + } + for (int i=0; i<len; i++) { + byte value = (byte)rand.nextInt(256); + buf[off + i] = value; + hash = hash ^ value; + } + if ((off == 0) && (len == buf.length)) { + out.write(buf); + } else { + out.write(buf, off, len); + } + rem -= len; + } while (rem > 0); + + // close stream when done + out.close(); + + } catch (IOException x) { + x.printStackTrace(); + } + } + + int total() { return total; } + int hash() { return hash; } + } +} diff --git a/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java b/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java index 03b5daa68f1..6928bcded3e 100644 --- a/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java +++ b/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,11 +64,11 @@ public class BasicMulticastTests { // check key if (!key.isValid()) throw new RuntimeException("key is not valid"); - if (!key.getGroup().equals(group)) + if (!key.group().equals(group)) throw new RuntimeException("group is incorrect"); - if (!key.getNetworkInterface().equals(nif)) + if (!key.networkInterface().equals(nif)) throw new RuntimeException("network interface is incorrect"); - if (key.getSourceAddress() != null) + if (key.sourceAddress() != null) throw new RuntimeException("key is source specific"); // drop membership @@ -86,11 +86,11 @@ public class BasicMulticastTests { } if (!key.isValid()) throw new RuntimeException("key is not valid"); - if (!key.getGroup().equals(group)) + if (!key.group().equals(group)) throw new RuntimeException("group is incorrect"); - if (!key.getNetworkInterface().equals(nif)) + if (!key.networkInterface().equals(nif)) throw new RuntimeException("network interface is incorrect"); - if (!key.getSourceAddress().equals(source)) + if (!key.sourceAddress().equals(source)) throw new RuntimeException("key's source address incorrect"); // drop membership diff --git a/jdk/test/java/nio/channels/DatagramChannel/NotBound.java b/jdk/test/java/nio/channels/DatagramChannel/NotBound.java index 9a58fe64d18..d9fbd7b5efa 100644 --- a/jdk/test/java/nio/channels/DatagramChannel/NotBound.java +++ b/jdk/test/java/nio/channels/DatagramChannel/NotBound.java @@ -22,27 +22,110 @@ */ /* @test - * @bug 4512723 - * @summary Unit test for datagram-socket-channel adaptors + * @bug 4512723 6621689 + * @summary Test that connect/send/receive with unbound DatagramChannel causes + * the channel's socket to be bound to a local address */ import java.net.*; -import java.nio.*; -import java.nio.channels.*; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.io.IOException; -class NotBound { - public static void main(String[] args) throws Exception { - test1(false); - test1(true); +public class NotBound { + + static void checkBound(DatagramChannel dc) throws IOException { + if (dc.getLocalAddress() == null) + throw new RuntimeException("Not bound??"); } - static void test1(boolean blocking) throws Exception { - ByteBuffer bb = ByteBuffer.allocateDirect(256); - DatagramChannel dc1 = DatagramChannel.open(); - dc1.configureBlocking(false); - SocketAddress isa = dc1.receive(bb); - if (isa != null) - throw new Exception("Unbound dc returned non-null"); - dc1.close(); + // starts a thread to send a datagram to the given channel once the channel + // is bound to a local address + static void wakeupWhenBound(final DatagramChannel dc) { + Runnable wakeupTask = new Runnable() { + public void run() { + try { + // poll for local address + InetSocketAddress local; + do { + Thread.sleep(50); + local = (InetSocketAddress)dc.getLocalAddress(); + } while (local == null); + + // send message to channel to wakeup receiver + DatagramChannel sender = DatagramChannel.open(); + try { + ByteBuffer bb = ByteBuffer.wrap("hello".getBytes()); + InetAddress lh = InetAddress.getLocalHost(); + SocketAddress target = + new InetSocketAddress(lh, local.getPort()); + sender.send(bb, target); + } finally { + sender.close(); + } + + } catch (Exception x) { + x.printStackTrace(); + } + }}; + new Thread(wakeupTask).start(); + } + + public static void main(String[] args) throws IOException { + DatagramChannel dc; + + // connect + dc = DatagramChannel.open(); + try { + DatagramChannel peer = DatagramChannel.open() + .bind(new InetSocketAddress(0)); + int peerPort = ((InetSocketAddress)(peer.getLocalAddress())).getPort(); + try { + dc.connect(new InetSocketAddress(InetAddress.getLocalHost(), peerPort)); + checkBound(dc); + } finally { + peer.close(); + } + } finally { + dc.close(); + } + + // send + dc = DatagramChannel.open(); + try { + ByteBuffer bb = ByteBuffer.wrap("ignore this".getBytes()); + SocketAddress target = + new InetSocketAddress(InetAddress.getLocalHost(), 5000); + dc.send(bb, target); + checkBound(dc); + } finally { + dc.close(); + } + + // receive (blocking) + dc = DatagramChannel.open(); + try { + ByteBuffer bb = ByteBuffer.allocateDirect(128); + wakeupWhenBound(dc); + SocketAddress sender = dc.receive(bb); + if (sender == null) + throw new RuntimeException("Sender should not be null"); + checkBound(dc); + } finally { + dc.close(); + } + + // receive (non-blocking) + dc = DatagramChannel.open(); + try { + dc.configureBlocking(false); + ByteBuffer bb = ByteBuffer.allocateDirect(128); + SocketAddress sender = dc.receive(bb); + if (sender != null) + throw new RuntimeException("Sender should be null"); + checkBound(dc); + } finally { + dc.close(); + } } } diff --git a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java index e4e85b11fb4..3df7bbbda45 100644 --- a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ public class SocketOptionTests { DatagramChannel dc = DatagramChannel.open(); // check supported options - Set<SocketOption<?>> options = dc.options(); + Set<SocketOption<?>> options = dc.supportedOptions(); List<? extends SocketOption<?>> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP); diff --git a/jdk/test/java/nio/channels/Selector/HelperSlowToDie.java b/jdk/test/java/nio/channels/Selector/HelperSlowToDie.java new file mode 100644 index 00000000000..d3cb7e64efc --- /dev/null +++ b/jdk/test/java/nio/channels/Selector/HelperSlowToDie.java @@ -0,0 +1,75 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6823609 + * @summary Selector.select can hangs on Windows for cases where a helper thread + * becomes redudant but a new helper is immediately needed. + */ + +import java.nio.channels.*; +import java.io.IOException; + +public class HelperSlowToDie { + private static final int CHANNELS_PER_THREAD = 1023; + private static volatile boolean done; + + public static void main(String[] args) throws IOException { + Selector sel = Selector.open(); + + // register channels + SocketChannel[] channels = new SocketChannel[CHANNELS_PER_THREAD]; + for (int i=0; i<CHANNELS_PER_THREAD; i++) { + SocketChannel sc = SocketChannel.open(); + sc.configureBlocking(false); + sc.register(sel, SelectionKey.OP_CONNECT); + channels[i] = sc; + } + sel.selectNow(); + + // Start threads to swamp all cores but one. This improves the chances + // of duplicating the bug. + Runnable busy = new Runnable() { + public void run() { + while (!done) ; // no nothing + } + }; + int ncores = Runtime.getRuntime().availableProcessors(); + for (int i=0; i<ncores-1; i++) + new Thread(busy).start(); + + // Loop changing the number of channels from 1023 to 1024 and back. + for (int i=0; i<1000; i++) { + SocketChannel sc = SocketChannel.open(); + sc.configureBlocking(false); + sc.register(sel, SelectionKey.OP_CONNECT); + sel.selectNow(); // cause helper to spin up + sc.close(); + sel.selectNow(); // cause helper to retire + } + + // terminate busy threads + done = true; + } +} diff --git a/jdk/test/java/nio/channels/Selector/LotsOfUpdates.java b/jdk/test/java/nio/channels/Selector/LotsOfUpdates.java new file mode 100644 index 00000000000..71018fa8d32 --- /dev/null +++ b/jdk/test/java/nio/channels/Selector/LotsOfUpdates.java @@ -0,0 +1,38 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.channels.*; +import java.io.IOException; + +public class LotsOfUpdates { + public static void main(String[] args) throws IOException { + Selector sel = Selector.open(); + SocketChannel sc = SocketChannel.open(); + sc.configureBlocking(false); + SelectionKey key = sc.register(sel, 0); + for (int i=0; i<50000; i++) { + key.interestOps(0); + } + sel.selectNow(); + } +} diff --git a/jdk/test/java/nio/channels/Selector/RegAfterPreClose.java b/jdk/test/java/nio/channels/Selector/RegAfterPreClose.java new file mode 100644 index 00000000000..c5f6be1d60c --- /dev/null +++ b/jdk/test/java/nio/channels/Selector/RegAfterPreClose.java @@ -0,0 +1,127 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6693490 + * @summary Pre-close file descriptor may inadvertently get registered with + * epoll during close + */ + +import java.net.*; +import java.nio.channels.*; +import java.util.concurrent.*; +import java.util.*; +import java.io.IOException; + +public class RegAfterPreClose { + + static volatile boolean done; + + /** + * A task that continuously connects to a given address and immediately + * closes the connection. + */ + static class Connector implements Runnable { + private final SocketAddress sa; + Connector(int port) throws IOException { + InetAddress lh = InetAddress.getLocalHost(); + this.sa = new InetSocketAddress(lh, port); + } + public void run() { + while (!done) { + try { + SocketChannel.open(sa).close(); + } catch (IOException x) { + // back-off as probably resource related + try { + Thread.sleep(10); + } catch (InterruptedException ignore) { } + } + } + } + } + + /** + * A task that closes a channel. + */ + static class Closer implements Runnable { + private final Channel channel; + Closer(Channel sc) { + this.channel = sc; + } + public void run() { + try { + channel.close(); + } catch (IOException ignore) { } + } + } + + public static void main(String[] args) throws Exception { + // create listener + InetSocketAddress isa = new InetSocketAddress(0); + ServerSocketChannel ssc = ServerSocketChannel.open(); + ssc.socket().bind(isa); + + // register with Selector + final Selector sel = Selector.open(); + ssc.configureBlocking(false); + SelectionKey key = ssc.register(sel, SelectionKey.OP_ACCEPT); + + ThreadFactory factory = new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setDaemon(true); + return t; + } + }; + + // schedule test to run for 1 minute + Executors.newScheduledThreadPool(1, factory).schedule(new Runnable() { + public void run() { + done = true; + sel.wakeup(); + }}, 1, TimeUnit.MINUTES); + + // create Executor that handles tasks that closes channels + // "asynchronously" - this creates the conditions to provoke the bug. + Executor executor = Executors.newFixedThreadPool(2, factory); + + // submit task that connects to listener + executor.execute(new Connector(ssc.socket().getLocalPort())); + + // loop accepting connections until done (or an IOException is thrown) + while (!done) { + sel.select(); + if (key.isAcceptable()) { + SocketChannel sc = ssc.accept(); + if (sc != null) { + sc.configureBlocking(false); + sc.register(sel, SelectionKey.OP_READ); + executor.execute(new Closer(sc)); + } + } + sel.selectedKeys().clear(); + } + } +} diff --git a/jdk/test/java/nio/channels/Selector/lots_of_updates.sh b/jdk/test/java/nio/channels/Selector/lots_of_updates.sh new file mode 100644 index 00000000000..5054f18cc32 --- /dev/null +++ b/jdk/test/java/nio/channels/Selector/lots_of_updates.sh @@ -0,0 +1,49 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 6824477 +# @summary Selector.select can fail with IOException "Invalid argument" on +# Solaris if maximum number of file descriptors is less than 10000 +# @build LotsOfUpdates +# @run shell lots_of_updates.sh + +OS=`uname -s` +case "$OS" in + Windows_* ) + echo "ulimit not on Windows" + exit 0 + ;; + * ) + CLASSPATH=${TESTCLASSES}:${TESTSRC} + ;; +esac +export CLASSPATH + +# hard limit needs to be less than 10000 for this bug +NOFILES=`ulimit -n -H` +if [ "$NOFILES" = "unlimited" ] || [ $NOFILES -ge 10000 ]; then + ulimit -n 2048 +fi + +${TESTJAVA}/bin/java LotsOfUpdates diff --git a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java index 6c4a443ed0a..cba99e0f285 100644 --- a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ public class SocketOptionTests { ServerSocketChannel ssc = ServerSocketChannel.open(); // check supported options - Set<SocketOption<?>> options = ssc.options(); + Set<SocketOption<?>> options = ssc.supportedOptions(); if (!options.contains(SO_REUSEADDR)) throw new RuntimeException("SO_REUSEADDR should be supported"); if (!options.contains(SO_RCVBUF)) diff --git a/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java index b6fadced8e2..abcb97476ef 100644 --- a/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ public class SocketOptionTests { SocketChannel sc = SocketChannel.open(); // check supported options - Set<SocketOption<?>> options = sc.options(); + Set<SocketOption<?>> options = sc.supportedOptions(); List<? extends SocketOption> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, TCP_NODELAY); for (SocketOption opt: expected) { diff --git a/jdk/test/java/nio/channels/etc/NetworkChannelTests.java b/jdk/test/java/nio/channels/etc/NetworkChannelTests.java index 5f03453ca11..2a29bcebbd6 100644 --- a/jdk/test/java/nio/channels/etc/NetworkChannelTests.java +++ b/jdk/test/java/nio/channels/etc/NetworkChannelTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,13 +103,14 @@ public class NetworkChannelTests { // closed ch.close(); - if (ch.getLocalAddress() != null) { - throw new RuntimeException("Local address return when closed"); - } + try { + ch.getLocalAddress(); + throw new RuntimeException("ClosedChannelException expected"); + } catch (ClosedChannelException e) { } } /** - * Exercise getConnectedAddress method (SocketChannel only) + * Exercise getRemoteAddress method (SocketChannel only) */ static void connectedAddressTests() throws IOException { ServerSocketChannel ssc = ServerSocketChannel.open() @@ -121,19 +122,21 @@ public class NetworkChannelTests { SocketChannel sc = SocketChannel.open(); // not connected - if (sc.getConnectedAddress() != null) - throw new RuntimeException("getConnectedAddress returned address when not connected"); + if (sc.getRemoteAddress() != null) + throw new RuntimeException("getRemoteAddress returned address when not connected"); // connected sc.connect(server); - SocketAddress remote = sc.getConnectedAddress(); + SocketAddress remote = sc.getRemoteAddress(); if (!remote.equals(server)) - throw new RuntimeException("getConnectedAddress returned incorrect address"); + throw new RuntimeException("getRemoteAddress returned incorrect address"); // closed sc.close(); - if (sc.getConnectedAddress() != null) - throw new RuntimeException("getConnectedAddress returned address when closed"); + try { + sc.getRemoteAddress(); + throw new RuntimeException("ClosedChannelException expected"); + } catch (ClosedChannelException e) { } ssc.close(); } diff --git a/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/CheckProvider.java b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/CheckProvider.java new file mode 100644 index 00000000000..4f6d8483807 --- /dev/null +++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/CheckProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.channels.spi.AsynchronousChannelProvider; + +public class CheckProvider { + public static void main(String[] args) { + Class<?> c = AsynchronousChannelProvider.provider().getClass(); + + String expected = args[0]; + String actual = c.getName(); + + if (!actual.equals(expected)) + throw new RuntimeException("Provider is of type '" + actual + + "', expected '" + expected + "'"); + + } +} diff --git a/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/META-INF/services/java.nio.channels.spi.AsynchronousChannelProvider b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/META-INF/services/java.nio.channels.spi.AsynchronousChannelProvider new file mode 100644 index 00000000000..6b3e87eb404 --- /dev/null +++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/META-INF/services/java.nio.channels.spi.AsynchronousChannelProvider @@ -0,0 +1 @@ +Provider1 diff --git a/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java new file mode 100644 index 00000000000..fc6036a1ea9 --- /dev/null +++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java @@ -0,0 +1,69 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.nio.channels.*; +import java.net.ProtocolFamily; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.io.IOException; + +public class Provider1 extends AsynchronousChannelProvider { + public Provider1() { + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factorry) + throws IOException + { + throw new RuntimeException(); + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) + throws IOException + { + throw new RuntimeException(); + } + + @Override + public AsynchronousSocketChannel openAsynchronousSocketChannel + (AsynchronousChannelGroup group) throws IOException + { + throw new RuntimeException(); + } + + @Override + public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel + (AsynchronousChannelGroup group) throws IOException + { + throw new RuntimeException(); + } + + @Override + public AsynchronousDatagramChannel openAsynchronousDatagramChannel + (ProtocolFamily family, AsynchronousChannelGroup group) throws IOException + { + throw new RuntimeException(); + } +} diff --git a/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java new file mode 100644 index 00000000000..a42c12ff9de --- /dev/null +++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java @@ -0,0 +1,69 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.nio.channels.*; +import java.net.ProtocolFamily; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.io.IOException; + +public class Provider2 extends AsynchronousChannelProvider { + public Provider2() { + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup + (int nThreads, ThreadFactory threadFactory) throws IOException + { + throw new RuntimeException(); + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup + (ExecutorService executor, int initialSize) throws IOException + { + throw new RuntimeException(); + } + + @Override + public AsynchronousSocketChannel openAsynchronousSocketChannel + (AsynchronousChannelGroup group) throws IOException + { + throw new RuntimeException(); + } + + @Override + public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel + (AsynchronousChannelGroup group) throws IOException + { + throw new RuntimeException(); + } + + @Override + public AsynchronousDatagramChannel openAsynchronousDatagramChannel + (ProtocolFamily family, AsynchronousChannelGroup group) throws IOException + { + throw new RuntimeException(); + } +} diff --git a/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/custom_provider.sh b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/custom_provider.sh new file mode 100644 index 00000000000..13fb2a2fae0 --- /dev/null +++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/custom_provider.sh @@ -0,0 +1,71 @@ +# +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @summary Unit test for java.nio.channels.spi.AsynchronousChannelProvider +# @build Provider1 Provider2 CheckProvider +# @run shell custom_provider.sh + +# if TESTJAVA isn't set then we assume an interactive run. + +if [ -z "$TESTJAVA" ]; then + TESTSRC=. + TESTCLASSES=. + JAVA=java +else + JAVA="${TESTJAVA}/bin/java" +fi + +OS=`uname -s` +case "$OS" in + Windows_* ) + CLASSPATH="${TESTCLASSES};${TESTSRC}" + ;; + * ) + CLASSPATH=${TESTCLASSES}:${TESTSRC} + ;; +esac +export CLASSPATH + +failures=0 + +go() { + echo '' + $JAVA $1 $2 $3 2>&1 + if [ $? != 0 ]; then failures=`expr $failures + 1`; fi +} + +# Run the tests + +go CheckProvider Provider1 +go -Djava.nio.channels.spi.AsynchronousChannelProvider=Provider2 CheckProvider \ + Provider2 + +# +# Results +# +echo '' +if [ $failures -gt 0 ]; + then echo "$failures test(s) failed"; + else echo "All test(s) passed"; fi +exit $failures diff --git a/jdk/test/java/nio/file/DirectoryStream/Basic.java b/jdk/test/java/nio/file/DirectoryStream/Basic.java new file mode 100644 index 00000000000..b92447d70f6 --- /dev/null +++ b/jdk/test/java/nio/file/DirectoryStream/Basic.java @@ -0,0 +1,168 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.DirectoryStream + * @library .. + */ + +import java.nio.file.*; +import java.util.*; +import java.io.IOException; + +public class Basic { + static boolean found; + + static void doTest(final Path dir) throws IOException { + DirectoryStream<Path> stream; + + // test that directory is empty + Files.withDirectory(dir, new FileAction<FileRef>() { + public void invoke(FileRef entry) { + throw new RuntimeException("directory not empty"); + } + }); + + // create file in directory + final Path foo = Paths.get("foo"); + dir.resolve(foo).createFile(); + + // iterate over directory and check there is one entry + found = false; + Files.withDirectory(dir, new FileAction<Path>() { + public void invoke(Path entry) { + if (entry.getName().equals(foo)) { + if (found) + throw new RuntimeException("entry already found"); + found = true; + } else { + throw new RuntimeException("entry " + entry.getName() + + " not expected"); + } + } + }); + if (!found) + throw new RuntimeException("entry not found"); + + // check filtering: f* should match foo + DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() { + private PathMatcher matcher = + dir.getFileSystem().getPathMatcher("glob:f*"); + public boolean accept(Path file) { + return matcher.matches(file); + } + }; + Files.withDirectory(dir, filter, new FileAction<Path>() { + public void invoke(Path entry) { + if (!entry.getName().equals(foo)) + throw new RuntimeException("entry not expected"); + } + }); + + // check filtering: z* should not match any files + filter = new DirectoryStream.Filter<Path>() { + private PathMatcher matcher = + dir.getFileSystem().getPathMatcher("glob:z*"); + public boolean accept(Path file) { + return matcher.matches(file); + } + }; + Files.withDirectory(dir, filter, new FileAction<FileRef>() { + public void invoke(FileRef entry) { + throw new RuntimeException("no matching entries expected"); + } + }); + + // check that exception or error thrown by filter is not thrown + // by newDirectoryStream or iterator method. + stream = dir.newDirectoryStream(new DirectoryStream.Filter<Path>() { + public boolean accept(Path file) { + throw new RuntimeException("Should not be visible"); + } + }); + try { + stream.iterator(); + } finally { + stream.close(); + } + + // test NotDirectoryException + try { + dir.resolve(foo).newDirectoryStream(); + throw new RuntimeException("NotDirectoryException not thrown"); + } catch (NotDirectoryException x) { + } + + // test iterator remove method + stream = dir.newDirectoryStream(); + Iterator<Path> i = stream.iterator(); + while (i.hasNext()) { + Path entry = i.next(); + if (!entry.getName().equals(foo)) + throw new RuntimeException("entry not expected"); + i.remove(); + } + stream.close(); + + // test IllegalStateException + stream = dir.newDirectoryStream(); + i = stream.iterator(); + try { + stream.iterator(); + throw new RuntimeException("IllegalStateException not thrown as expected"); + } catch (IllegalStateException x) { + } + stream.close(); + try { + stream.iterator(); + throw new RuntimeException("IllegalStateException not thrown as expected"); + } catch (IllegalStateException x) { + } + try { + i.hasNext(); + throw new RuntimeException("ConcurrentModificationException not thrown as expected"); + } catch (ConcurrentModificationException x) { + Throwable t = x.getCause(); + if (!(t instanceof IllegalStateException)) + throw new RuntimeException("Cause is not IllegalStateException as expected"); + } + try { + i.next(); + throw new RuntimeException("IllegalStateException not thrown as expected"); + } catch (ConcurrentModificationException x) { + Throwable t = x.getCause(); + if (!(t instanceof IllegalStateException)) + throw new RuntimeException("Cause is not IllegalStateException as expected"); + } + } + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + doTest(dir); + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/DirectoryStream/DriveLetter.java b/jdk/test/java/nio/file/DirectoryStream/DriveLetter.java new file mode 100644 index 00000000000..92159f5df5f --- /dev/null +++ b/jdk/test/java/nio/file/DirectoryStream/DriveLetter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6808647 + * @summary Checks that a DirectoryStream's iterator returns the expected + * path when opening a directory by specifying only the drive letter. + * @library .. + */ + +import java.nio.file.*; +import java.io.File; +import java.io.IOException; + +public class DriveLetter { + + public static void main(String[] args) throws IOException { + String os = System.getProperty("os.name"); + if (!os.startsWith("Windows")) { + System.out.println("This is Windows specific test"); + return; + } + String here = System.getProperty("user.dir"); + if (here.length() < 2 || here.charAt(1) != ':') + throw new RuntimeException("Unable to determine drive letter"); + + // create temporary file in current directory + File tempFile = File.createTempFile("foo", "tmp", new File(here)); + try { + // we should expect C:foo.tmp to be returned by iterator + String drive = here.substring(0, 2); + Path expected = Paths.get(drive).resolve(tempFile.getName()); + + boolean found = false; + DirectoryStream<Path> stream = Paths.get(drive).newDirectoryStream(); + try { + for (Path file : stream) { + if (file.equals(expected)) { + found = true; + break; + } + } + } finally { + stream.close(); + } + if (!found) + throw new RuntimeException("Temporary file not found???"); + + } finally { + tempFile.delete(); + } + } +} diff --git a/jdk/test/java/nio/file/DirectoryStream/Filters.java b/jdk/test/java/nio/file/DirectoryStream/Filters.java new file mode 100644 index 00000000000..ea539c95df3 --- /dev/null +++ b/jdk/test/java/nio/file/DirectoryStream/Filters.java @@ -0,0 +1,241 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.DirectoryStreamFilters + * @library .. + */ + +import java.nio.file.*; +import static java.nio.file.DirectoryStreamFilters.*; +import java.nio.file.attribute.Attributes; +import java.io.*; +import java.util.*; + +public class Filters { + static final Random rand = new Random(); + + // returns a filter that only accepts files that are larger than a given size + static DirectoryStream.Filter<FileRef> newMinimumSizeFilter(final long min) { + return new DirectoryStream.Filter<FileRef>() { + public boolean accept(FileRef file) { + try { + long size = Attributes.readBasicFileAttributes(file).size(); + return size >= min; + } catch (IOException e) { + throw new IOError(e); + } + } + }; + } + + // returns a filter that only accepts files that are matched by a given glob + static DirectoryStream.Filter<Path> newGlobFilter(final String glob) { + return new DirectoryStream.Filter<Path>() { + PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:"+ glob); + public boolean accept(Path file) { + return matcher.matches(file.getName()); + } + }; + } + + static final int BIG_FILE_THRESHOLD = 8192; + + static int totalCount; + static int htmlCount; + static int bigAndHtmlCount; + static int bigOrHtmlCount; + + // generates random files in the test directory and initializes the counts + static void setup(Path dir) throws IOException { + // create 10-26 files. + totalCount = 10 + rand.nextInt(17); + char firstChar = 'A'; + for (int i=0; i<totalCount; i++) { + boolean isHtml = rand.nextBoolean(); + boolean isBig = rand.nextBoolean(); + if (isHtml) { + htmlCount++; + if (isBig) bigAndHtmlCount++; + } + if (isHtml || isBig) + bigOrHtmlCount++; + String name; + if (isHtml) { + name = firstChar + ".html"; + } else { + name = firstChar + ".tmp"; + } + firstChar++; + int size = rand.nextInt(BIG_FILE_THRESHOLD); + if (isBig) + size += BIG_FILE_THRESHOLD; + Path file = dir.resolve(name); + OutputStream out = file.newOutputStream(); + try { + if (size > 0) + out.write(new byte[size]); + } finally { + out.close(); + } + System.out.format("Created %s, size %d byte(s)\n", name, size); + } + } + + static boolean isHtml(Path file) { + return file.toString().endsWith(".html"); + } + + static boolean isBig(Path file) throws IOException { + long size = Attributes.readBasicFileAttributes(file).size(); + return size >= BIG_FILE_THRESHOLD; + } + + static void checkCount(int expected, int actual) { + if (actual != expected) + throw new RuntimeException("'" + expected + + "' entries expected, actual: " + actual); + } + + static void doTests(Path dir) throws IOException { + final List<DirectoryStream.Filter<Path>> emptyList = Collections.emptyList(); + + // list containing two filters + List<DirectoryStream.Filter<? super Path>> filters = + new ArrayList<DirectoryStream.Filter<? super Path>>(); + filters.add(newMinimumSizeFilter(BIG_FILE_THRESHOLD)); + filters.add(newGlobFilter("*.html")); + + int accepted; + DirectoryStream<Path> stream; + + System.out.println("Test: newContentTypeFilter"); + accepted = 0; + stream = dir.newDirectoryStream(newContentTypeFilter("text/html")); + try { + for (Path entry: stream) { + if (!isHtml(entry)) + throw new RuntimeException("html file expected"); + accepted++; + } + } finally { + stream.close(); + } + checkCount(htmlCount, accepted); + + System.out.println("Test: allOf with list of filters"); + accepted = 0; + stream = dir.newDirectoryStream(allOf(filters)); + try { + for (Path entry: stream) { + if (!isHtml(entry)) + throw new RuntimeException("html file expected"); + if (!isBig(entry)) + throw new RuntimeException("big file expected"); + accepted++; + } + } finally { + stream.close(); + } + checkCount(bigAndHtmlCount, accepted); + + System.out.println("Test: allOf with empty list"); + accepted = 0; + stream = dir.newDirectoryStream(allOf(emptyList)); + try { + for (Path entry: stream) { + accepted++; + } + } finally { + stream.close(); + } + checkCount(totalCount, accepted); + + System.out.println("Test: anyOf with list of filters"); + accepted = 0; + stream = dir.newDirectoryStream(anyOf(filters)); + try { + for (Path entry: stream) { + if (!isHtml(entry) && !isBig(entry)) + throw new RuntimeException("html or big file expected"); + accepted++; + } + } finally { + stream.close(); + } + checkCount(bigOrHtmlCount, accepted); + + System.out.println("Test: anyOf with empty list"); + accepted = 0; + stream = dir.newDirectoryStream(anyOf(emptyList)); + try { + for (Path entry: stream) { + accepted++; + } + } finally { + stream.close(); + } + checkCount(0, accepted); + + System.out.println("Test: complementOf"); + accepted = 0; + stream = dir.newDirectoryStream(complementOf(newGlobFilter("*.html"))); + try { + for (Path entry: stream) { + accepted++; + } + } finally { + stream.close(); + } + checkCount(totalCount-htmlCount, accepted); + + System.out.println("Test: nulls"); + try { + newContentTypeFilter(null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException npe) { } + try { + allOf(null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException npe) { } + try { + anyOf(null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException npe) { } + try { + complementOf(null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException npe) { } + } + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + setup(dir); + doTests(dir); + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/DirectoryStream/SecureDS.java b/jdk/test/java/nio/file/DirectoryStream/SecureDS.java new file mode 100644 index 00000000000..98367d8958c --- /dev/null +++ b/jdk/test/java/nio/file/DirectoryStream/SecureDS.java @@ -0,0 +1,370 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.SecureDirectoryStream + * @library .. + */ + +import java.nio.file.*; +import static java.nio.file.StandardOpenOption.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; +import java.nio.channels.*; +import java.io.IOException; +import java.util.*; + +public class SecureDS { + static boolean supportsLinks; + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + DirectoryStream stream = dir.newDirectoryStream(); + stream.close(); + if (!(stream instanceof SecureDirectoryStream)) { + System.out.println("SecureDirectoryStream not supported."); + return; + } + + supportsLinks = TestUtil.supportsLinks(dir); + + // run tests + doBasicTests(dir); + doMoveTests(dir); + miscTests(dir); + + } finally { + TestUtil.removeAll(dir); + } + } + + // Exercise each of SecureDirectoryStream's method (except move) + static void doBasicTests(Path dir) throws IOException { + Path dir1 = dir.resolve("dir1").createDirectory(); + Path dir2 = dir.resolve("dir2"); + + // create a file, directory, and two sym links in the directory + Path fileEntry = Paths.get("myfile"); + dir1.resolve(fileEntry).createFile(); + Path dirEntry = Paths.get("mydir"); + dir1.resolve(dirEntry).createDirectory(); + // myfilelink -> myfile + Path link1Entry = Paths.get("myfilelink"); + if (supportsLinks) + dir1.resolve(link1Entry).createSymbolicLink(fileEntry); + // mydirlink -> mydir + Path link2Entry = Paths.get("mydirlink"); + if (supportsLinks) + dir1.resolve(link2Entry).createSymbolicLink(dirEntry); + + // open directory and then move it so that it is no longer accessible + // via its original path. + SecureDirectoryStream stream = + (SecureDirectoryStream)dir1.newDirectoryStream(); + dir1.moveTo(dir2); + + // Test: iterate over all entries + int count = 0; + for (Path entry: stream) { count++; } + assertTrue(count == (supportsLinks ? 4 : 2)); + + // Test: getFileAttributeView to access directory's attributes + assertTrue(stream + .getFileAttributeView(BasicFileAttributeView.class) + .readAttributes() + .isDirectory()); + + // Test: dynamic access to directory's attributes + BasicFileAttributeView view = stream. + getFileAttributeView(BasicFileAttributeView.class); + Map<String,?> attrs = view.readAttributes("*"); + assertTrue((Boolean)attrs.get("isDirectory")); + attrs = view.readAttributes("isRegularFile", "size"); + assertTrue(!(Boolean)attrs.get("isRegularFile")); + assertTrue((Long)attrs.get("size") >= 0); + int linkCount = (Integer)view.getAttribute("linkCount"); + assertTrue(linkCount > 0); + view.setAttribute("lastModifiedTime", 0L); + + // Test: getFileAttributeView to access attributes of entries + assertTrue(stream + .getFileAttributeView(fileEntry, BasicFileAttributeView.class) + .readAttributes() + .isRegularFile()); + assertTrue(stream + .getFileAttributeView(fileEntry, BasicFileAttributeView.class, NOFOLLOW_LINKS) + .readAttributes() + .isRegularFile()); + assertTrue(stream + .getFileAttributeView(dirEntry, BasicFileAttributeView.class) + .readAttributes() + .isDirectory()); + assertTrue(stream + .getFileAttributeView(dirEntry, BasicFileAttributeView.class, NOFOLLOW_LINKS) + .readAttributes() + .isDirectory()); + if (supportsLinks) { + assertTrue(stream + .getFileAttributeView(link1Entry, BasicFileAttributeView.class) + .readAttributes() + .isRegularFile()); + assertTrue(stream + .getFileAttributeView(link1Entry, BasicFileAttributeView.class, NOFOLLOW_LINKS) + .readAttributes() + .isSymbolicLink()); + assertTrue(stream + .getFileAttributeView(link2Entry, BasicFileAttributeView.class) + .readAttributes() + .isDirectory()); + assertTrue(stream + .getFileAttributeView(link2Entry, BasicFileAttributeView.class, NOFOLLOW_LINKS) + .readAttributes() + .isSymbolicLink()); + } + + // Test: dynamic access to entry attributes + view = stream + .getFileAttributeView(fileEntry, PosixFileAttributeView.class, NOFOLLOW_LINKS); + if (view != null) { + attrs = view.readAttributes("owner", "size"); + UserPrincipal owner = (UserPrincipal)attrs.get("owner"); + assertTrue(owner != null); + assertTrue((Long)attrs.get("size") >= 0L); + view.setAttribute("lastAccessTime", 0L); + } + + // Test: newByteChannel + Set<StandardOpenOption> opts = Collections.emptySet(); + stream.newByteChannel(fileEntry, opts).close(); + if (supportsLinks) { + stream.newByteChannel(link1Entry, opts).close(); + try { + Set<OpenOption> mixed = new HashSet<OpenOption>(); + mixed.add(READ); + mixed.add(NOFOLLOW_LINKS); + stream.newByteChannel(link1Entry, mixed).close(); + shouldNotGetHere(); + } catch (IOException x) { } + } + + // Test: newDirectoryStream + stream.newDirectoryStream(dirEntry, true, null).close(); + stream.newDirectoryStream(dirEntry, false, null).close(); + if (supportsLinks) { + stream.newDirectoryStream(link2Entry, true, null).close(); + try { + stream.newDirectoryStream(link2Entry, false, null).close(); + shouldNotGetHere(); + } catch (IOException x) { } + } + + // Test: delete + if (supportsLinks) { + stream.deleteFile(link1Entry); + stream.deleteFile(link2Entry); + } + stream.deleteDirectory(dirEntry); + stream.deleteFile(fileEntry); + + // Test: remove + // (requires resetting environment to get new iterator) + stream.close(); + dir2.moveTo(dir1); + dir1.resolve(fileEntry).createFile(); + stream = (SecureDirectoryStream)dir1.newDirectoryStream(); + dir1.moveTo(dir2); + Iterator<Path> iter = stream.iterator(); + int removed = 0; + while (iter.hasNext()) { + iter.next(); + iter.remove(); + removed++; + } + assertTrue(removed == 1); + + // clean-up + stream.close(); + dir2.delete(); + } + + // Exercise SecureDirectoryStream's move method + static void doMoveTests(Path dir) throws IOException { + Path dir1 = dir.resolve("dir1").createDirectory(); + Path dir2 = dir.resolve("dir2").createDirectory(); + + // create dir1/myfile, dir1/mydir, dir1/mylink + Path fileEntry = Paths.get("myfile"); + dir1.resolve(fileEntry).createFile(); + Path dirEntry = Paths.get("mydir"); + dir1.resolve(dirEntry).createDirectory(); + Path linkEntry = Paths.get("mylink"); + if (supportsLinks) + dir1.resolve(linkEntry).createSymbolicLink(Paths.get("missing")); + + // target name + Path target = Paths.get("newfile"); + + // open stream to both directories + SecureDirectoryStream stream1 = + (SecureDirectoryStream)dir1.newDirectoryStream(); + SecureDirectoryStream stream2 = + (SecureDirectoryStream)dir2.newDirectoryStream(); + + // Test: move dir1/myfile -> dir2/newfile + stream1.move(fileEntry, stream2, target); + assertTrue(dir1.resolve(fileEntry).notExists()); + assertTrue(dir2.resolve(target).exists()); + stream2.deleteFile(target); + + // Test: move dir1/mydir -> dir2/newfile + stream1.move(dirEntry, stream2, target); + assertTrue(dir1.resolve(dirEntry).notExists()); + assertTrue(dir2.resolve(target).exists()); + stream2.deleteDirectory(target); + + // Test: move dir1/mylink -> dir2/newfile + if (supportsLinks) { + stream1.move(linkEntry, stream2, target); + assertTrue(dir2.resolve(target) + .getFileAttributeView(BasicFileAttributeView.class, NOFOLLOW_LINKS) + .readAttributes() + .isSymbolicLink()); + stream2.deleteFile(target); + } + + // Test: move between devices + String testDirAsString = System.getProperty("test.dir"); + if (testDirAsString != null) { + Path testDir = Paths.get(testDirAsString); + if (!dir1.getFileStore().equals(testDir.getFileStore())) { + SecureDirectoryStream ts = + (SecureDirectoryStream)testDir.newDirectoryStream(); + dir1.resolve(fileEntry).createFile(); + try { + stream1.move(fileEntry, ts, target); + shouldNotGetHere(); + } catch (AtomicMoveNotSupportedException x) { } + ts.close(); + stream1.deleteFile(fileEntry); + } + } + + // clean-up + dir1.delete(); + dir2.delete(); + } + + // null and ClosedDirectoryStreamException + static void miscTests(Path dir) throws IOException { + Path file = Paths.get("file"); + dir.resolve(file).createFile(); + + SecureDirectoryStream stream = + (SecureDirectoryStream)dir.newDirectoryStream(); + + // NullPointerException + try { + stream.getFileAttributeView(null); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.getFileAttributeView(null, BasicFileAttributeView.class); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.getFileAttributeView(file, null); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.newByteChannel(null, EnumSet.of(CREATE,WRITE)); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.newByteChannel(null, EnumSet.of(CREATE,WRITE,null)); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.newByteChannel(file, null); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.move(null, stream, file); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.move(file, null, file); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.move(file, stream, null); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.newDirectoryStream(null, true, null); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.deleteFile(null); + shouldNotGetHere(); + } catch (NullPointerException x) { } + try { + stream.deleteDirectory(null); + shouldNotGetHere(); + } catch (NullPointerException x) { } + + // close stream + stream.close(); + stream.close(); // should be no-op + + // ClosedDirectoryStreamException + try { + stream.newDirectoryStream(file, true, null); + shouldNotGetHere(); + } catch (ClosedDirectoryStreamException x) { } + try { + stream.newByteChannel(file, EnumSet.of(READ)); + shouldNotGetHere(); + } catch (ClosedDirectoryStreamException x) { } + try { + stream.move(file, stream, file); + shouldNotGetHere(); + } catch (ClosedDirectoryStreamException x) { } + try { + stream.deleteFile(file); + shouldNotGetHere(); + } catch (ClosedDirectoryStreamException x) { } + + // clean-up + dir.resolve(file).delete(); + } + + static void assertTrue(boolean b) { + if (!b) throw new RuntimeException("Assertion failed"); + } + + static void shouldNotGetHere() { + assertTrue(false); + } +} diff --git a/jdk/test/java/nio/file/FileStore/Basic.java b/jdk/test/java/nio/file/FileStore/Basic.java new file mode 100644 index 00000000000..604795db435 --- /dev/null +++ b/jdk/test/java/nio/file/FileStore/Basic.java @@ -0,0 +1,87 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.FileStore + * @library .. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; + +public class Basic { + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + doTests(dir); + } finally { + TestUtil.removeAll(dir); + } + } + + static void assertTrue(boolean okay) { + if (!okay) + throw new RuntimeException("Assertion failed"); + } + + static void doTests(Path dir) throws IOException { + /** + * Test: Directory should be on FileStore that is writable + */ + assertTrue(!dir.getFileStore().isReadOnly()); + + /** + * Test: Two files should have the same FileStore + */ + FileStore store1 = dir.resolve("foo").createFile().getFileStore(); + FileStore store2 = dir.resolve("bar").createFile().getFileStore(); + assertTrue(store1.equals(store2)); + assertTrue(store2.equals(store1)); + assertTrue(store1.hashCode() == store2.hashCode()); + + /** + * Test: File and FileStore attributes + */ + assertTrue(store1.supportsFileAttributeView("basic")); + + /** + * Test: Enumerate all FileStores + */ + FileStore prev = null; + for (FileStore store: FileSystems.getDefault().getFileStores()) { + System.out.format("%s (name=%s type=%s)\n", store, store.name(), + store.type()); + + // check space attributes + Attributes.readFileStoreSpaceAttributes(store); + + // two distinct FileStores should not be equal + assertTrue(!store.equals(prev)); + prev = store; + } + } +} diff --git a/jdk/test/java/nio/file/FileSystem/Basic.java b/jdk/test/java/nio/file/FileSystem/Basic.java new file mode 100644 index 00000000000..8df7c1e8de6 --- /dev/null +++ b/jdk/test/java/nio/file/FileSystem/Basic.java @@ -0,0 +1,82 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.FileSystem + * @library .. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; + +/** + * Simple santity checks for java.nio.file.FileSystem + */ +public class Basic { + + static void check(boolean okay, String msg) { + if (!okay) + throw new RuntimeException(msg); + } + + static void checkSupported(FileSystem fs, String... views) { + for (String view: views) { + check(fs.supportedFileAttributeViews().contains(view), + "support for '" + view + "' expected"); + } + } + + public static void main(String[] args) throws IOException { + FileSystem fs = FileSystems.getDefault(); + + // close should throw UOE + try { + fs.close(); + throw new RuntimeException("UnsupportedOperationException expected"); + } catch (UnsupportedOperationException e) { } + check(fs.isOpen(), "should be open"); + + check(!fs.isReadOnly(), "should provide read-write access"); + + check(fs.provider().getScheme().equals("file"), + "should use 'file' scheme"); + + // santity check method - need to re-visit this in future as I/O errors + // are possible + for (FileStore store: fs.getFileStores()) { + System.out.println(store); + } + + // sanity check supportedFileAttributeViews + checkSupported(fs, "basic"); + String os = System.getProperty("os.name"); + if (os.equals("SunOS")) + checkSupported(fs, "posix", "unix", "owner", "acl", "xattr"); + if (os.equals("Linux")) + checkSupported(fs, "posix", "unix", "owner", "dos", "xattr"); + if (os.equals("Windows")) + checkSupported(fs, "owner", "dos", "acl", "xattr"); + } +} diff --git a/jdk/test/java/nio/file/Files/ContentType.java b/jdk/test/java/nio/file/Files/ContentType.java new file mode 100644 index 00000000000..a0a5afc22b7 --- /dev/null +++ b/jdk/test/java/nio/file/Files/ContentType.java @@ -0,0 +1,91 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.*; +import java.io.*; + +/** + * Uses Files.probeContentType to probe html file and custom file type. + */ + +public class ContentType { + + static FileRef createHtmlFile() throws IOException { + Path file = File.createTempFile("foo", ".html").toPath(); + OutputStream out = file.newOutputStream(); + try { + out.write("<html><body>foo</body></html>".getBytes()); + } finally { + out.close(); + } + + return file; + } + + static FileRef createUnknownFile() throws IOException { + return File.createTempFile("unknown", "unknown-file-type-789").toPath(); + } + + static FileRef createGrapeFile() throws IOException { + return File.createTempFile("red", ".grape").toPath(); + } + + public static void main(String[] args) throws IOException { + + // exercise default file type detector + FileRef file = createHtmlFile(); + try { + String type = Files.probeContentType(file); + if (type == null) { + System.err.println("Content type cannot be determined - test skipped"); + } else { + if (!type.equals("text/html")) + throw new RuntimeException("Unexpected type: " + type); + } + } finally { + TestUtil.deleteUnchecked(file); + } + file = createUnknownFile(); + try { + String type = Files.probeContentType(file); + if (type != null) + throw new RuntimeException(file + " should not be recognized as:" + + type); + } finally { + TestUtil.deleteUnchecked(file); + } + + // exercise custom file type detector + file = createGrapeFile(); + try { + String type = Files.probeContentType(file); + if (type == null) + throw new RuntimeException("Custom file type detector not installed?"); + if (!type.equals("grape/unknown")) + throw new RuntimeException("Unexpected type: " + type); + } finally { + TestUtil.deleteUnchecked(file); + } + + } +} diff --git a/jdk/test/java/nio/file/Files/CreateFileTree.java b/jdk/test/java/nio/file/Files/CreateFileTree.java new file mode 100644 index 00000000000..17549a7e350 --- /dev/null +++ b/jdk/test/java/nio/file/Files/CreateFileTree.java @@ -0,0 +1,96 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.*; +import java.io.IOException; +import java.util.*; + +/** + * Creates a file tree with possible cycles caused by symbolic links + * to ancestor directories. + */ + +public class CreateFileTree { + + static final Random rand = new Random(); + + public static Path createTemporaryDirectory() throws IOException { + Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir")); + Path dir; + do { + dir = tmpdir.resolve("name" + rand.nextInt()); + } while (dir.exists()); + dir.createDirectory(); + return dir; + } + + public static void main(String[] args) throws IOException { + Path top = createTemporaryDirectory(); + if (!top.isAbsolute()) + top = top.toAbsolutePath(); + + List<Path> dirs = new ArrayList<Path>(); + + // create tree + Queue<Path> queue = new ArrayDeque<Path>(); + queue.add(top); + int total = 1 + rand.nextInt(20); + int n = 0; + Path dir; + while (((dir = queue.poll()) != null) && (n < total)) { + int r = Math.min((total-n), (1+rand.nextInt(3))); + for (int i=0; i<r; i++) { + String name = "dir" + (++n); + Path subdir = dir.resolve(name).createDirectory(); + queue.offer(subdir); + dirs.add(subdir); + } + } + assert dirs.size() >= 2; + + // create a few regular files in the file tree + int files = dirs.size() * 3; + for (int i=0; i<files; i++) { + String name = "file" + (i+1); + int x = rand.nextInt(dirs.size()); + dirs.get(x).resolve(name).createFile(); + } + + // create a few sym links in the file tree so as to create cycles + int links = 1 + rand.nextInt(5); + for (int i=0; i<links; i++) { + int x = rand.nextInt(dirs.size()); + int y; + do { + y = rand.nextInt(dirs.size()); + } while (y != x); + String name = "link" + (i+1); + Path link = dirs.get(x).resolve(name); + Path target = dirs.get(y); + link.createSymbolicLink(target); + } + + // done + System.out.println(top); + } +} diff --git a/jdk/test/java/nio/file/Files/ForceLoad.java b/jdk/test/java/nio/file/Files/ForceLoad.java new file mode 100644 index 00000000000..b6fe84c3496 --- /dev/null +++ b/jdk/test/java/nio/file/Files/ForceLoad.java @@ -0,0 +1,38 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Test library dependencies by invoking Files.probeContentType + * before other methods that would cause nio.dll to be loaded. + */ + +import java.nio.file.*; +import java.io.IOException; + +public class ForceLoad { + + public static void main(String[] args) throws IOException { + Files.probeContentType(Paths.get(".")); + } +} diff --git a/jdk/test/java/nio/file/Files/META-INF/services/java.nio.file.spi.FileTypeDetector b/jdk/test/java/nio/file/Files/META-INF/services/java.nio.file.spi.FileTypeDetector new file mode 100644 index 00000000000..ccd6ac7b604 --- /dev/null +++ b/jdk/test/java/nio/file/Files/META-INF/services/java.nio.file.spi.FileTypeDetector @@ -0,0 +1 @@ +SimpleFileTypeDetector diff --git a/jdk/test/java/nio/file/Files/Misc.java b/jdk/test/java/nio/file/Files/Misc.java new file mode 100644 index 00000000000..dde74a4b546 --- /dev/null +++ b/jdk/test/java/nio/file/Files/Misc.java @@ -0,0 +1,126 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.Files for miscellenous cases not + * covered by other tests + * @library .. + */ + +import java.nio.file.*; +import java.io.IOException; +import java.util.*; + +public class Misc { + + static void npeExpected() { + throw new RuntimeException("NullPointerException expected"); + } + + public static void main(String[] args) throws IOException { + try { + Files.probeContentType(null); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.withDirectory(null, "*", new FileAction<Path>() { + public void invoke(Path entry) { + } + }); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.withDirectory(Paths.get("."), (String)null, new FileAction<Path>() { + public void invoke(Path entry) { + } + }); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.withDirectory(Paths.get("."), "*", null); + npeExpected(); + } catch (NullPointerException e) { + } + + // test propogation of IOException + Path tmpdir = TestUtil.createTemporaryDirectory(); + try { + tmpdir.resolve("foo").createFile(); + try { + Files.withDirectory(tmpdir, new FileAction<Path>() { + public void invoke(Path entry) throws IOException { + throw new IOException(); + } + }); + throw new RuntimeException("IOException expected"); + } catch (IOException e) { + } + } finally { + TestUtil.removeAll(tmpdir); + } + + try { + Files.walkFileTree(null, EnumSet.noneOf(FileVisitOption.class), + Integer.MAX_VALUE, new SimpleFileVisitor<Path>(){}); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.walkFileTree(Paths.get("."), null, Integer.MAX_VALUE, + new SimpleFileVisitor<Path>(){}); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class), + -1, new SimpleFileVisitor<Path>(){}); + throw new RuntimeException("IllegalArgumentExpected expected"); + } catch (IllegalArgumentException e) { + } + + try { + Set<FileVisitOption> opts = new HashSet<FileVisitOption>(1); + opts.add(null); + Files.walkFileTree(Paths.get("."), opts, Integer.MAX_VALUE, + new SimpleFileVisitor<Path>(){}); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class), + Integer.MAX_VALUE, null); + npeExpected(); + } catch (NullPointerException e) { + } + } +} diff --git a/jdk/test/java/nio/file/Files/PrintFileTree.java b/jdk/test/java/nio/file/Files/PrintFileTree.java new file mode 100644 index 00000000000..dc2c49f8db1 --- /dev/null +++ b/jdk/test/java/nio/file/Files/PrintFileTree.java @@ -0,0 +1,78 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; + +/** + * Invokes Files.walkFileTree to traverse a file tree and prints + * each of the directories and files. The -L option causes symbolic + * links to be followed. + */ + +public class PrintFileTree { + + public static void main(String[] args) throws Exception { + boolean followLinks = false; + Path dir; + + if (args[0].equals("-L")) { + followLinks = true; + dir = Paths.get(args[1]); + } else { + dir = Paths.get(args[0]); + } + + Set<FileVisitOption> options = new HashSet<FileVisitOption>(); + if (followLinks) + options.add(FileVisitOption.FOLLOW_LINKS); + + Files.walkFileTree(dir, options, Integer.MAX_VALUE, new FileVisitor<FileRef>() { + public FileVisitResult preVisitDirectory(FileRef dir) { + System.out.println(dir); + return FileVisitResult.CONTINUE; + } + public FileVisitResult preVisitDirectoryFailed(FileRef dir, IOException exc) { + exc.printStackTrace(); + return FileVisitResult.CONTINUE; + } + public FileVisitResult visitFile(FileRef file, BasicFileAttributes attrs) { + System.out.println(file); + return FileVisitResult.CONTINUE; + } + public FileVisitResult postVisitDirectory(FileRef dir, IOException exc) { + if (exc != null) { + exc.printStackTrace(); + return FileVisitResult.TERMINATE; + } + return FileVisitResult.CONTINUE; + } + public FileVisitResult visitFileFailed(FileRef file, IOException exc) { + exc.printStackTrace(); + return FileVisitResult.TERMINATE; + } + }); + } +} diff --git a/jdk/test/java/nio/file/Files/SimpleFileTypeDetector.java b/jdk/test/java/nio/file/Files/SimpleFileTypeDetector.java new file mode 100644 index 00000000000..0b66706d636 --- /dev/null +++ b/jdk/test/java/nio/file/Files/SimpleFileTypeDetector.java @@ -0,0 +1,47 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.*; +import java.nio.file.spi.FileTypeDetector; +import java.io.*; + + +public class SimpleFileTypeDetector extends FileTypeDetector { + public SimpleFileTypeDetector() { + } + + public String probeContentType(FileRef file) throws IOException { + + System.out.println("probe " + file + "..."); + + if (file instanceof Path) { + String name = ((Path)file).toString(); + if (name.endsWith(".grape")) { + return "grape/unknown"; + } + } + + // unknown + return null; + } +} diff --git a/jdk/test/java/nio/file/Files/SkipSiblings.java b/jdk/test/java/nio/file/Files/SkipSiblings.java new file mode 100644 index 00000000000..e8524552012 --- /dev/null +++ b/jdk/test/java/nio/file/Files/SkipSiblings.java @@ -0,0 +1,85 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; + +/** + * Unit test for Files.walkFileTree to test SKIP_SIBLINGS return value. + */ + +public class SkipSiblings { + + static final Random rand = new Random(); + static final Set<Path> skipped = new HashSet<Path>(); + + // check if this path's directory has been skipped + static void check(Path path) { + if (skipped.contains(path.getParent())) + throw new RuntimeException(path + " should not have been visited"); + } + + // indicates if the siblings of this path should be skipped + static boolean skip(Path path) { + Path parent = path.getParent(); + if (parent != null && rand.nextBoolean()) { + skipped.add(parent); + return true; + } + return false; + } + + public static void main(String[] args) throws Exception { + Path dir = Paths.get(args[0]); + + Files.walkFileTree(dir, new FileVisitor<Path>() { + public FileVisitResult preVisitDirectory(Path dir) { + check(dir); + if (skip(dir)) + return FileVisitResult.SKIP_SIBLINGS; + return FileVisitResult.CONTINUE; + } + public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) { + throw new RuntimeException(exc); + } + + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + check(file); + if (skip(file)) + return FileVisitResult.SKIP_SIBLINGS; + return FileVisitResult.CONTINUE; + } + public FileVisitResult postVisitDirectory(Path dir, IOException x) { + if (x != null) + throw new RuntimeException(x); + check(dir); + return FileVisitResult.CONTINUE; + } + public FileVisitResult visitFileFailed(Path file, IOException x) { + throw new RuntimeException(x); + } + }); + } +} diff --git a/jdk/test/java/nio/file/Files/TerminateWalk.java b/jdk/test/java/nio/file/Files/TerminateWalk.java new file mode 100644 index 00000000000..82fc8ed579f --- /dev/null +++ b/jdk/test/java/nio/file/Files/TerminateWalk.java @@ -0,0 +1,70 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; + +/** + * Unit test for Files.walkFileTree to test TERMINATE return value + */ + +public class TerminateWalk { + + static final Random rand = new Random(); + static boolean terminated; + + static FileVisitResult maybeTerminate() { + if (terminated) + throw new RuntimeException("FileVisitor invoked after termination"); + if (rand.nextInt(10) == 0) { + terminated = true; + return FileVisitResult.TERMINATE; + } else { + return FileVisitResult.CONTINUE; + } + } + + public static void main(String[] args) throws Exception { + Path dir = Paths.get(args[0]); + + Files.walkFileTree(dir, new FileVisitor<Path>() { + public FileVisitResult preVisitDirectory(Path dir) { + return maybeTerminate(); + } + public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) { + return maybeTerminate(); + } + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + return maybeTerminate(); + } + public FileVisitResult postVisitDirectory(Path dir, IOException x) { + return maybeTerminate(); + } + public FileVisitResult visitFileFailed(Path file, IOException x) { + return maybeTerminate(); + } + }); + } +} diff --git a/jdk/test/java/nio/file/Files/content_type.sh b/jdk/test/java/nio/file/Files/content_type.sh new file mode 100644 index 00000000000..46f4626c72a --- /dev/null +++ b/jdk/test/java/nio/file/Files/content_type.sh @@ -0,0 +1,71 @@ +# +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 4313887 +# @summary Unit test for probeContentType method +# @library .. +# @build ContentType SimpleFileTypeDetector +# @run shell content_type.sh + +# if TESTJAVA isn't set then we assume an interactive run. + +if [ -z "$TESTJAVA" ]; then + TESTSRC=. + TESTCLASSES=. + JAVA=java +else + JAVA="${TESTJAVA}/bin/java" +fi + +OS=`uname -s` +case "$OS" in + Windows_* ) + CLASSPATH="${TESTCLASSES};${TESTSRC}" + ;; + * ) + CLASSPATH=${TESTCLASSES}:${TESTSRC} + ;; +esac +export CLASSPATH + +failures=0 + +go() { + echo '' + $JAVA $1 $2 $3 2>&1 + if [ $? != 0 ]; then failures=`expr $failures + 1`; fi +} + +# Run the test + +go ContentType + +# +# Results +# +echo '' +if [ $failures -gt 0 ]; + then echo "$failures test(s) failed"; + else echo "All test(s) passed"; fi +exit $failures diff --git a/jdk/test/java/nio/file/Files/walk_file_tree.sh b/jdk/test/java/nio/file/Files/walk_file_tree.sh new file mode 100644 index 00000000000..73022d31d58 --- /dev/null +++ b/jdk/test/java/nio/file/Files/walk_file_tree.sh @@ -0,0 +1,86 @@ +# +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 4313887 +# @summary Unit test for walkFileTree method +# @build CreateFileTree PrintFileTree SkipSiblings TerminateWalk +# @run shell walk_file_tree.sh + +# if TESTJAVA isn't set then we assume an interactive run. + +if [ -z "$TESTJAVA" ]; then + TESTSRC=. + TESTCLASSES=. + JAVA=java +else + JAVA="${TESTJAVA}/bin/java" +fi + +OS=`uname -s` +case "$OS" in + Windows_* ) + echo "This test does not run on Windows" + exit 0 + ;; + * ) + CLASSPATH=${TESTCLASSES}:${TESTSRC} + ;; +esac +export CLASSPATH + +# create the file tree +ROOT=`$JAVA CreateFileTree` +if [ $? != 0 ]; then exit 1; fi + +failures=0 + +# print the file tree and compare output with find(1) +$JAVA PrintFileTree "$ROOT" > out1 +find "$ROOT" > out2 +diff out1 out2 +if [ $? != 0 ]; then failures=`expr $failures + 1`; fi + +# repeat test following links (use -follow instead of -L +# to allow running on older systems) +$JAVA PrintFileTree -L "$ROOT" > out1 +find "$ROOT" -follow > out2 +diff out1 out2 +if [ $? != 0 ]; then failures=`expr $failures + 1`; fi + +# test SKIP_SIBLINGS +$JAVA SkipSiblings "$ROOT" +if [ $? != 0 ]; then failures=`expr $failures + 1`; fi + +# test TERMINATE +$JAVA TerminateWalk "$ROOT" +if [ $? != 0 ]; then failures=`expr $failures + 1`; fi + +# clean-up +rm -r "$ROOT" + +echo '' +if [ $failures -gt 0 ]; + then echo "$failures test(s) failed"; + else echo "Test passed"; fi +exit $failures diff --git a/jdk/test/java/nio/file/Path/CopyAndMove.java b/jdk/test/java/nio/file/Path/CopyAndMove.java new file mode 100644 index 00000000000..4e4c75fd2aa --- /dev/null +++ b/jdk/test/java/nio/file/Path/CopyAndMove.java @@ -0,0 +1,983 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.Path copyTo/moveTo methods + * @library .. + */ + +import java.nio.ByteBuffer; +import java.nio.file.*; +import static java.nio.file.StandardCopyOption.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; +import java.io.*; +import java.util.*; + +public class CopyAndMove { + static final Random rand = new Random(); + static boolean heads() { return rand.nextBoolean(); } + static boolean supportsLinks; + + public static void main(String[] args) throws Exception { + Path dir1 = TestUtil.createTemporaryDirectory(); + try { + supportsLinks = TestUtil.supportsLinks(dir1); + + // Exercise copyTo + doCopyTests(dir1); + + // Exercise moveTo + // if test.dir differs to temporary file system then can test + // moving between devices + String testDir = System.getProperty("test.dir"); + Path dir2 = (testDir != null) ? Paths.get(testDir) : dir1; + doMoveTests(dir1, dir2); + + } finally { + TestUtil.removeAll(dir1); + } + } + + static void checkBasicAttributes(BasicFileAttributes attrs1, + BasicFileAttributes attrs2) + { + // check file type + assertTrue(attrs1.isRegularFile() == attrs2.isRegularFile()); + assertTrue(attrs1.isDirectory() == attrs2.isDirectory()); + assertTrue(attrs1.isSymbolicLink() == attrs2.isSymbolicLink()); + assertTrue(attrs1.isOther() == attrs2.isOther()); + + // check last modified time (assume millisecond precision) + long time1 = attrs1.resolution().toMillis(attrs1.lastModifiedTime()); + long time2 = attrs1.resolution().toMillis(attrs2.lastModifiedTime()); + assertTrue(time1 == time2); + + // check size + if (attrs1.isRegularFile()) + assertTrue(attrs1.size() == attrs2.size()); + } + + static void checkPosixAttributes(PosixFileAttributes attrs1, + PosixFileAttributes attrs2) + { + assertTrue(attrs1.permissions().equals(attrs2.permissions())); + assertTrue(attrs1.owner().equals(attrs2.owner())); + assertTrue(attrs1.group().equals(attrs2.group())); + } + + static void checkDosAttributes(DosFileAttributes attrs1, + DosFileAttributes attrs2) + { + assertTrue(attrs1.isReadOnly() == attrs2.isReadOnly()); + assertTrue(attrs1.isHidden() == attrs2.isHidden()); + assertTrue(attrs1.isArchive() == attrs2.isArchive()); + assertTrue(attrs1.isSystem() == attrs2.isSystem()); + } + + static void checkUserDefinedFileAttributes(Map<String,ByteBuffer> attrs1, + Map<String,ByteBuffer> attrs2) + { + assert attrs1.size() == attrs2.size(); + for (String name: attrs1.keySet()) { + ByteBuffer bb1 = attrs1.get(name); + ByteBuffer bb2 = attrs2.get(name); + assertTrue(bb2 != null); + assertTrue(bb1.equals(bb2)); + } + } + + static Map<String,ByteBuffer> readUserDefinedFileAttributes(Path file) + throws IOException + { + UserDefinedFileAttributeView view = file + .getFileAttributeView(UserDefinedFileAttributeView.class); + Map<String,ByteBuffer> result = new HashMap<String,ByteBuffer>(); + for (String name: view.list()) { + int size = view.size(name); + ByteBuffer bb = ByteBuffer.allocate(size); + int n = view.read(name, bb); + assertTrue(n == size); + bb.flip(); + result.put(name, bb); + } + return result; + } + + // move source to target with verification + static void moveAndVerify(Path source, Path target, CopyOption... options) + throws IOException + { + // read attributes before file is moved + BasicFileAttributes basicAttributes = null; + PosixFileAttributes posixAttributes = null; + DosFileAttributes dosAttributes = null; + Map<String,ByteBuffer> namedAttributes = null; + + // get file attributes of source file + String os = System.getProperty("os.name"); + if (os.equals("SunOS") || os.equals("Linux")) { + posixAttributes = Attributes.readPosixFileAttributes(source, NOFOLLOW_LINKS); + basicAttributes = posixAttributes; + } + if (os.startsWith("Windows")) { + dosAttributes = Attributes.readDosFileAttributes(source, NOFOLLOW_LINKS); + basicAttributes = dosAttributes; + } + if (basicAttributes == null) + basicAttributes = Attributes.readBasicFileAttributes(source, NOFOLLOW_LINKS); + + // hash file contents if regular file + int hash = (basicAttributes.isRegularFile()) ? computeHash(source) : 0; + + // record link target if symbolic link + Path linkTarget = null; + if (basicAttributes.isSymbolicLink()) + linkTarget = source.readSymbolicLink(); + + // read named attributes if available (and file is not a sym link) + if (!basicAttributes.isSymbolicLink() && + source.getFileStore().supportsFileAttributeView("xattr")) + { + namedAttributes = readUserDefinedFileAttributes(source); + } + + // move file + source.moveTo(target, options); + + // verify source does not exist + assertTrue(source.notExists()); + + // verify file contents + if (basicAttributes.isRegularFile()) { + if (computeHash(target) != hash) + throw new RuntimeException("Failed to verify move of regular file"); + } + + // verify link target + if (basicAttributes.isSymbolicLink()) { + if (!target.readSymbolicLink().equals(linkTarget)) + throw new RuntimeException("Failed to verify move of symbolic link"); + } + + // verify basic attributes + checkBasicAttributes(basicAttributes, + Attributes.readBasicFileAttributes(target, NOFOLLOW_LINKS)); + + // verify POSIX attributes + if (posixAttributes != null && !basicAttributes.isSymbolicLink()) { + checkPosixAttributes(posixAttributes, + Attributes.readPosixFileAttributes(target, NOFOLLOW_LINKS)); + } + + // verify DOS attributes + if (dosAttributes != null && !basicAttributes.isSymbolicLink()) { + checkDosAttributes(dosAttributes, + Attributes.readDosFileAttributes(target, NOFOLLOW_LINKS)); + } + + // verify named attributes + if (namedAttributes != null && + target.getFileStore().supportsFileAttributeView("xattr")) + { + checkUserDefinedFileAttributes(namedAttributes, readUserDefinedFileAttributes(target)); + } + } + + /** + * Tests all possible ways to invoke moveTo + */ + static void doMoveTests(Path dir1, Path dir2) throws IOException { + Path source, target, entry; + + boolean sameDevice = dir1.getFileStore().equals(dir2.getFileStore()); + + // -- regular file -- + + /** + * Test: move regular file, target does not exist + */ + source = createSourceFile(dir1); + target = getTargetFile(dir1); + moveAndVerify(source, target); + target.delete(); + + /** + * Test: move regular file, target exists + */ + source = createSourceFile(dir1); + target = getTargetFile(dir1).createFile(); + try { + moveAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + target.delete(); + target.createDirectory(); + try { + moveAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + source.delete(); + target.delete(); + + /** + * Test: move regular file, target does not exist + */ + source = createSourceFile(dir1); + target = getTargetFile(dir1); + moveAndVerify(source, target, REPLACE_EXISTING); + target.delete(); + + /** + * Test: move regular file, target exists + */ + source = createSourceFile(dir1); + target = getTargetFile(dir1).createFile(); + moveAndVerify(source, target, REPLACE_EXISTING); + target.delete(); + + /** + * Test: move regular file, target exists and is empty directory + */ + source = createSourceFile(dir1); + target = getTargetFile(dir1).createDirectory(); + moveAndVerify(source, target, REPLACE_EXISTING); + target.delete(); + + /** + * Test: move regular file, target exists and is non-empty directory + */ + source = createSourceFile(dir1); + target = getTargetFile(dir1).createDirectory(); + entry = target.resolve("foo").createFile(); + try { + moveAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + entry.delete(); + source.delete(); + target.delete(); + + /** + * Test atomic move of regular file (same file store) + */ + source = createSourceFile(dir1); + target = getTargetFile(dir1); + moveAndVerify(source, target, ATOMIC_MOVE); + target.delete(); + + /** + * Test atomic move of regular file (different file store) + */ + if (!sameDevice) { + source = createSourceFile(dir1); + target = getTargetFile(dir2); + try { + moveAndVerify(source, target, ATOMIC_MOVE); + throw new RuntimeException("AtomicMoveNotSupportedException expected"); + } catch (AtomicMoveNotSupportedException x) { + } + source.delete(); + } + + // -- directories -- + + /* + * Test: move empty directory, target does not exist + */ + source = createSourceDirectory(dir1); + target = getTargetFile(dir1); + moveAndVerify(source, target); + target.delete(); + + /** + * Test: move empty directory, target exists + */ + source = createSourceDirectory(dir1); + target = getTargetFile(dir1).createFile(); + try { + moveAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + target.delete(); + target.createDirectory(); + try { + moveAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + source.delete(); + target.delete(); + + /** + * Test: move empty directory, target does not exist + */ + source = createSourceDirectory(dir1); + target = getTargetFile(dir1); + moveAndVerify(source, target, REPLACE_EXISTING); + target.delete(); + + /** + * Test: move empty directory, target exists + */ + source = createSourceDirectory(dir1); + target = getTargetFile(dir1).createFile(); + moveAndVerify(source, target, REPLACE_EXISTING); + target.delete(); + + /** + * Test: move empty, target exists and is empty directory + */ + source = createSourceDirectory(dir1); + target = getTargetFile(dir1).createDirectory(); + moveAndVerify(source, target, REPLACE_EXISTING); + target.delete(); + + /** + * Test: move empty directory, target exists and is non-empty directory + */ + source = createSourceDirectory(dir1); + target = getTargetFile(dir1).createDirectory(); + entry = target.resolve("foo").createFile(); + try { + moveAndVerify(source, target, REPLACE_EXISTING); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + entry.delete(); + source.delete(); + target.delete(); + + /** + * Test: move non-empty directory (same file system) + */ + source = createSourceDirectory(dir1); + source.resolve("foo").createFile(); + target = getTargetFile(dir1); + moveAndVerify(source, target); + target.resolve("foo").delete(); + target.delete(); + + /** + * Test: move non-empty directory (different file store) + */ + if (!sameDevice) { + source = createSourceDirectory(dir1); + source.resolve("foo").createFile(); + target = getTargetFile(dir2); + try { + moveAndVerify(source, target); + throw new RuntimeException("IOException expected"); + } catch (IOException x) { + } + source.resolve("foo").delete(); + source.delete(); + } + + /** + * Test atomic move of directory (same file store) + */ + source = createSourceDirectory(dir1); + source.resolve("foo").createFile(); + target = getTargetFile(dir1); + moveAndVerify(source, target, ATOMIC_MOVE); + target.resolve("foo").delete(); + target.delete(); + + // -- symbolic links -- + + /** + * Test: Move symbolic link to file, target does not exist + */ + if (supportsLinks) { + Path tmp = createSourceFile(dir1); + source = dir1.resolve("link").createSymbolicLink(tmp); + target = getTargetFile(dir1); + moveAndVerify(source, target); + target.delete(); + tmp.delete(); + } + + /** + * Test: Move symbolic link to directory, target does not exist + */ + if (supportsLinks) { + source = dir1.resolve("link").createSymbolicLink(dir2); + target = getTargetFile(dir1); + moveAndVerify(source, target); + target.delete(); + } + + /** + * Test: Move broken symbolic link, target does not exists + */ + if (supportsLinks) { + Path tmp = Paths.get("doesnotexist"); + source = dir1.resolve("link").createSymbolicLink(tmp); + target = getTargetFile(dir1); + moveAndVerify(source, target); + target.delete(); + } + + /** + * Test: Move symbolic link, target exists + */ + if (supportsLinks) { + source = dir1.resolve("link").createSymbolicLink(dir2); + target = getTargetFile(dir1).createFile(); + try { + moveAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + source.delete(); + target.delete(); + } + + /** + * Test: Move regular file, target exists + */ + if (supportsLinks) { + source = dir1.resolve("link").createSymbolicLink(dir2); + target = getTargetFile(dir1).createFile(); + moveAndVerify(source, target, REPLACE_EXISTING); + target.delete(); + } + + /** + * Test: move symbolic link, target exists and is empty directory + */ + if (supportsLinks) { + source = dir1.resolve("link").createSymbolicLink(dir2); + target = getTargetFile(dir1).createDirectory(); + moveAndVerify(source, target, REPLACE_EXISTING); + target.delete(); + } + + /** + * Test: symbolic link, target exists and is non-empty directory + */ + if (supportsLinks) { + source = dir1.resolve("link").createSymbolicLink(dir2); + target = getTargetFile(dir1).createDirectory(); + entry = target.resolve("foo").createFile(); + try { + moveAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + entry.delete(); + source.delete(); + target.delete(); + } + + /** + * Test atomic move of symbolic link (same file store) + */ + if (supportsLinks) { + source = dir1.resolve("link").createSymbolicLink(dir1); + target = getTargetFile(dir1).createFile(); + moveAndVerify(source, target, REPLACE_EXISTING); + target.delete(); + } + + // -- misc. tests -- + + /** + * Test nulls + */ + source = createSourceFile(dir1); + target = getTargetFile(dir1); + try { + source.moveTo(null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + try { + source.moveTo(target, (CopyOption[])null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + try { + CopyOption[] opts = { REPLACE_EXISTING, null }; + source.moveTo(target, opts); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + source.delete(); + + /** + * Test UOE + */ + source = createSourceFile(dir1); + target = getTargetFile(dir1); + try { + source.moveTo(target, new CopyOption() { }); + } catch (UnsupportedOperationException x) { } + try { + source.moveTo(target, REPLACE_EXISTING, new CopyOption() { }); + } catch (UnsupportedOperationException x) { } + source.delete(); + } + + // copy source to target with verification + static void copyAndVerify(Path source, Path target, CopyOption... options) + throws IOException + { + source.copyTo(target, options); + + // get attributes of source and target file to verify copy + boolean followLinks = true; + LinkOption[] linkOptions = new LinkOption[0]; + boolean copyAttributes = false; + for (CopyOption opt : options) { + if (opt == NOFOLLOW_LINKS) { + followLinks = false; + linkOptions = new LinkOption[] { NOFOLLOW_LINKS }; + } + if (opt == COPY_ATTRIBUTES) + copyAttributes = true; + } + BasicFileAttributes basicAttributes = Attributes + .readBasicFileAttributes(source, linkOptions); + + // check hash if regular file + if (basicAttributes.isRegularFile()) + assertTrue(computeHash(source) == computeHash(target)); + + // check link target if symbolic link + if (basicAttributes.isSymbolicLink()) + assert( source.readSymbolicLink().equals(target.readSymbolicLink())); + + // check that attributes are copied + if (copyAttributes && followLinks) { + checkBasicAttributes(basicAttributes, + Attributes.readBasicFileAttributes(source, linkOptions)); + + // check POSIX attributes are copied + String os = System.getProperty("os.name"); + if (os.equals("SunOS") || os.equals("Linux")) { + checkPosixAttributes( + Attributes.readPosixFileAttributes(source, linkOptions), + Attributes.readPosixFileAttributes(target, linkOptions)); + } + + // check DOS attributes are copied + if (os.startsWith("Windows")) { + checkDosAttributes( + Attributes.readDosFileAttributes(source, linkOptions), + Attributes.readDosFileAttributes(target, linkOptions)); + } + + // check named attributes are copied + if (followLinks && + source.getFileStore().supportsFileAttributeView("xattr") && + target.getFileStore().supportsFileAttributeView("xattr")) + { + checkUserDefinedFileAttributes(readUserDefinedFileAttributes(source), + readUserDefinedFileAttributes(target)); + } + } + } + + /** + * Tests all possible ways to invoke copyTo + */ + static void doCopyTests(Path dir) throws IOException { + Path source, target, link, entry; + + // -- regular file -- + + /** + * Test: move regular file, target does not exist + */ + source = createSourceFile(dir); + target = getTargetFile(dir); + copyAndVerify(source, target); + source.delete(); + target.delete(); + + /** + * Test: copy regular file, target exists + */ + source = createSourceFile(dir); + target = getTargetFile(dir).createFile(); + try { + copyAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + target.delete(); + target.createDirectory(); + try { + copyAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + source.delete(); + target.delete(); + + /** + * Test: copy regular file, target does not exist + */ + source = createSourceFile(dir); + target = getTargetFile(dir); + copyAndVerify(source, target, REPLACE_EXISTING); + source.delete(); + target.delete(); + + /** + * Test: copy regular file, target exists + */ + source = createSourceFile(dir); + target = getTargetFile(dir).createFile(); + copyAndVerify(source, target, REPLACE_EXISTING); + source.delete(); + target.delete(); + + /** + * Test: copy regular file, target exists and is empty directory + */ + source = createSourceFile(dir); + target = getTargetFile(dir).createDirectory(); + copyAndVerify(source, target, REPLACE_EXISTING); + source.delete(); + target.delete(); + + /** + * Test: copy regular file, target exists and is non-empty directory + */ + source = createSourceFile(dir); + target = getTargetFile(dir).createDirectory(); + entry = target.resolve("foo").createFile(); + try { + copyAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + entry.delete(); + source.delete(); + target.delete(); + + /** + * Test: copy regular file + attributes + */ + source = createSourceFile(dir); + target = getTargetFile(dir); + copyAndVerify(source, target, COPY_ATTRIBUTES); + source.delete(); + target.delete(); + + + // -- directory -- + + /* + * Test: copy directory, target does not exist + */ + source = createSourceDirectory(dir); + target = getTargetFile(dir); + copyAndVerify(source, target); + source.delete(); + target.delete(); + + /** + * Test: copy directory, target exists + */ + source = createSourceDirectory(dir); + target = getTargetFile(dir).createFile(); + try { + copyAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + target.delete(); + target.createDirectory(); + try { + copyAndVerify(source, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + source.delete(); + target.delete(); + + /** + * Test: copy directory, target does not exist + */ + source = createSourceDirectory(dir); + target = getTargetFile(dir); + copyAndVerify(source, target, REPLACE_EXISTING); + source.delete(); + target.delete(); + + /** + * Test: copy directory, target exists + */ + source = createSourceDirectory(dir); + target = getTargetFile(dir).createFile(); + copyAndVerify(source, target, REPLACE_EXISTING); + source.delete(); + target.delete(); + + /** + * Test: copy directory, target exists and is empty directory + */ + source = createSourceDirectory(dir); + target = getTargetFile(dir).createDirectory(); + copyAndVerify(source, target, REPLACE_EXISTING); + source.delete(); + target.delete(); + + /** + * Test: copy directory, target exists and is non-empty directory + */ + source = createSourceDirectory(dir); + target = getTargetFile(dir).createDirectory(); + entry = target.resolve("foo").createFile(); + try { + copyAndVerify(source, target, REPLACE_EXISTING); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } + entry.delete(); + source.delete(); + target.delete(); + + /* + * Test: copy directory + attributes + */ + source = createSourceDirectory(dir); + target = getTargetFile(dir); + copyAndVerify(source, target, COPY_ATTRIBUTES); + source.delete(); + target.delete(); + + // -- symbolic links -- + + /** + * Test: Follow link + */ + if (supportsLinks) { + source = createSourceFile(dir); + link = dir.resolve("link").createSymbolicLink(source); + target = getTargetFile(dir); + copyAndVerify(link, target); + link.delete(); + source.delete(); + } + + /** + * Test: Copy link (to file) + */ + if (supportsLinks) { + source = createSourceFile(dir); + link = dir.resolve("link").createSymbolicLink(source); + target = getTargetFile(dir); + copyAndVerify(link, target, NOFOLLOW_LINKS); + link.delete(); + source.delete(); + } + + /** + * Test: Copy link (to directory) + */ + if (supportsLinks) { + source = dir.resolve("mydir").createDirectory(); + link = dir.resolve("link").createSymbolicLink(source); + target = getTargetFile(dir); + copyAndVerify(link, target, NOFOLLOW_LINKS); + link.delete(); + source.delete(); + } + + /** + * Test: Copy broken link + */ + if (supportsLinks) { + assertTrue(source.notExists()); + link = dir.resolve("link").createSymbolicLink(source); + target = getTargetFile(dir); + copyAndVerify(link, target, NOFOLLOW_LINKS); + link.delete(); + } + + /** + * Test: Copy link to UNC (Windows only) + */ + if (supportsLinks && + System.getProperty("os.name").startsWith("Windows")) + { + Path unc = Paths.get("\\\\rialto\\share\\file"); + link = dir.resolve("link").createSymbolicLink(unc); + target = getTargetFile(dir); + copyAndVerify(link, target, NOFOLLOW_LINKS); + link.delete(); + } + + // -- misc. tests -- + + /** + * Test nulls + */ + source = createSourceFile(dir); + target = getTargetFile(dir); + try { + source.copyTo(null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + try { + source.copyTo(target, (CopyOption[])null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + try { + CopyOption[] opts = { REPLACE_EXISTING, null }; + source.copyTo(target, opts); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + source.delete(); + + /** + * Test UOE + */ + source = createSourceFile(dir); + target = getTargetFile(dir); + try { + source.copyTo(target, new CopyOption() { }); + } catch (UnsupportedOperationException x) { } + try { + source.copyTo(target, REPLACE_EXISTING, new CopyOption() { }); + } catch (UnsupportedOperationException x) { } + source.delete(); + } + + + static void assertTrue(boolean value) { + if (!value) + throw new RuntimeException("Assertion failed"); + } + + // computes simple hash of the given file + static int computeHash(Path file) throws IOException { + int h = 0; + + InputStream in = file.newInputStream(); + try { + byte[] buf = new byte[1024]; + int n; + do { + n = in.read(buf); + for (int i=0; i<n; i++) { + h = 31*h + (buf[i] & 0xff); + } + } while (n > 0); + } finally { + in.close(); + } + return h; + } + + // create file of random size in given directory + static Path createSourceFile(Path dir) throws IOException { + String name = "source" + Integer.toString(rand.nextInt()); + Path file = dir.resolve(name).createFile(); + byte[] bytes = new byte[rand.nextInt(128*1024)]; + rand.nextBytes(bytes); + OutputStream out = file.newOutputStream(); + try { + out.write(bytes); + } finally { + out.close(); + } + randomizeAttributes(file); + return file; + } + + // create directory in the given directory + static Path createSourceDirectory(Path dir) throws IOException { + String name = "sourcedir" + Integer.toString(rand.nextInt()); + Path subdir = dir.resolve(name).createDirectory(); + randomizeAttributes(subdir); + return subdir; + } + + // "randomize" the file attributes of the given file. + static void randomizeAttributes(Path file) throws IOException { + String os = System.getProperty("os.name"); + boolean isWindows = os.startsWith("Windows"); + boolean isUnix = os.equals("SunOS") || os.equals("Linux"); + boolean isDirectory = Attributes.readBasicFileAttributes(file, NOFOLLOW_LINKS) + .isDirectory(); + + if (isUnix) { + Set<PosixFilePermission> perms = Attributes + .readPosixFileAttributes(file, NOFOLLOW_LINKS).permissions(); + PosixFilePermission[] toChange = { + PosixFilePermission.GROUP_READ, + PosixFilePermission.GROUP_WRITE, + PosixFilePermission.GROUP_EXECUTE, + PosixFilePermission.OTHERS_READ, + PosixFilePermission.OTHERS_WRITE, + PosixFilePermission.OTHERS_EXECUTE + }; + for (PosixFilePermission perm: toChange) { + if (heads()) { + perms.add(perm); + } else { + perms.remove(perm); + } + } + Attributes.setPosixFilePermissions(file, perms); + } + + if (isWindows) { + DosFileAttributeView view = file + .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS); + // only set or unset the hidden attribute + view.setHidden(heads()); + } + + boolean addUserDefinedFileAttributes = heads() && + file.getFileStore().supportsFileAttributeView("xattr"); + + // remove this when copying a direcory copies its named streams + if (isWindows && isDirectory) addUserDefinedFileAttributes = false; + + if (addUserDefinedFileAttributes) { + UserDefinedFileAttributeView view = file + .getFileAttributeView(UserDefinedFileAttributeView.class); + int n = rand.nextInt(16); + while (n > 0) { + byte[] value = new byte[1 + rand.nextInt(100)]; + view.write("user." + Integer.toString(n), ByteBuffer.wrap(value)); + n--; + } + } + } + + // create name for file in given directory + static Path getTargetFile(Path dir) throws IOException { + String name = "target" + Integer.toString(rand.nextInt()); + return dir.resolve(name); + } + } diff --git a/jdk/test/java/nio/file/Path/DeleteOnClose.java b/jdk/test/java/nio/file/Path/DeleteOnClose.java new file mode 100644 index 00000000000..8bc0e852c3e --- /dev/null +++ b/jdk/test/java/nio/file/Path/DeleteOnClose.java @@ -0,0 +1,77 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.*; +import static java.nio.file.StandardOpenOption.*; +import java.io.*; +import java.util.*; + +public class DeleteOnClose { + + public static void main(String[] args) throws IOException { + // open file but do not close it. Its existance will be checked by + // the calling script. + Paths.get(args[0]).newByteChannel(READ, WRITE, DELETE_ON_CLOSE); + + // check temporary file has been deleted after closing it + Path file = File.createTempFile("blah", "tmp").toPath(); + file.newByteChannel(READ, WRITE, DELETE_ON_CLOSE).close(); + if (file.exists()) + throw new RuntimeException("Temporary file was not deleted"); + + Path dir = TestUtil.createTemporaryDirectory(); + try { + // check that DELETE_ON_CLOSE fails when file is a sym link + if (TestUtil.supportsLinks(dir)) { + file = dir.resolve("foo").createFile(); + Path link = dir.resolve("link").createSymbolicLink(file); + try { + link.newByteChannel(READ, WRITE, DELETE_ON_CLOSE); + throw new RuntimeException("IOException expected"); + } catch (IOException ignore) { } + } + + // check that DELETE_ON_CLOSE works with files created via open + // directories + DirectoryStream stream = dir.newDirectoryStream(); + try { + if (stream instanceof SecureDirectoryStream) { + SecureDirectoryStream secure = (SecureDirectoryStream)stream; + file = Paths.get("foo"); + + Set<OpenOption> opts = new HashSet<OpenOption>(); + opts.add(WRITE); + opts.add(DELETE_ON_CLOSE); + secure.newByteChannel(file, opts).close(); + + if (dir.resolve(file).exists()) + throw new RuntimeException("File not deleted"); + } + } finally { + stream.close(); + } + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/Path/InterruptCopy.java b/jdk/test/java/nio/file/Path/InterruptCopy.java new file mode 100644 index 00000000000..d7962224eb1 --- /dev/null +++ b/jdk/test/java/nio/file/Path/InterruptCopy.java @@ -0,0 +1,119 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for Sun-specific ExtendedCopyOption.INTERRUPTIBLE option + * @library .. + * @run main/othervm -XX:-UseVMInterruptibleIO InterruptCopy + */ + +import java.nio.file.*; +import java.nio.file.attribute.Attributes; +import java.io.*; +import java.util.concurrent.*; +import com.sun.nio.file.ExtendedCopyOption; + +public class InterruptCopy { + + private static final long FILE_SIZE_TO_COPY = 512 * 1024 * 1024; + private static final int DELAY_IN_MS = 500; + + public static void main(String[] args) throws Exception { + Path dir = TestUtil.createTemporaryDirectory(); + try { + FileStore store = dir.getFileStore(); + System.out.format("Checking space (%s)\n", store); + long usableSpace = Attributes + .readFileStoreSpaceAttributes(store).usableSpace(); + if (usableSpace < 2*FILE_SIZE_TO_COPY) { + System.out.println("Insufficient disk space to run test."); + return; + } + doTest(dir); + } finally { + TestUtil.removeAll(dir); + } + } + + static void doTest(Path dir) throws Exception { + final Path source = dir.resolve("foo"); + final Path target = dir.resolve("bar"); + + // create source file (don't create it as sparse file because we + // require the copy to take a long time) + System.out.println("Creating source file..."); + byte[] buf = new byte[32*1024]; + long total = 0; + OutputStream out = source.newOutputStream(); + try { + do { + out.write(buf); + total += buf.length; + } while (total < FILE_SIZE_TO_COPY); + } finally { + out.close(); + } + System.out.println("Source file created."); + + ScheduledExecutorService pool = + Executors.newSingleThreadScheduledExecutor(); + try { + // copy source to target in main thread, interrupting it after a delay + final Thread me = Thread.currentThread(); + pool.schedule(new Runnable() { + public void run() { + me.interrupt(); + }}, DELAY_IN_MS, TimeUnit.MILLISECONDS); + System.out.println("Copying file..."); + try { + source.copyTo(target, ExtendedCopyOption.INTERRUPTIBLE); + throw new RuntimeException("Copy completed (this is not expected)"); + } catch (IOException e) { + boolean interrupted = Thread.interrupted(); + if (!interrupted) + throw new RuntimeException("Interrupt status was not set"); + System.out.println("Copy failed (this is expected)"); + } + + // copy source to target via task in thread pool, interrupting it after + // a delay using cancel(true) + Future<Void> result = pool.submit(new Callable<Void>() { + public Void call() throws IOException { + System.out.println("Copying file..."); + source.copyTo(target, ExtendedCopyOption.INTERRUPTIBLE, + StandardCopyOption.REPLACE_EXISTING); + return null; + } + }); + Thread.sleep(DELAY_IN_MS); + boolean cancelled = result.cancel(true); + if (!cancelled) + result.get(); + System.out.println("Copy cancelled."); + } finally { + pool.shutdown(); + pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); + } + } +} diff --git a/jdk/test/java/nio/file/Path/Links.java b/jdk/test/java/nio/file/Path/Links.java new file mode 100644 index 00000000000..3b0d6daeaa8 --- /dev/null +++ b/jdk/test/java/nio/file/Path/Links.java @@ -0,0 +1,147 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.Path createSymbolicLink, + * readSymbolicLink, and createLink methods + * @library .. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.*; +import java.util.*; + +public class Links { + + static final boolean isWindows = + System.getProperty("os.name").startsWith("Windows"); + + static void assertTrue(boolean okay) { + if (!okay) + throw new RuntimeException("Assertion failed"); + } + + /** + * Exercise createSymbolicLink and readLink methods + */ + static void testSymLinks(Path dir) throws IOException { + Path link = dir.resolve("link"); + + // Check if sym links are supported + try { + link.createSymbolicLink(Paths.get("foo")); + link.delete(); + } catch (UnsupportedOperationException x) { + // sym links not supported + return; + } catch (IOException x) { + // probably insufficient privileges to create sym links (Windows) + return; + } + + // Test links to various targets + String[] windowsTargets = + { "foo", "C:\\foo", "\\foo", "\\\\server\\share\\foo" }; + String[] otherTargets = { "relative", "/absolute" }; + + String[] targets = (isWindows) ? windowsTargets : otherTargets; + for (String s: targets) { + Path target = Paths.get(s); + link.createSymbolicLink(target); + try { + assertTrue(link.readSymbolicLink().equals(target)); + } finally { + link.delete(); + } + } + } + + /** + * Exercise createLink method + */ + static void testHardLinks(Path dir) throws IOException { + Path foo = dir.resolve("foo").createFile(); + try { + Path bar; + try { + bar = dir.resolve("bar").createLink(foo); + } catch (UnsupportedOperationException x) { + return; + } catch (IOException x) { + // probably insufficient privileges (Windows) + return; + } + try { + Object key1 = Attributes + .readBasicFileAttributes(foo).fileKey(); + Object key2 = Attributes + .readBasicFileAttributes(bar).fileKey(); + assertTrue((key1 == null) || (key1.equals(key2))); + +// Testing of linkCount disabled until linkCount method removed frmo +// BasicFileAttributes +/* + assertTrue(Attributes + .readBasicFileAttributes(foo).linkCount() >= 2); + assertTrue(Attributes + .readBasicFileAttributes(bar).linkCount() >= 2); +*/ + + } finally { + bar.delete(); + } + + + } finally { + foo.delete(); + } + } + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + testSymLinks(dir); + testHardLinks(dir); + + // repeat tests on Windows with long path + if (isWindows) { + Path dirWithLongPath = null; + try { + dirWithLongPath = TestUtil.createDirectoryWithLongPath(dir); + } catch (IOException x) { + System.out.println("Unable to create long path: " + x); + } + if (dirWithLongPath != null) { + System.out.println(""); + System.out.println("** REPEAT TESTS WITH LONG PATH **"); + testSymLinks(dirWithLongPath); + testHardLinks(dirWithLongPath); + } + } + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/Path/Misc.java b/jdk/test/java/nio/file/Path/Misc.java new file mode 100644 index 00000000000..ba6640f7f34 --- /dev/null +++ b/jdk/test/java/nio/file/Path/Misc.java @@ -0,0 +1,389 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.Path for miscellenous methods not + * covered by other tests + * @library .. + */ + +import java.nio.file.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; +import java.io.*; +import java.util.*; + +public class Misc { + static final boolean isWindows = + System.getProperty("os.name").startsWith("Windows"); + static boolean supportsLinks; + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + supportsLinks = TestUtil.supportsLinks(dir); + + // equals and hashCode methods + equalsAndHashCode(); + + // checkAccess method + checkAccessTests(dir); + + // getFileAttributeView methods + getFileAttributeViewTests(dir); + + // toRealPath method + toRealPathTests(dir); + + // isSameFile method + isSameFileTests(dir); + + // isHidden method + isHiddenTests(dir); + + } finally { + TestUtil.removeAll(dir); + } + } + + /** + * Exercise equals and hashCode methods + */ + static void equalsAndHashCode() { + + Path thisFile = Paths.get("this"); + Path thatFile = Paths.get("that"); + + assertTrue(thisFile.equals(thisFile)); + assertTrue(!thisFile.equals(thatFile)); + + assertTrue(!thisFile.equals(null)); + assertTrue(!thisFile.equals(new Object())); + + Path likeThis = Paths.get("This"); + if (isWindows) { + // case insensitive + assertTrue(thisFile.equals(likeThis)); + assertTrue(thisFile.hashCode() == likeThis.hashCode()); + } else { + // case senstive + assertTrue(!thisFile.equals(likeThis)); + } + } + + /** + * Exercise checkAccess method + */ + static void checkAccessTests(Path dir) throws IOException { + final Path file = dir.resolve("foo").createFile(); + + /** + * Test: This directory should readable and writable + */ + dir.checkAccess(); + dir.checkAccess(AccessMode.READ); + dir.checkAccess(AccessMode.WRITE); + dir.checkAccess(AccessMode.READ, AccessMode.WRITE); + + /** + * Test: File does not exist + */ + Path doesNotExist = dir.resolve("thisDoesNotExists"); + try { + doesNotExist.checkAccess(); + throw new RuntimeException("NoSuchFileException expected"); + } catch (NoSuchFileException x) { + } + try { + doesNotExist.checkAccess(AccessMode.READ); + throw new RuntimeException("NoSuchFileException expected"); + } catch (NoSuchFileException x) { + } + try { + doesNotExist.checkAccess(AccessMode.WRITE); + throw new RuntimeException("NoSuchFileException expected"); + } catch (NoSuchFileException x) { + } + try { + doesNotExist.checkAccess(AccessMode.EXECUTE); + throw new RuntimeException("NoSuchFileException expected"); + } catch (NoSuchFileException x) { + } + + /** + * Test: Edit ACL to deny WRITE and EXECUTE + */ + AclFileAttributeView view = file + .getFileAttributeView(AclFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView("acl")) + { + UserPrincipal owner = view.getOwner(); + List<AclEntry> acl = view.getAcl(); + + // Insert entry to deny WRITE and EXECUTE + AclEntry entry = AclEntry.newBuilder() + .setType(AclEntryType.DENY) + .setPrincipal(owner) + .setPermissions(AclEntryPermission.WRITE_DATA, + AclEntryPermission.EXECUTE) + .build(); + acl.add(0, entry); + view.setAcl(acl); + + try { + file.checkAccess(AccessMode.WRITE); + throw new RuntimeException("AccessDeniedException expected"); + } catch (AccessDeniedException x) { + } + + try { + file.checkAccess(AccessMode.EXECUTE); + throw new RuntimeException("AccessDeniedException expected"); + } catch (AccessDeniedException x) { + } + + + // Restore ACL + acl.remove(0); + view.setAcl(acl); + } + + /** + * Test: Windows DOS read-only attribute + */ + if (isWindows) { + DosFileAttributeView dview = + file.getFileAttributeView(DosFileAttributeView.class); + dview.setReadOnly(true); + try { + file.checkAccess(AccessMode.WRITE); + throw new RuntimeException("AccessDeniedException expected"); + } catch (AccessDeniedException x) { + } + dview.setReadOnly(false); + + // Read-only attribute does not make direcory read-only + dview = dir.getFileAttributeView(DosFileAttributeView.class); + boolean save = dview.readAttributes().isReadOnly(); + dview.setReadOnly(true); + dir.checkAccess(AccessMode.WRITE); + dview.setReadOnly(save); + } + + /** + * Test: null + */ + try { + file.checkAccess((AccessMode)null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + + // clean-up + file.delete(); + } + + /** + * Exercise getFileAttributeFile methods + */ + static void getFileAttributeViewTests(Path dir) { + assertTrue(dir.getFileAttributeView(BasicFileAttributeView.class) + instanceof BasicFileAttributeView); + assertTrue(dir.getFileAttributeView(BasicFileAttributeView.class, NOFOLLOW_LINKS) + instanceof BasicFileAttributeView); + assertTrue(dir.getFileAttributeView("basic") + instanceof BasicFileAttributeView); + assertTrue(dir.getFileAttributeView("basic", NOFOLLOW_LINKS) + instanceof BasicFileAttributeView); + assertTrue(dir.getFileAttributeView(BogusFileAttributeView.class) == null); + assertTrue(dir.getFileAttributeView("bogus") == null); + try { + dir.getFileAttributeView((Class<FileAttributeView>)null); + } catch (NullPointerException ignore) { } + try { + dir.getFileAttributeView(BasicFileAttributeView.class, (LinkOption[])null); + } catch (NullPointerException ignore) { } + try { + dir.getFileAttributeView(BasicFileAttributeView.class, (LinkOption)null); + } catch (NullPointerException ignore) { } + try { + dir.getFileAttributeView((String)null); + } catch (NullPointerException ignore) { } + try { + dir.getFileAttributeView("basic", (LinkOption[])null); + } catch (NullPointerException ignore) { } + try { + dir.getFileAttributeView("basic", (LinkOption)null); + } catch (NullPointerException ignore) { } + + } + interface BogusFileAttributeView extends FileAttributeView { } + + /** + * Exercise toRealPath method + */ + static void toRealPathTests(Path dir) throws IOException { + final Path file = dir.resolve("foo").createFile(); + final Path link = dir.resolve("link"); + + /** + * Test: toRealPath(true) will access same file as toRealPath(false) + */ + assertTrue(file.toRealPath(true).isSameFile(file.toRealPath(false))); + + /** + * Test: toRealPath(true) should resolve links + */ + if (supportsLinks) { + link.createSymbolicLink(file.toAbsolutePath()); + assertTrue(link.toRealPath(true).equals(file.toRealPath(true))); + link.delete(); + } + + + /** + * Test: toRealPath(false) should not resolve links + */ + if (supportsLinks) { + link.createSymbolicLink(file.toAbsolutePath()); + assertTrue(link.toRealPath(false).getName().equals(link.getName())); + link.delete(); + } + + /** + * Test: toRealPath should eliminate "." + */ + assertTrue(dir.resolve(".").toRealPath(true).equals(dir.toRealPath(true))); + assertTrue(dir.resolve(".").toRealPath(false).equals(dir.toRealPath(false))); + + /** + * Test: toRealPath should eliminate ".." when it doesn't follow a + * symbolic link + */ + Path subdir = dir.resolve("subdir").createDirectory(); + assertTrue(subdir.resolve("..").toRealPath(true).equals(dir.toRealPath(true))); + assertTrue(subdir.resolve("..").toRealPath(false).equals(dir.toRealPath(false))); + subdir.delete(); + + // clean-up + file.delete(); + } + + /** + * Exercise isSameFile method + */ + static void isSameFileTests(Path dir) throws IOException { + Path thisFile = dir.resolve("thisFile"); + Path thatFile = dir.resolve("thatFile"); + + /** + * Test: isSameFile for self and null + */ + assertTrue(thisFile.isSameFile(thisFile)); + assertTrue(!thisFile.isSameFile(null)); + + /** + * Test: Neither files exist + */ + try { + thisFile.isSameFile(thatFile); + throw new RuntimeException("IOException not thrown"); + } catch (IOException x) { + } + try { + thatFile.isSameFile(thisFile); + throw new RuntimeException("IOException not thrown"); + } catch (IOException x) { + } + + thisFile.createFile(); + try { + /** + * Test: One file exists + */ + try { + thisFile.isSameFile(thatFile); + throw new RuntimeException("IOException not thrown"); + } catch (IOException x) { + } + try { + thatFile.isSameFile(thisFile); + throw new RuntimeException("IOException not thrown"); + } catch (IOException x) { + } + + thatFile.createFile(); + + /** + * Test: Both file exists + */ + try { + assertTrue(!thisFile.isSameFile(thatFile)); + assertTrue(!thatFile.isSameFile(thisFile)); + } finally { + TestUtil.deleteUnchecked(thatFile); + } + + /** + * Test: Symbolic links + */ + if (supportsLinks) { + thatFile.createSymbolicLink(thisFile); + try { + assertTrue(thisFile.isSameFile(thatFile)); + assertTrue(thatFile.isSameFile(thisFile)); + } finally { + TestUtil.deleteUnchecked(thatFile); + } + } + } finally { + thisFile.delete(false); + } + } + + /** + * Exercise isHidden method + */ + static void isHiddenTests(Path dir) throws IOException { + assertTrue(!dir.isHidden()); + + Path file = dir.resolve(".foo"); + if (isWindows) { + file.createFile(); + try { + Attributes.setAttribute(file, "dos:hidden", true); + assertTrue(file.isHidden()); + } finally { + file.delete(); + } + } else { + assertTrue(file.isHidden()); + } + } + + static void assertTrue(boolean okay) { + if (!okay) + throw new RuntimeException("Assertion Failed"); + } +} diff --git a/jdk/test/java/nio/file/Path/PathOps.java b/jdk/test/java/nio/file/Path/PathOps.java new file mode 100644 index 00000000000..231123c7d9a --- /dev/null +++ b/jdk/test/java/nio/file/Path/PathOps.java @@ -0,0 +1,752 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.Path path operations + */ + +import java.nio.file.*; + +public class PathOps { + + static final java.io.PrintStream out = System.out; + + private String input; + private Path path; + private Exception exc; + + private PathOps(String s) { + out.println(); + input = s; + try { + path = FileSystems.getDefault().getPath(s); + out.format("%s -> %s", s, path); + } catch (Exception x) { + exc = x; + out.format("%s -> %s", s, x); + } + out.println(); + } + + Path path() { + return path; + } + + void fail() { + throw new RuntimeException("PathOps failed"); + } + + void checkPath() { + if (path == null) { + throw new InternalError("path is null"); + } + } + + void check(Object result, String expected) { + out.format("\tExpected: %s\n", expected); + out.format("\tActual: %s\n", result); + if (result == null) { + if (expected == null) return; + } else { + // compare string representations + if (expected != null && result.toString().equals(expected.toString())) + return; + } + fail(); + } + + void check(Object result, boolean expected) { + check(result, Boolean.toString(expected)); + } + + PathOps root(String expected) { + out.println("check root"); + checkPath(); + check(path.getRoot(), expected); + return this; + } + + PathOps parent(String expected) { + out.println("check parent"); + checkPath(); + check(path.getParent(), expected); + return this; + } + + PathOps name(String expected) { + out.println("check name"); + checkPath(); + check(path.getName(), expected); + return this; + } + + PathOps element(int index, String expected) { + out.format("check element %d\n", index); + checkPath(); + check(path.getName(index), expected); + return this; + } + + PathOps subpath(int startIndex, int endIndex, String expected) { + out.format("test subpath(%d,%d)\n", startIndex, endIndex); + checkPath(); + check(path.subpath(startIndex, endIndex), expected); + return this; + } + + PathOps starts(String prefix) { + out.format("test startsWith with %s\n", prefix); + checkPath(); + Path s = FileSystems.getDefault().getPath(prefix); + check(path.startsWith(s), true); + return this; + } + + PathOps notStarts(String prefix) { + out.format("test not startsWith with %s\n", prefix); + checkPath(); + Path s = FileSystems.getDefault().getPath(prefix); + check(path.startsWith(s), false); + return this; + } + + PathOps ends(String suffix) { + out.format("test endsWith %s\n", suffix); + checkPath(); + Path s = FileSystems.getDefault().getPath(suffix); + check(path.endsWith(s), true); + return this; + } + + PathOps notEnds(String suffix) { + out.format("test not endsWith %s\n", suffix); + checkPath(); + Path s = FileSystems.getDefault().getPath(suffix); + check(path.endsWith(s), false); + return this; + } + + PathOps absolute() { + out.println("check path is absolute"); + checkPath(); + check(path.isAbsolute(), true); + return this; + } + + PathOps notAbsolute() { + out.println("check path is not absolute"); + checkPath(); + check(path.isAbsolute(), false); + return this; + } + + PathOps resolve(String other, String expected) { + out.format("test resolve %s\n", other); + checkPath(); + check(path.resolve(other), expected); + return this; + } + + PathOps relativize(String other, String expected) { + out.format("test relativize %s\n", other); + checkPath(); + Path that = FileSystems.getDefault().getPath(other); + check(path.relativize(that), expected); + return this; + } + + PathOps normalize(String expected) { + out.println("check normalized path"); + checkPath(); + check(path.normalize(), expected); + return this; + } + + PathOps string(String expected) { + out.println("check string representation"); + checkPath(); + check(path, expected); + return this; + } + + PathOps invalid() { + if (!(exc instanceof InvalidPathException)) { + out.println("InvalidPathException not thrown as expected"); + fail(); + } + return this; + } + + static PathOps test(String s) { + return new PathOps(s); + } + + // -- PathOpss -- + + static void header(String s) { + out.println(); + out.println(); + out.println("-- " + s + " --"); + } + + static void doWindowsTests() { + header("Windows specific tests"); + + // all components present + test("C:\\a\\b\\c") + .root("C:\\") + .parent("C:\\a\\b") + .name("c"); + test("C:a\\b\\c") + .root("C:") + .parent("C:a\\b") + .name("c"); + test("\\\\server\\share\\a") + .root("\\\\server\\share\\") + .parent("\\\\server\\share\\") + .name("a"); + + // root component only + test("C:\\") + .root("C:\\") + .parent(null) + .name(null); + test("C:") + .root("C:") + .parent(null) + .name(null); + test("\\\\server\\share\\") + .root("\\\\server\\share\\") + .parent(null) + .name(null); + + // no root component + test("a\\b") + .root(null) + .parent("a") + .name("b"); + + // name component only + test("foo") + .root(null) + .parent(null) + .name("foo"); + + // startsWith + test("C:\\") + .starts("C:\\") + .starts("c:\\") + .notStarts("C") + .notStarts("C:"); + test("C:") + .starts("C:") + .starts("c:") + .notStarts("C"); + test("\\") + .starts("\\"); + test("C:\\foo\\bar") + .starts("C:\\") + .starts("C:\\foo") + .starts("C:\\FOO") + .starts("C:\\foo\\bar") + .starts("C:\\Foo\\Bar") + .notStarts("C:") + .notStarts("C") + .notStarts("C:foo"); + test("\\foo\\bar") + .starts("\\") + .starts("\\foo") + .starts("\\foO") + .starts("\\foo\\bar") + .starts("\\fOo\\BaR") + .notStarts("foo") + .notStarts("foo\\bar"); + test("foo\\bar") + .starts("foo") + .starts("foo\\bar") + .notStarts("\\"); + test("\\\\server\\share") + .starts("\\\\server\\share") + .starts("\\\\server\\share\\") + .notStarts("\\"); + + // endsWith + test("C:\\") + .ends("C:\\") + .ends("c:\\") + .notEnds("\\"); + test("C:") + .ends("C:") + .ends("c:"); + test("\\") + .ends("\\"); + test("C:\\foo\\bar") + .ends("bar") + .ends("BAR") + .ends("foo\\bar") + .ends("Foo\\Bar") + .ends("C:\\foo\\bar") + .ends("c:\\foO\\baR") + .notEnds("r") + .notEnds("\\foo\\bar"); + test("\\foo\\bar") + .ends("bar") + .ends("BaR") + .ends("foo\\bar") + .ends("foO\\baR") + .ends("\\foo\\bar") + .ends("\\Foo\\Bar") + .notEnds("oo\\bar"); + test("foo\\bar") + .ends("bar") + .ends("BAR") + .ends("foo\\bar") + .ends("Foo\\Bar") + .notEnds("ar"); + test("\\\\server\\share") + .ends("\\\\server\\share") + .ends("\\\\server\\share\\") + .notEnds("shared") + .notEnds("\\"); + + // elements + test("C:\\a\\b\\c") + .element(0, "a") + .element(1, "b") + .element(2, "c"); + test("foo.bar\\gus.alice") + .element(0, "foo.bar") + .element(1, "gus.alice"); + + // subpath + test("C:\\foo") + .subpath(0, 1, "foo"); + test("C:foo") + .subpath(0, 1, "foo"); + test("foo") + .subpath(0, 1, "foo"); + test("C:\\foo\\bar\\gus") + .subpath(0, 1, "foo") + .subpath(0, 2, "foo\\bar") + .subpath(0, 3, "foo\\bar\\gus") + .subpath(1, 2, "bar") + .subpath(1, 3, "bar\\gus") + .subpath(2, 3, "gus"); + test("\\\\server\\share\\foo") + .subpath(0, 1, "foo"); + + // isAbsolute + test("foo").notAbsolute(); + test("C:").notAbsolute(); + test("C:\\").absolute(); + test("C:\\abc").absolute(); + test("\\\\server\\share\\").absolute(); + + // resolve + test("C:\\") + .resolve("foo", "C:\\foo") + .resolve("D:\\bar", "D:\\bar") + .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar") + .resolve("C:foo", "C:\\foo") + .resolve("D:foo", "D:foo"); + test("\\") + .resolve("foo", "\\foo") + .resolve("D:bar", "D:bar") + .resolve("C:\\bar", "C:\\bar") + .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar") + .resolve("\\foo", "\\foo"); + test("\\foo") + .resolve("bar", "\\foo\\bar") + .resolve("D:bar", "D:bar") + .resolve("C:\\bar", "C:\\bar") + .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar") + .resolve("\\bar", "\\bar"); + test("foo") + .resolve("bar", "foo\\bar") + .resolve("D:\\bar", "D:\\bar") + .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar") + .resolve("C:bar", "C:bar") + .resolve("D:foo", "D:foo"); + test("C:") + .resolve("foo", "C:foo"); + test("\\\\server\\share\\foo") + .resolve("bar", "\\\\server\\share\\foo\\bar") + .resolve("\\bar", "\\\\server\\share\\bar") + .resolve("D:\\bar", "D:\\bar") + .resolve("\\\\other\\share\\bar", "\\\\other\\share\\bar") + .resolve("D:bar", "D:bar"); + + // relativize + test("foo\\bar") + .relativize("foo\\bar", null) + .relativize("foo", ".."); + test("C:\\a\\b\\c") + .relativize("C:\\a", "..\\.."); + test("\\\\server\\share\\foo") + .relativize("\\\\server\\share\\bar", "..\\bar"); + + // normalize + test("C:\\") + .normalize("C:\\"); + test("C:\\.") + .normalize("C:\\"); + test("C:\\..") + .normalize("C:\\"); + test("\\\\server\\share") + .normalize("\\\\server\\share\\"); + test("\\\\server\\share\\.") + .normalize("\\\\server\\share\\"); + test("\\\\server\\share\\..") + .normalize("\\\\server\\share\\"); + test("C:") + .normalize("C:"); + test("C:.") + .normalize("C:"); + test("C:..") + .normalize("C:.."); + test("\\") + .normalize("\\"); + test("\\.") + .normalize("\\"); + test("\\..") + .normalize("\\"); + test("foo") + .normalize("foo"); + test("foo\\.") + .normalize("foo"); + test("foo\\..") + .normalize(null); + test("C:\\foo") + .normalize("C:\\foo"); + test("C:\\foo\\.") + .normalize("C:\\foo"); + test("C:\\.\\foo") + .normalize("C:\\foo"); + test("C:\\foo\\..") + .normalize("C:\\"); + test("C:\\..\\foo") + .normalize("C:\\foo"); + test("\\\\server\\share\\foo") + .normalize("\\\\server\\share\\foo"); + test("\\\\server\\share\\foo\\.") + .normalize("\\\\server\\share\\foo"); + test("\\\\server\\share\\.\\foo") + .normalize("\\\\server\\share\\foo"); + test("\\\\server\\share\\foo\\..") + .normalize("\\\\server\\share\\"); + test("\\\\server\\share\\..\\foo") + .normalize("\\\\server\\share\\foo"); + test("C:foo") + .normalize("C:foo"); + test("C:foo\\.") + .normalize("C:foo"); + test("C:.\\foo") + .normalize("C:foo"); + test("C:foo\\..") + .normalize("C:"); + test("C:..\\foo") + .normalize("C:..\\foo"); + test("\\foo") + .normalize("\\foo"); + test("\\foo\\.") + .normalize("\\foo"); + test("\\.\\foo") + .normalize("\\foo"); + test("\\foo\\..") + .normalize("\\"); + test("\\..\\foo") + .normalize("\\foo"); + test(".") + .normalize(null); + test("..") + .normalize(".."); + test("\\..\\..") + .normalize("\\"); + test("..\\..\\foo") + .normalize("..\\..\\foo"); + test("foo\\bar\\..") + .normalize("foo"); + test("foo\\bar\\.\\..") + .normalize("foo"); + test("foo\\bar\\gus\\..\\..") + .normalize("foo"); + test(".\\foo\\.\\bar\\.\\gus\\..\\.\\..") + .normalize("foo"); + + // UNC corner cases + test("\\\\server\\share\\") + .root("\\\\server\\share\\") + .parent(null) + .name(null); + test("\\\\server") + .invalid(); + test("\\\\server\\") + .invalid(); + test("\\\\server\\share") + .root("\\\\server\\share\\") + .parent(null) + .name(null); + + // invalid + test(":\\foo") + .invalid(); + test("C::") + .invalid(); + test("C:\\?") // invalid character + .invalid(); + test("C:\\*") // invalid character + .invalid(); + test("C:\\abc\u0001\\foo") + .invalid(); + test("C:\\\u0019\\foo") + .invalid(); + test("\\\\server\u0019\\share") + .invalid(); + test("\\\\server\\share\u0019") + .invalid(); + test("foo\u0000\bar") + .invalid(); + test("C:\\foo ") // trailing space + .invalid(); + test("C:\\foo \\bar") + .invalid(); + //test("C:\\foo.") // trailing dot + //.invalid(); + //test("C:\\foo...\\bar") + //.invalid(); + + // normalization at construction time (remove redundant and replace slashes) + test("C:/a/b/c") + .string("C:\\a\\b\\c") + .root("C:\\") + .parent("C:\\a\\b"); + test("C://a//b//c") + .string("C:\\a\\b\\c") + .root("C:\\") + .parent("C:\\a\\b"); + + // hashCode + header("hashCode"); + int h1 = test("C:\\foo").path().hashCode(); + int h2 = test("c:\\FOO").path().hashCode(); + if (h1 != h2) + throw new RuntimeException("PathOps failed"); + } + + static void doUnixTests() { + header("Unix specific tests"); + + // all components + test("/a/b/c") + .root("/") + .parent("/a/b") + .name("c"); + + // root component only + test("/") + .root("/") + .parent(null) + .name(null); + + // no root component + test("a/b") + .root(null) + .parent("a") + .name("b"); + + // name component only + test("foo") + .root(null) + .parent(null) + .name("foo"); + + // startsWith + test("/") + .starts("/") + .notStarts("/foo"); + test("/foo") + .starts("/") + .starts("/foo") + .notStarts("/f"); + test("/foo/bar") + .starts("/") + .starts("/foo") + .starts("/foo/bar") + .notStarts("/f") + .notStarts("foo") + .notStarts("foo/bar"); + test("foo") + .starts("foo") + .notStarts("f"); + test("foo/bar") + .starts("foo") + .starts("foo/bar") + .notStarts("f") + .notStarts("/foo") + .notStarts("/foo/bar"); + + // endsWith + test("/") + .ends("/") + .notEnds("foo") + .notEnds("/foo"); + test("/foo") + .ends("foo") + .ends("/foo") + .notEnds("/"); + test("/foo/bar") + .ends("bar") + .ends("foo/bar") + .ends("/foo/bar") + .notEnds("/bar"); + test("foo") + .ends("foo"); + test("foo/bar") + .ends("bar") + .ends("foo/bar"); + + // elements + test("a/b/c") + .element(0,"a") + .element(1,"b") + .element(2,"c"); + + // isAbsolute + test("/") + .absolute(); + test("/tmp") + .absolute(); + test("tmp") + .notAbsolute(); + + // resolve + test("/tmp") + .resolve("foo", "/tmp/foo") + .resolve("/foo", "/foo"); + test("tmp") + .resolve("foo", "tmp/foo") + .resolve("/foo", "/foo"); + + // relativize + test("/a/b/c") + .relativize("/a/b/c", null) + .relativize("/a/b/c/d/e", "d/e") + .relativize("/a/x", "../../x"); + + // normalize + test("/") + .normalize("/"); + test("foo") + .normalize("foo"); + test("/foo") + .normalize("/foo"); + test(".") + .normalize(null); + test("..") + .normalize(".."); + test("/..") + .normalize("/"); + test("/../..") + .normalize("/"); + test("foo/.") + .normalize("foo"); + test("./foo") + .normalize("foo"); + test("foo/..") + .normalize(null); + test("../foo") + .normalize("../foo"); + test("../../foo") + .normalize("../../foo"); + test("foo/bar/..") + .normalize("foo"); + test("foo/bar/gus/../..") + .normalize("foo"); + test("/foo/bar/gus/../..") + .normalize("/foo"); + + // invalid + test("foo\u0000\bar") + .invalid(); + + // normalization + test("//foo//bar") + .string("/foo/bar") + .root("/") + .parent("/foo") + .name("bar"); + } + + static void npes() { + header("NullPointerException"); + + Path path = FileSystems.getDefault().getPath("foo"); + + try { + path.resolve((String)null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + try { + path.relativize(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + try { + path.compareTo(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + try { + path.startsWith(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + try { + path.endsWith(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + } + + public static void main(String[] args) { + // all platforms + npes(); + + // operating system specific + String osname = System.getProperty("os.name"); + if (osname.startsWith("Windows")) { + doWindowsTests(); + } + if (osname.equals("SunOS") || osname.equals("Linux")) { + doUnixTests(); + } + + } +} diff --git a/jdk/test/java/nio/file/Path/SBC.java b/jdk/test/java/nio/file/Path/SBC.java new file mode 100644 index 00000000000..724c8706a26 --- /dev/null +++ b/jdk/test/java/nio/file/Path/SBC.java @@ -0,0 +1,468 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.Path.newByteChannel + * @library .. + */ + +import java.nio.ByteBuffer; +import java.nio.file.*; +import static java.nio.file.StandardOpenOption.*; +import static com.sun.nio.file.ExtendedOpenOption.*; +import java.nio.file.attribute.FileAttribute; +import java.nio.channels.*; +import java.io.IOException; +import java.util.*; + +public class SBC { + + static boolean supportsLinks; + + public static void main(String[] args) throws Exception { + Path dir = TestUtil.createTemporaryDirectory(); + try { + supportsLinks = TestUtil.supportsLinks(dir); + + // open options + createTests(dir); + appendTests(dir); + truncateExistingTests(dir); + noFollowLinksTests(dir); + + // SeekableByteChannel methods + sizeTruncatePositionTests(dir); + + // platform specific + if (System.getProperty("os.name").startsWith("Windows")) + dosSharingOptionTests(dir); + + // misc. tests + badCombinations(dir); + unsupportedOptions(dir); + nullTests(dir); + + } finally { + TestUtil.removeAll(dir); + } + } + + // test CREATE and CREATE_NEW options + static void createTests(Path dir) throws Exception { + Path file = dir.resolve("foo"); + + // CREATE + try { + // create file (no existing file) + file.newByteChannel(CREATE, WRITE).close(); + if (file.notExists()) + throw new RuntimeException("File not created"); + + // create file (existing file) + file.newByteChannel(CREATE, WRITE).close(); + + // create file where existing file is a sym link + if (supportsLinks) { + Path link = dir.resolve("link").createSymbolicLink(file); + try { + // file already exists + link.newByteChannel(CREATE, WRITE).close(); + + // file does not exist + file.delete(); + link.newByteChannel(CREATE, WRITE).close(); + if (file.notExists()) + throw new RuntimeException("File not created"); + + } finally { + TestUtil.deleteUnchecked(link); + } + } + + } finally { + TestUtil.deleteUnchecked(file); + } + + // CREATE_NEW + try { + // create file + file.newByteChannel(CREATE_NEW, WRITE).close(); + if (file.notExists()) + throw new RuntimeException("File not created"); + + // create should fail + try { + SeekableByteChannel sbc = + file.newByteChannel(CREATE_NEW, WRITE); + sbc.close(); + throw new RuntimeException("FileAlreadyExistsException not thrown"); + } catch (FileAlreadyExistsException x) { } + + // create should fail + if (supportsLinks) { + Path link = dir.resolve("link"); + Path target = dir.resolve("thisDoesNotExist"); + link.createSymbolicLink(target); + try { + + try { + SeekableByteChannel sbc = + file.newByteChannel(CREATE_NEW, WRITE); + sbc.close(); + throw new RuntimeException("FileAlreadyExistsException not thrown"); + } catch (FileAlreadyExistsException x) { } + + } finally { + TestUtil.deleteUnchecked(link); + } + } + + + } finally { + TestUtil.deleteUnchecked(file); + } + + // CREATE_NEW + SPARSE + try { + SeekableByteChannel sbc = file + .newByteChannel(CREATE_NEW, WRITE, SPARSE); + try { + final long hole = 2L * 1024L * 1024L * 1024L; + sbc.position(hole); + write(sbc, "hello"); + long size = sbc.size(); + if (size != (hole + 5)) + throw new RuntimeException("Unexpected size"); + } finally { + sbc.close(); + } + } finally { + TestUtil.deleteUnchecked(file); + } + } + + // test APPEND option + static void appendTests(Path dir) throws Exception { + Path file = dir.resolve("foo"); + try { + // "hello there" should be written to file + SeekableByteChannel sbc = file + .newByteChannel(CREATE_NEW, WRITE, APPEND); + try { + write(sbc, "hello "); + sbc.position(0L); + write(sbc, "there"); + } finally { + sbc.close(); + } + + // check file + Scanner s = new Scanner(file); + try { + String line = s.nextLine(); + if (!line.equals("hello there")) + throw new RuntimeException("Unexpected file contents"); + } finally { + s.close(); + } + + // check that read is not allowed + sbc = file.newByteChannel(APPEND); + try { + sbc.read(ByteBuffer.allocate(100)); + } catch (NonReadableChannelException x) { + } finally { + sbc.close(); + } + } finally { + // clean-up + TestUtil.deleteUnchecked(file); + } + } + + // test TRUNCATE_EXISTING option + static void truncateExistingTests(Path dir) throws Exception { + Path file = dir.resolve("foo"); + try { + SeekableByteChannel sbc = + file.newByteChannel(CREATE_NEW, WRITE); + try { + write(sbc, "Have a nice day!"); + } finally { + sbc.close(); + } + + // re-open with truncate option + // write short message and check + sbc = file.newByteChannel(WRITE, TRUNCATE_EXISTING); + try { + write(sbc, "Hello there!"); + } finally { + sbc.close(); + } + Scanner s = new Scanner(file); + try { + String line = s.nextLine(); + if (!line.equals("Hello there!")) + throw new RuntimeException("Unexpected file contents"); + } finally { + s.close(); + } + + // re-open with create + truncate option + // check file is of size 0L + sbc = file.newByteChannel(WRITE, CREATE, TRUNCATE_EXISTING); + try { + long size = ((FileChannel)sbc).size(); + if (size != 0L) + throw new RuntimeException("File not truncated"); + } finally { + sbc.close(); + } + + } finally { + // clean-up + TestUtil.deleteUnchecked(file); + } + + } + + // test NOFOLLOW_LINKS option + static void noFollowLinksTests(Path dir) throws Exception { + if (!supportsLinks) + return; + Path file = dir.resolve("foo").createFile(); + try { + // ln -s foo link + Path link = dir.resolve("link").createSymbolicLink(file); + + // open with NOFOLLOW_LINKS option + try { + link.newByteChannel(READ, LinkOption.NOFOLLOW_LINKS); + throw new RuntimeException(); + } catch (IOException x) { + } finally { + TestUtil.deleteUnchecked(link); + } + + } finally { + // clean-up + TestUtil.deleteUnchecked(file); + } + } + + // test size/truncate/position methods + static void sizeTruncatePositionTests(Path dir) throws Exception { + Path file = dir.resolve("foo"); + try { + SeekableByteChannel sbc = file + .newByteChannel(CREATE_NEW, READ, WRITE); + try { + if (sbc.size() != 0L) + throw new RuntimeException("Unexpected size"); + + // check size + write(sbc, "hello"); + if (sbc.size() != 5L) + throw new RuntimeException("Unexpected size"); + + // truncate (size and position should change) + sbc.truncate(4L); + if (sbc.size() != 4L) + throw new RuntimeException("Unexpected size"); + if (sbc.position() != 4L) + throw new RuntimeException("Unexpected position"); + + // truncate (position should not change) + sbc.position(2L).truncate(3L); + if (sbc.size() != 3L) + throw new RuntimeException("Unexpected size"); + if (sbc.position() != 2L) + throw new RuntimeException("Unexpected position"); + } finally { + sbc.close(); + } + } finally { + TestUtil.deleteUnchecked(file); + } + } + + // Windows specific options for the use by applications that really want + // to use legacy DOS sharing options + static void dosSharingOptionTests(Path dir) throws Exception { + Path file = dir.resolve("foo").createFile(); + try { + SeekableByteChannel ch; + + // no sharing + ch = file.newByteChannel(READ, + NOSHARE_READ, NOSHARE_WRITE, NOSHARE_DELETE); + try { + try { + file.newByteChannel(READ); + throw new RuntimeException("Sharing violation expected"); + } catch (IOException ignore) { } + try { + file.newByteChannel(WRITE); + throw new RuntimeException("Sharing violation expected"); + } catch (IOException ignore) { } + try { + file.delete(); + throw new RuntimeException("Sharing violation expected"); + } catch (IOException ignore) { } + } finally { + ch.close(); + } + + // read allowed + ch = file.newByteChannel(READ, NOSHARE_WRITE, NOSHARE_DELETE); + try { + file.newByteChannel(READ).close(); + try { + file.newByteChannel(WRITE); + throw new RuntimeException("Sharing violation expected"); + } catch (IOException ignore) { } + try { + file.delete(); + throw new RuntimeException("Sharing violation expected"); + } catch (IOException ignore) { } + } finally { + ch.close(); + } + + // write allowed + ch = file.newByteChannel(READ, NOSHARE_READ, NOSHARE_DELETE); + try { + try { + file.newByteChannel(READ); + throw new RuntimeException("Sharing violation expected"); + } catch (IOException ignore) { } + file.newByteChannel(WRITE).close(); + try { + file.delete(); + throw new RuntimeException("Sharing violation expected"); + } catch (IOException ignore) { } + } finally { + ch.close(); + } + + // delete allowed + ch = file.newByteChannel(READ, NOSHARE_READ, NOSHARE_WRITE); + try { + try { + file.newByteChannel(READ); + throw new RuntimeException("Sharing violation expected"); + } catch (IOException ignore) { } + try { + file.newByteChannel(WRITE); + throw new RuntimeException("Sharing violation expected"); + } catch (IOException ignore) { } + file.delete(); + } finally { + ch.close(); + } + + } finally { + TestUtil.deleteUnchecked(file); + } + } + + // invalid combinations of options + static void badCombinations(Path dir) throws Exception { + Path file = dir.resolve("bad"); + + try { + file.newByteChannel(READ, APPEND); + throw new RuntimeException("IllegalArgumentException expected"); + } catch (IllegalArgumentException x) { } + + try { + file.newByteChannel(WRITE, APPEND, TRUNCATE_EXISTING); + throw new RuntimeException("IllegalArgumentException expected"); + } catch (IllegalArgumentException x) { } + } + + // unsupported operations + static void unsupportedOptions(Path dir) throws Exception { + Path file = dir.resolve("bad"); + + OpenOption badOption = new OpenOption() { }; + try { + file.newByteChannel(badOption); + throw new RuntimeException("UnsupportedOperationException expected"); + } catch (UnsupportedOperationException e) { } + try { + file.newByteChannel(READ, WRITE, badOption); + throw new RuntimeException("UnsupportedOperationException expected"); + } catch (UnsupportedOperationException e) { } + } + + // null handling + static void nullTests(Path dir) throws Exception { + Path file = dir.resolve("foo"); + + try { + file.newByteChannel((OpenOption[])null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + + try { + OpenOption[] opts = { READ, null }; + file.newByteChannel(opts); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + + try { + file.newByteChannel((Set<OpenOption>)null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + + try { + Set<OpenOption> opts = new HashSet<OpenOption>(); + opts.add(READ); + opts.add(null); + file.newByteChannel(opts); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + + try { + EnumSet<StandardOpenOption> opts = EnumSet.of(READ); + file.newByteChannel(opts, (FileAttribute[])null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + + try { + EnumSet<StandardOpenOption> opts = EnumSet.of(READ); + FileAttribute[] attrs = { null }; + file.newByteChannel(opts, attrs); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + } + + static void write(WritableByteChannel wbc, String msg) throws IOException { + ByteBuffer buf = ByteBuffer.wrap(msg.getBytes()); + while (buf.hasRemaining()) + wbc.write(buf); + } +} diff --git a/jdk/test/java/nio/file/Path/TemporaryFiles.java b/jdk/test/java/nio/file/Path/TemporaryFiles.java new file mode 100644 index 00000000000..6a9d28d9782 --- /dev/null +++ b/jdk/test/java/nio/file/Path/TemporaryFiles.java @@ -0,0 +1,76 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.*; +import static java.nio.file.StandardOpenOption.*; +import java.nio.file.attribute.*; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Set; + +public class TemporaryFiles { + + static void checkFile(Path file) throws IOException { + // check file is in temporary directory + Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir")); + if (!file.getParent().equals(tmpdir)) + throw new RuntimeException("Not in temporary directory"); + + // check that file can be opened for reading and writing + file.newByteChannel(READ).close(); + file.newByteChannel(WRITE).close(); + file.newByteChannel(READ,WRITE).close(); + + // check file permissions are 0600 or more secure + if (file.getFileStore().supportsFileAttributeView("posix")) { + Set<PosixFilePermission> perms = Attributes + .readPosixFileAttributes(file).permissions(); + perms.remove(PosixFilePermission.OWNER_READ); + perms.remove(PosixFilePermission.OWNER_WRITE); + if (!perms.isEmpty()) + throw new RuntimeException("Temporary file is not secure"); + } + } + + public static void main(String[] args) throws IOException { + Path file = File.createTempFile("blah", null, false).toPath(); + try { + checkFile(file); + } finally { + TestUtil.deleteUnchecked(file); + } + + // temporary file with deleteOnExit + file = File.createTempFile("blah", "tmp", true).toPath(); + checkFile(file); + // write path to temporary file to file so that calling script can + // check that it is deleted + OutputStream out = Paths.get(args[0]).newOutputStream(); + try { + out.write(file.toString().getBytes()); + } finally { + out.close(); + } + } +} diff --git a/jdk/test/java/nio/file/Path/UriImportExport.java b/jdk/test/java/nio/file/Path/UriImportExport.java new file mode 100644 index 00000000000..560423195ed --- /dev/null +++ b/jdk/test/java/nio/file/Path/UriImportExport.java @@ -0,0 +1,80 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.Path + */ + +import java.nio.file.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.io.PrintStream; + +public class UriImportExport { + + static final PrintStream log = System.out; + static int failures = 0; + + static void test(String fn, String expected) { + log.println(); + Path p = Paths.get(fn); + log.println(p); + URI u = p.toUri(); + log.println(" --> " + u); + if (expected != null && !(u.toString().equals(expected))) { + log.println("FAIL: Expected " + expected); + failures++; + return; + } + Path q = Paths.get(u); + log.println(" --> " + q); + if (!p.toAbsolutePath().equals(q)) { + log.println("FAIL: Expected " + p + ", got " + q); + failures++; + return; + } + } + + static void test(String fn) { + test(fn, null); + } + + public static void main(String[] args) throws Exception { + test("foo"); + test("/foo"); + test("/foo bar"); + + String osname = System.getProperty("os.name"); + if (osname.startsWith("Windows")) { + test("C:\\foo"); + test("C:foo"); + test("\\\\rialto.dublin.com\\share\\"); + test("\\\\fe80--203-baff-fe5a-749ds1.ipv6-literal.net\\share\\missing", + "file://[fe80::203:baff:fe5a:749d%1]/share/missing"); + } + + if (failures > 0) + throw new RuntimeException(failures + " test(s) failed"); + } +} diff --git a/jdk/test/java/nio/file/Path/delete_on_close.sh b/jdk/test/java/nio/file/Path/delete_on_close.sh new file mode 100644 index 00000000000..198e99d7201 --- /dev/null +++ b/jdk/test/java/nio/file/Path/delete_on_close.sh @@ -0,0 +1,61 @@ +# +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 4313887 +# @summary Unit test for DELETE_ON_CLOSE open option +# @library .. +# @build DeleteOnClose +# @run shell delete_on_close.sh + +# if TESTJAVA isn't set then we assume an interactive run. + +if [ -z "$TESTJAVA" ]; then + TESTSRC=. + TESTCLASSES=. + JAVA=java +else + JAVA="${TESTJAVA}/bin/java" +fi + +OS=`uname -s` +case "$OS" in + Windows_* ) + CLASSPATH="${TESTCLASSES};${TESTSRC}" + ;; + * ) + CLASSPATH=${TESTCLASSES}:${TESTSRC} + ;; +esac +export CLASSPATH + +TMPFILE="$$.tmp" +touch $TMPFILE +$JAVA DeleteOnClose $TMPFILE 2>&1 +if [ $? != 0 ]; then exit 1; fi +if [ -f $TMPFILE ]; then + echo "$TMPFILE was not deleted" + exit 1 +fi + +exit 0 diff --git a/jdk/test/java/nio/file/Path/temporary_files.sh b/jdk/test/java/nio/file/Path/temporary_files.sh new file mode 100644 index 00000000000..552dcfdab46 --- /dev/null +++ b/jdk/test/java/nio/file/Path/temporary_files.sh @@ -0,0 +1,65 @@ +# +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 4313887 +# @summary Unit test for File.createTempFile (to be be moved to test/java/io/File) +# @library .. +# @build TemporaryFiles +# @run shell temporary_files.sh + +# if TESTJAVA isn't set then we assume an interactive run. + +if [ -z "$TESTJAVA" ]; then + TESTSRC=. + TESTCLASSES=. + JAVA=java +else + JAVA="${TESTJAVA}/bin/java" +fi + +OS=`uname -s` +case "$OS" in + Windows_* ) + CLASSPATH="${TESTCLASSES};${TESTSRC}" + ;; + * ) + CLASSPATH=${TESTCLASSES}:${TESTSRC} + ;; +esac +export CLASSPATH + +TMPFILENAME="$$.tmp" +$JAVA TemporaryFiles $TMPFILENAME 2>&1 +if [ $? != 0 ]; then exit 1; fi +if [ ! -f $TMPFILENAME ]; then + echo "$TMPFILENAME not found" + exit 1 +fi +TMPFILE=`cat $TMPFILENAME` +if [ -f $TMPFILE ]; then + echo "$TMPFILE not deleted" + exit 1 +fi + +exit 0 diff --git a/jdk/test/java/nio/file/PathMatcher/Basic.java b/jdk/test/java/nio/file/PathMatcher/Basic.java new file mode 100644 index 00000000000..16efcf099d0 --- /dev/null +++ b/jdk/test/java/nio/file/PathMatcher/Basic.java @@ -0,0 +1,174 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.PathMatcher + */ + +import java.nio.file.*; +import java.util.regex.PatternSyntaxException; + +public class Basic { + static int failures; + + static void match(String name, String pattern, boolean expectedToMatch) { + System.out.format("%s -> %s", name, pattern); + Path file = Paths.get(name); + boolean matched = file.getFileSystem() + .getPathMatcher("glob:" + pattern).matches(file); + if (matched) + System.out.print(" (matched)"); + else + System.out.print(" (no match)"); + if (matched != expectedToMatch) { + System.out.println(" ==> UNEXPECTED RESULT!"); + failures++; + } else { + System.out.println(" OKAY"); + } + } + + static void assertMatch(String path, String pattern) { + match(path, pattern, true); + } + + static void assertNotMatch(String path, String pattern) { + match(path, pattern, false); + } + + static void assertBadPattern(String path, String pattern) { + System.out.format("Compile bad pattern %s\t", pattern); + try { + FileSystems.getDefault().getPathMatcher("glob:" + pattern); + System.out.println("Compiled ==> UNEXPECTED RESULT!"); + failures++; + } catch (PatternSyntaxException e) { + System.out.println("Failed to compile ==> OKAY"); + } + } + + public static void main(String[] args) { + // basic + assertMatch("foo.html", "foo.html"); + assertNotMatch("foo.html", "foo.htm"); + assertNotMatch("foo.html", "bar.html"); + + // match zero or more characters + assertMatch("foo.html", "f*"); + assertMatch("foo.html", "*.html"); + assertMatch("foo.html", "foo.html*"); + assertMatch("foo.html", "*foo.html"); + assertMatch("foo.html", "*foo.html*"); + assertNotMatch("foo.html", "*.htm"); + assertNotMatch("foo.html", "f.*"); + + // match one character + assertMatch("foo.html", "?oo.html"); + assertMatch("foo.html", "??o.html"); + assertMatch("foo.html", "???.html"); + assertMatch("foo.html", "???.htm?"); + assertNotMatch("foo.html", "foo.???"); + + // group of subpatterns + assertMatch("foo.html", "foo{.html,.class}"); + assertMatch("foo.html", "foo.{class,html}"); + assertNotMatch("foo.html", "foo{.htm,.class}"); + + // bracket expressions + assertMatch("foo.html", "[f]oo.html"); + assertMatch("foo.html", "[e-g]oo.html"); + assertMatch("foo.html", "[abcde-g]oo.html"); + assertMatch("foo.html", "[abcdefx-z]oo.html"); + assertMatch("foo.html", "[!a]oo.html"); + assertMatch("foo.html", "[!a-e]oo.html"); + assertMatch("foo-bar", "foo[-a-z]bar"); // match dash + assertMatch("foo.html", "foo[!-]html"); // match !dash + + // groups of subpattern with bracket expressions + assertMatch("foo.html", "[f]oo.{[h]tml,class}"); + assertMatch("foo.html", "foo.{[a-z]tml,class}"); + assertMatch("foo.html", "foo.{[!a-e]tml,.class}"); + + // assume special characters are allowed in file names + assertMatch("{foo}.html", "\\{foo*"); + assertMatch("{foo}.html", "*\\}.html"); + assertMatch("[foo].html", "\\[foo*"); + assertMatch("[foo].html", "*\\].html"); + + // errors + assertBadPattern("foo.html", "*[a--z]"); // bad range + assertBadPattern("foo.html", "*[a--]"); // bad range + assertBadPattern("foo.html", "*[a-z"); // missing ] + assertBadPattern("foo.html", "*{class,java"); // missing } + assertBadPattern("foo.html", "*.{class,{.java}}"); // nested group + assertBadPattern("foo.html", "*.html\\"); // nothing to escape + + // platform specific + if (System.getProperty("os.name").startsWith("Windows")) { + assertMatch("C:\\foo", "C:\\\\f*"); + assertMatch("C:\\FOO", "c:\\\\f*"); + assertMatch("C:\\foo\\bar\\gus", "C:\\\\**\\\\gus"); + assertMatch("C:\\foo\\bar\\gus", "C:\\\\**"); + } else { + assertMatch("/tmp/foo", "/tmp/*"); + assertMatch("/tmp/foo/bar", "/tmp/**"); + + // some special characters not allowed on Windows + assertMatch("myfile?", "myfile\\?"); + assertMatch("one\\two", "one\\\\two"); + assertMatch("one*two", "one\\*two"); + } + + + + // regex syntax + { + String pattern = ".*\\.html"; + System.out.format("Test regex pattern: %s", pattern); + Path file = Paths.get("foo.html"); + boolean matched = file.getFileSystem() + .getPathMatcher("regex:" + pattern).matches(file); + if (matched) { + System.out.println(" OKAY"); + } else { + System.out.println(" ==> UNEXPECTED RESULT!"); + failures++; + } + } + + // unknown syntax + try { + System.out.format("Test unknown syntax"); + FileSystems.getDefault().getPathMatcher("grep:foo"); + System.out.println(" ==> NOT EXPECTED TO COMPILE"); + failures++; + } catch (UnsupportedOperationException e) { + System.out.println(" OKAY"); + } + + if (failures > 0) + throw new RuntimeException(failures + + " sub-test(s) failed - see log for details"); + } +} diff --git a/jdk/test/java/nio/file/TestUtil.java b/jdk/test/java/nio/file/TestUtil.java new file mode 100644 index 00000000000..c19e28fbdc4 --- /dev/null +++ b/jdk/test/java/nio/file/TestUtil.java @@ -0,0 +1,125 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Random; +import java.io.IOException; + +public class TestUtil { + private TestUtil() { + } + + public static Path createTemporaryDirectory() throws IOException { + Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir")); + Random r = new Random(); + + Path dir; + do { + dir = tmpdir.resolve("name" + r.nextInt()); + } while (dir.exists()); + return dir.createDirectory(); + } + + static void removeAll(Path dir) { + Files.walkFileTree(dir, new FileVisitor<Path>() { + @Override + public FileVisitResult preVisitDirectory(Path dir) { + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) { + System.err.format("Error occured accessing directory %s\n", dir, exc); + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + try { + file.delete(false); + } catch (IOException x) { + System.err.format("Unable to delete %s: %s\n", file, x); + } + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) { + try { + dir.delete(false); + } catch (IOException x) { + System.err.format("Unable to delete %s: %s\n", dir, x); + } + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) { + System.err.format("Unable to visit %s: %s\n", file, exc); + return FileVisitResult.CONTINUE; + } + }); + } + + static void deleteUnchecked(FileRef file) { + try { + file.delete(); + } catch (IOException exc) { + System.err.format("Unable to delete %s: %s\n", file, exc); + } + } + + /** + * Creates a directory tree in the given directory so that the total + * size of the path is more than 2k in size. This is used for long + * path tests on Windows. + */ + static Path createDirectoryWithLongPath(Path dir) + throws IOException + { + StringBuilder sb = new StringBuilder(); + for (int i=0; i<240; i++) { + sb.append('A'); + } + String name = sb.toString(); + do { + dir = dir.resolve(name).resolve("."); + dir.createDirectory(); + } while (dir.toString().length() < 2048); + return dir; + } + + /** + * Returns true if symbolic links are supported + */ + static boolean supportsLinks(Path dir) { + Path link = dir.resolve("testlink"); + Path target = dir.resolve("testtarget"); + try { + link.createSymbolicLink(target); + target.delete(false); + return true; + } catch (UnsupportedOperationException x) { + return false; + } catch (IOException x) { + return false; + } + } +} diff --git a/jdk/test/java/nio/file/WatchService/Basic.java b/jdk/test/java/nio/file/WatchService/Basic.java new file mode 100644 index 00000000000..60c18d74b9b --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/Basic.java @@ -0,0 +1,493 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.WatchService + * @library .. + * @run main/timeout=120 Basic + */ + +import java.nio.file.*; +import static java.nio.file.StandardWatchEventKind.*; +import java.nio.file.attribute.*; +import java.io.*; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * Unit test for WatchService that exercises all methods in various scenarios. + */ + +public class Basic { + + static void createFile(Path file) throws IOException { + file.newOutputStream().close(); + } + + static void takeExpectedKey(WatchService watcher, WatchKey expected) { + System.out.println("take events..."); + WatchKey key; + try { + key = watcher.take(); + } catch (InterruptedException x) { + // not expected + throw new RuntimeException(x); + } + if (key != expected) + throw new RuntimeException("removed unexpected key"); + } + + static void checkExpectedEvent(Iterable<WatchEvent<?>> events, + WatchEvent.Kind<?> expectedKind, + Object expectedContext) + { + WatchEvent<?> event = events.iterator().next(); + System.out.format("got event: type=%s, count=%d, context=%s\n", + event.kind(), event.count(), event.context()); + if (event.kind() != expectedKind) + throw new RuntimeException("unexpected event"); + if (!expectedContext.equals(event.context())) + throw new RuntimeException("unexpected context"); + } + + /** + * Simple test of each of the standard events + */ + static void testEvents(Path dir) throws IOException { + System.out.println("-- Standard Events --"); + + FileSystem fs = FileSystems.getDefault(); + Path name = fs.getPath("foo"); + + WatchService watcher = fs.newWatchService(); + try { + // --- ENTRY_CREATE --- + + // register for event + System.out.format("register %s for ENTRY_CREATE\n", dir); + WatchKey myKey = dir.register(watcher, + new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); + + // create file + Path file = dir.resolve("foo"); + System.out.format("create %s\n", file); + createFile(file); + + // remove key and check that we got the ENTRY_CREATE event + takeExpectedKey(watcher, myKey); + checkExpectedEvent(myKey.pollEvents(), + StandardWatchEventKind.ENTRY_CREATE, name); + + System.out.println("reset key"); + if (!myKey.reset()) + throw new RuntimeException("key has been cancalled"); + + System.out.println("OKAY"); + + // --- ENTRY_DELETE --- + + System.out.format("register %s for ENTRY_DELETE\n", dir); + WatchKey deleteKey = dir.register(watcher, + new WatchEvent.Kind<?>[]{ ENTRY_DELETE }); + if (deleteKey != myKey) + throw new RuntimeException("register did not return existing key"); + + System.out.format("delete %s\n", file); + file.delete(false); + takeExpectedKey(watcher, myKey); + checkExpectedEvent(myKey.pollEvents(), + StandardWatchEventKind.ENTRY_DELETE, name); + + System.out.println("reset key"); + if (!myKey.reset()) + throw new RuntimeException("key has been cancalled"); + + System.out.println("OKAY"); + + // create the file for the next test + createFile(file); + + // --- ENTRY_MODIFY --- + + System.out.format("register %s for ENTRY_MODIFY\n", dir); + WatchKey newKey = dir.register(watcher, + new WatchEvent.Kind<?>[]{ ENTRY_MODIFY }); + if (newKey != myKey) + throw new RuntimeException("register did not return existing key"); + + System.out.format("update: %s\n", file); + OutputStream out = file.newOutputStream(EnumSet.of(StandardOpenOption.APPEND)); + try { + out.write("I am a small file".getBytes("UTF-8")); + } finally { + out.close(); + } + + // remove key and check that we got the ENTRY_MODIFY event + takeExpectedKey(watcher, myKey); + checkExpectedEvent(myKey.pollEvents(), + StandardWatchEventKind.ENTRY_MODIFY, name); + System.out.println("OKAY"); + + // done + file.delete(false); + + } finally { + watcher.close(); + } + } + + /** + * Check that a cancelled key will never be queued + */ + static void testCancel(Path dir) throws IOException { + System.out.println("-- Cancel --"); + + WatchService watcher = FileSystems.getDefault().newWatchService(); + try { + + System.out.format("register %s for events\n", dir); + WatchKey myKey = dir.register(watcher, + new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); + + System.out.println("cancel key"); + myKey.cancel(); + + // create a file in the directory + Path file = dir.resolve("mars"); + System.out.format("create: %s\n", file); + createFile(file); + + // poll for keys - there will be none + System.out.println("poll..."); + try { + WatchKey key = watcher.poll(3000, TimeUnit.MILLISECONDS); + if (key != null) + throw new RuntimeException("key should not be queued"); + } catch (InterruptedException x) { + throw new RuntimeException(x); + } + + // done + file.delete(false); + + System.out.println("OKAY"); + + } finally { + watcher.close(); + } + } + + /** + * Check that deleting a registered directory causes the key to be + * cancelled and queued. + */ + static void testAutomaticCancel(Path dir) throws IOException { + System.out.println("-- Automatic Cancel --"); + + Path subdir = dir.resolve("bar").createDirectory(); + + WatchService watcher = FileSystems.getDefault().newWatchService(); + try { + + System.out.format("register %s for events\n", subdir); + WatchKey myKey = subdir.register(watcher, + new WatchEvent.Kind<?>[]{ ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY }); + + System.out.format("delete: %s\n", subdir); + subdir.delete(false); + takeExpectedKey(watcher, myKey); + + System.out.println("reset key"); + if (myKey.reset()) + throw new RuntimeException("Key was not cancelled"); + if (myKey.isValid()) + throw new RuntimeException("Key is still valid"); + + System.out.println("OKAY"); + + } finally { + watcher.close(); + } + } + + /** + * Asynchronous close of watcher causes blocked threads to wakeup + */ + static void testWakeup(Path dir) throws IOException { + System.out.println("-- Wakeup Tests --"); + final WatchService watcher = FileSystems.getDefault().newWatchService(); + Runnable r = new Runnable() { + public void run() { + try { + Thread.sleep(5000); + System.out.println("close WatchService..."); + watcher.close(); + } catch (InterruptedException x) { + x.printStackTrace(); + } catch (IOException x) { + x.printStackTrace(); + } + } + }; + + // start thread to close watch service after delay + new Thread(r).start(); + + try { + System.out.println("take..."); + watcher.take(); + throw new RuntimeException("ClosedWatchServiceException not thrown"); + } catch (InterruptedException x) { + throw new RuntimeException(x); + } catch (ClosedWatchServiceException x) { + System.out.println("ClosedWatchServiceException thrown"); + } + + System.out.println("OKAY"); + } + + /** + * Simple test to check exceptions and other cases + */ + @SuppressWarnings("unchecked") + static void testExceptions(Path dir) throws IOException { + System.out.println("-- Exceptions and other simple tests --"); + + WatchService watcher = FileSystems.getDefault().newWatchService(); + try { + + // Poll tests + + WatchKey key; + System.out.println("poll..."); + key = watcher.poll(); + if (key != null) + throw new RuntimeException("no keys registered"); + + System.out.println("poll with timeout..."); + try { + long start = System.currentTimeMillis(); + key = watcher.poll(3000, TimeUnit.MILLISECONDS); + if (key != null) + throw new RuntimeException("no keys registered"); + long waited = System.currentTimeMillis() - start; + if (waited < 2900) + throw new RuntimeException("poll was too short"); + } catch (InterruptedException x) { + throw new RuntimeException(x); + } + + // IllegalArgumentException + System.out.println("IllegalArgumentException tests..."); + try { + dir.register(watcher, new WatchEvent.Kind<?>[]{ } ); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException x) { + } + try { + // OVERFLOW is ignored so this is equivalent to the empty set + dir.register(watcher, new WatchEvent.Kind<?>[]{ OVERFLOW }); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException x) { + } + + // UnsupportedOperationException + try { + dir.register(watcher, new WatchEvent.Kind<?>[]{ + new WatchEvent.Kind<Object>() { + @Override public String name() { return "custom"; } + @Override public Class<Object> type() { return Object.class; } + }}); + } catch (UnsupportedOperationException x) { + } + try { + dir.register(watcher, + new WatchEvent.Kind<?>[]{ ENTRY_CREATE }, + new WatchEvent.Modifier() { + @Override public String name() { return "custom"; } + }); + throw new RuntimeException("UnsupportedOperationException not thrown"); + } catch (UnsupportedOperationException x) { + } + + // NullPointerException + System.out.println("NullPointerException tests..."); + try { + dir.register(null, new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + dir.register(watcher, new WatchEvent.Kind<?>[]{ null }); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + dir.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_CREATE }, + (WatchEvent.Modifier)null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + } finally { + watcher.close(); + } + + // -- ClosedWatchServiceException -- + + System.out.println("ClosedWatchServiceException tests..."); + + try { + watcher.poll(); + throw new RuntimeException("ClosedWatchServiceException not thrown"); + } catch (ClosedWatchServiceException x) { + } + + // assume that poll throws exception immediately + long start = System.currentTimeMillis(); + try { + watcher.poll(10000, TimeUnit.MILLISECONDS); + throw new RuntimeException("ClosedWatchServiceException not thrown"); + } catch (InterruptedException x) { + throw new RuntimeException(x); + } catch (ClosedWatchServiceException x) { + long waited = System.currentTimeMillis() - start; + if (waited > 5000) + throw new RuntimeException("poll was too long"); + } + + try { + watcher.take(); + throw new RuntimeException("ClosedWatchServiceException not thrown"); + } catch (InterruptedException x) { + throw new RuntimeException(x); + } catch (ClosedWatchServiceException x) { + } + + try { + dir.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); + throw new RuntimeException("ClosedWatchServiceException not thrown"); + } catch (ClosedWatchServiceException x) { + } + + System.out.println("OKAY"); + } + + /** + * Test that directory can be registered with more than one watch service + * and that events don't interfere with each other + */ + static void testTwoWatchers(Path dir) throws IOException { + System.out.println("-- Two watchers test --"); + + FileSystem fs = FileSystems.getDefault(); + WatchService watcher1 = fs.newWatchService(); + WatchService watcher2 = fs.newWatchService(); + try { + Path name1 = fs.getPath("gus1"); + Path name2 = fs.getPath("gus2"); + + // create gus1 + Path file1 = dir.resolve(name1); + System.out.format("create %s\n", file1); + createFile(file1); + + // register with both watch services (different events) + System.out.println("register for different events"); + WatchKey key1 = dir.register(watcher1, + new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); + WatchKey key2 = dir.register(watcher2, + new WatchEvent.Kind<?>[]{ ENTRY_DELETE }); + + if (key1 == key2) + throw new RuntimeException("keys should be different"); + + // create gus2 + Path file2 = dir.resolve(name2); + System.out.format("create %s\n", file2); + createFile(file2); + + // check that key1 got ENTRY_CREATE + takeExpectedKey(watcher1, key1); + checkExpectedEvent(key1.pollEvents(), + StandardWatchEventKind.ENTRY_CREATE, name2); + + // check that key2 got zero events + WatchKey key = watcher2.poll(); + if (key != null) + throw new RuntimeException("key not expected"); + + // delete gus1 + file1.delete(false); + + // check that key2 got ENTRY_DELETE + takeExpectedKey(watcher2, key2); + checkExpectedEvent(key2.pollEvents(), + StandardWatchEventKind.ENTRY_DELETE, name1); + + // check that key1 got zero events + key = watcher1.poll(); + if (key != null) + throw new RuntimeException("key not expected"); + + // reset for next test + key1.reset(); + key2.reset(); + + // change registration with watcher2 so that they are both + // registered for the same event + System.out.println("register for same event"); + key2 = dir.register(watcher2, new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); + + // create file and key2 should be queued + System.out.format("create %s\n", file1); + createFile(file1); + takeExpectedKey(watcher2, key2); + checkExpectedEvent(key2.pollEvents(), + StandardWatchEventKind.ENTRY_CREATE, name1); + + System.out.println("OKAY"); + + } finally { + watcher2.close(); + watcher1.close(); + } + } + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + + testEvents(dir); + testCancel(dir); + testAutomaticCancel(dir); + testWakeup(dir); + testExceptions(dir); + testTwoWatchers(dir); + + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/WatchService/FileTreeModifier.java b/jdk/test/java/nio/file/WatchService/FileTreeModifier.java new file mode 100644 index 00000000000..741c86df094 --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/FileTreeModifier.java @@ -0,0 +1,148 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Sanity test for Sun-specific FILE_TREE watch event modifier + * @library .. + */ + +import java.nio.file.*; +import static java.nio.file.StandardWatchEventKind.*; +import java.io.IOException; +import java.io.OutputStream; +import java.util.*; +import java.util.concurrent.*; +import static com.sun.nio.file.ExtendedWatchEventModifier.*; + +public class FileTreeModifier { + + static void checkExpectedEvent(WatchService watcher, + WatchEvent.Kind<?> expectedType, + Object expectedContext) + { + WatchKey key; + try { + key = watcher.take(); + } catch (InterruptedException x) { + // should not happen + throw new RuntimeException(x); + } + WatchEvent<?> event = key.pollEvents().iterator().next(); + System.out.format("Event: type=%s, count=%d, context=%s\n", + event.kind(), event.count(), event.context()); + if (event.kind() != expectedType) + throw new RuntimeException("unexpected event"); + if (!expectedContext.equals(event.context())) + throw new RuntimeException("unexpected context"); + } + + static void doTest(Path top) throws IOException { + FileSystem fs = top.getFileSystem(); + WatchService watcher = fs.newWatchService(); + + // create directories + Path subdir = top + .resolve("a").createDirectory() + .resolve("b").createDirectory() + .resolve("c").createDirectory(); + + // Test ENTRY_CREATE with FILE_TREE modifier. + + WatchKey key = top.register(watcher, + new WatchEvent.Kind<?>[]{ ENTRY_CREATE }, FILE_TREE); + + // create file in a/b/c and check we get create event + Path file = subdir.resolve("foo").createFile(); + checkExpectedEvent(watcher, ENTRY_CREATE, top.relativize(file)); + key.reset(); + + // Test ENTRY_DELETE with FILE_TREE modifier. + + WatchKey k = top.register(watcher, + new WatchEvent.Kind<?>[]{ ENTRY_DELETE }, FILE_TREE); + if (k != key) + throw new RuntimeException("Existing key not returned"); + + // delete a/b/c/foo and check we get delete event + file.delete(false); + checkExpectedEvent(watcher, ENTRY_DELETE, top.relativize(file)); + key.reset(); + + // Test changing registration to ENTRY_CREATE without modifier + + k = top.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); + if (k != key) + throw new RuntimeException("Existing key not returned"); + + // create a/b/c/foo + file.createFile(); + + // check that key is not queued + try { + k = watcher.poll(3, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(); + } + if (k != null) + throw new RuntimeException("WatchKey not expected to be polled"); + + // create bar and check we get create event + file = top.resolve("bar").createFile(); + checkExpectedEvent(watcher, ENTRY_CREATE, top.relativize(file)); + key.reset(); + + // Test changing registration to <all> with FILE_TREE modifier + + k = top.register(watcher, + new WatchEvent.Kind<?>[]{ ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY }, + FILE_TREE); + if (k != key) + throw new RuntimeException("Existing key not returned"); + + // modify bar and check we get modify event + OutputStream out = file.newOutputStream(); + try { + out.write("Double shot expresso please".getBytes("UTF-8")); + } finally { + out.close(); + } + checkExpectedEvent(watcher, ENTRY_MODIFY, top.relativize(file)); + key.reset(); + } + + + public static void main(String[] args) throws IOException { + if (!System.getProperty("os.name").startsWith("Windows")) { + System.out.println("This is Windows-only test at this time!"); + return; + } + + Path dir = TestUtil.createTemporaryDirectory(); + try { + doTest(dir); + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/WatchService/SensitivityModifier.java b/jdk/test/java/nio/file/WatchService/SensitivityModifier.java new file mode 100644 index 00000000000..62aedeeac0a --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/SensitivityModifier.java @@ -0,0 +1,122 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Sanity test for Sun-specific sensitivyt level watch event modifier + * @library .. + * @run main/timeout=330 Basic + */ + +import java.nio.file.*; +import static java.nio.file.StandardWatchEventKind.*; +import java.io.OutputStream; +import java.io.IOException; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import com.sun.nio.file.SensitivityWatchEventModifier; + +public class SensitivityModifier { + + static final Random rand = new Random(); + + static void register(Path[] dirs, WatchService watcher) throws IOException { + SensitivityWatchEventModifier[] sensitivtives = + SensitivityWatchEventModifier.values(); + for (int i=0; i<dirs.length; i++) { + SensitivityWatchEventModifier sensivity = + sensitivtives[ rand.nextInt(sensitivtives.length) ]; + Path dir = dirs[i]; + dir.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_MODIFY }, sensivity); + } + } + + static void doTest(Path top) throws Exception { + FileSystem fs = top.getFileSystem(); + WatchService watcher = fs.newWatchService(); + + // create directories and files + int nDirs = 5 + rand.nextInt(20); + int nFiles = 50 + rand.nextInt(50); + Path[] dirs = new Path[nDirs]; + Path[] files = new Path[nFiles]; + for (int i=0; i<nDirs; i++) { + dirs[i] = top.resolve("dir" + i).createDirectory(); + } + for (int i=0; i<nFiles; i++) { + Path dir = dirs[rand.nextInt(nDirs)]; + files[i] = dir.resolve("file" + i).createFile(); + } + + // register the directories (random sensitivity) + register(dirs, watcher); + + // sleep a bit here to ensure that modification to the first file + // can be detected by polling implementations (ie: last modified time + // may not change otherwise). + try { Thread.sleep(1000); } catch (InterruptedException e) { } + + // modify files and check that events are received + for (int i=0; i<10; i++) { + Path file = files[rand.nextInt(nFiles)]; + System.out.println("Modify: " + file); + OutputStream out = file.newOutputStream(); + try { + out.write(new byte[100]); + } finally { + out.close(); + } + System.out.println("Waiting for event..."); + WatchKey key = watcher.take(); + WatchEvent<?> event = key.pollEvents().iterator().next(); + if (event.kind() != ENTRY_MODIFY) + throw new RuntimeException("Unexpected event: " + event); + Path name = ((WatchEvent<Path>)event).context(); + if (!name.equals(file.getName())) + throw new RuntimeException("Unexpected context: " + name); + System.out.println("Event OK"); + + // drain events (to avoid interference) + do { + key.reset(); + key = watcher.poll(1, TimeUnit.SECONDS); + } while (key != null); + + // re-register the directories to force changing their sensitivity + // level + register(dirs, watcher); + } + + // done + watcher.close(); + } + + public static void main(String[] args) throws Exception { + Path dir = TestUtil.createTemporaryDirectory(); + try { + doTest(dir); + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/WatchService/WithSecurityManager.java b/jdk/test/java/nio/file/WatchService/WithSecurityManager.java new file mode 100644 index 00000000000..c227585eef7 --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/WithSecurityManager.java @@ -0,0 +1,83 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for Watchable#register's permission checks + * @build WithSecurityManager + * @run main/othervm WithSecurityManager denyAll.policy - fail + * @run main/othervm WithSecurityManager denyAll.policy tree fail + * @run main/othervm WithSecurityManager grantDirOnly.policy - pass + * @run main/othervm WithSecurityManager grantDirOnly.policy tree fail + * @run main/othervm WithSecurityManager grantDirAndOneLevel.policy - pass + * @run main/othervm WithSecurityManager grantDirAndOneLevel.policy tree fail + * @run main/othervm WithSecurityManager grantDirAndTree.policy - pass + * @run main/othervm WithSecurityManager grantDirAndTree.policy tree pass + */ + +import java.nio.file.*; +import java.io.IOException; +import com.sun.nio.file.ExtendedWatchEventModifier; + +public class WithSecurityManager { + + public static void main(String[] args) throws IOException { + String policyFile = args[0]; + boolean recursive = args[1].equals("tree"); + boolean expectedToFail = args[2].equals("fail"); + + // install security manager with the given policy file + String testSrc = System.getProperty("test.src"); + if (testSrc == null) + throw new RuntimeException("This test must be run by jtreg"); + Path dir = Paths.get(testSrc); + System.setProperty("java.security.policy", dir.resolve(policyFile).toString()); + System.setSecurityManager(new SecurityManager()); + + // initialize optional modifier + WatchEvent.Modifier[] modifiers; + if (recursive) { + modifiers = new WatchEvent.Modifier[1]; + modifiers[0] = ExtendedWatchEventModifier.FILE_TREE; + } else { + modifiers = new WatchEvent.Modifier[0]; + } + + // attempt to register directory + try { + dir.register(dir.getFileSystem().newWatchService(), + new WatchEvent.Kind<?>[]{ StandardWatchEventKind.ENTRY_CREATE }, + modifiers); + if (expectedToFail) + throw new RuntimeException("SecurityException not thrown"); + } catch (SecurityException e) { + if (!expectedToFail) + throw e; + } catch (UnsupportedOperationException e) { + // FILE_TREE modifier only supported on some platforms + if (!recursive) + throw new RuntimeException(e); + System.out.println("FILE_TREE option not supported"); + } + } +} diff --git a/jdk/test/java/nio/file/WatchService/denyAll.policy b/jdk/test/java/nio/file/WatchService/denyAll.policy new file mode 100644 index 00000000000..32500947791 --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/denyAll.policy @@ -0,0 +1,3 @@ +// policy file that does not grant any permissions +grant { +}; diff --git a/jdk/test/java/nio/file/WatchService/grantDirAndOneLevel.policy b/jdk/test/java/nio/file/WatchService/grantDirAndOneLevel.policy new file mode 100644 index 00000000000..1a34646464a --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/grantDirAndOneLevel.policy @@ -0,0 +1,5 @@ +// policy file that grants read access to source directory and its entries +grant { + permission java.io.FilePermission "${test.src}", "read"; + permission java.io.FilePermission "${test.src}${file.separator}*", "read"; +}; diff --git a/jdk/test/java/nio/file/WatchService/grantDirAndTree.policy b/jdk/test/java/nio/file/WatchService/grantDirAndTree.policy new file mode 100644 index 00000000000..85bc0d0fb51 --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/grantDirAndTree.policy @@ -0,0 +1,5 @@ +// policy file that grants read access to source directory and all descendants +grant { + permission java.io.FilePermission "${test.src}", "read"; + permission java.io.FilePermission "${test.src}${file.separator}-", "read"; +}; diff --git a/jdk/test/java/nio/file/WatchService/grantDirOnly.policy b/jdk/test/java/nio/file/WatchService/grantDirOnly.policy new file mode 100644 index 00000000000..fca1539416f --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/grantDirOnly.policy @@ -0,0 +1,4 @@ +// policy file that grants read access to source directory +grant { + permission java.io.FilePermission "${test.src}", "read"; +}; diff --git a/jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java b/jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java new file mode 100644 index 00000000000..3a9960702f9 --- /dev/null +++ b/jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java @@ -0,0 +1,166 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.attribute.AclFileAttribueView + * @library ../.. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; + +import static java.nio.file.attribute.AclEntryType.*; +import static java.nio.file.attribute.AclEntryPermission.*; +import static java.nio.file.attribute.AclEntryFlag.*; + +public class Basic { + + static void printAcl(List<AclEntry> acl) { + for (AclEntry entry: acl) { + System.out.format(" %s%n", entry); + } + } + + // sanity check read and writing ACL + static void testReadWrite(Path dir) throws IOException { + Path file = dir.resolve("foo"); + if (file.notExists()) + file.createFile(); + + AclFileAttributeView view = file + .getFileAttributeView(AclFileAttributeView.class); + + // print existing ACL + List<AclEntry> acl = view.getAcl(); + System.out.println(" -- current ACL --"); + printAcl(acl); + + // insert entry to grant owner read access + UserPrincipal owner = view.getOwner(); + AclEntry entry = AclEntry.newBuilder() + .setType(ALLOW) + .setPrincipal(owner) + .setPermissions(READ_DATA, READ_ATTRIBUTES) + .build(); + System.out.println(" -- insert (entry 0) --"); + System.out.format(" %s%n", entry); + acl.add(0, entry); + view.setAcl(acl); + + // re-ACL and check entry + List<AclEntry> newacl = view.getAcl(); + System.out.println(" -- current ACL --"); + printAcl(acl); + if (!newacl.get(0).equals(entry)) { + throw new RuntimeException("Entry 0 is not expected"); + } + + // if PosixFileAttributeView then repeat test with OWNER@ + if (file.getFileStore().supportsFileAttributeView("posix")) { + owner = file.getFileSystem().getUserPrincipalLookupService() + .lookupPrincipalByName("OWNER@"); + entry = AclEntry.newBuilder(entry).setPrincipal(owner).build(); + + System.out.println(" -- replace (entry 0) --"); + System.out.format(" %s%n", entry); + + acl.set(0, entry); + view.setAcl(acl); + newacl = view.getAcl(); + System.out.println(" -- current ACL --"); + printAcl(acl); + if (!newacl.get(0).equals(entry)) { + throw new RuntimeException("Entry 0 is not expected"); + } + } + } + + static FileAttribute<List<AclEntry>> asAclAttribute(final List<AclEntry> acl) { + return new FileAttribute<List<AclEntry>>() { + public String name() { return "acl:acl"; } + public List<AclEntry> value() { return acl; } + }; + } + + static void assertEquals(List<AclEntry> actual, List<AclEntry> expected) { + if (!actual.equals(expected)) { + System.err.format("Actual: %s\n", actual); + System.err.format("Expected: %s\n", expected); + throw new RuntimeException("ACL not expected"); + } + } + + // sanity check create a file or directory with initial ACL + static void testCreateFile(Path dir) throws IOException { + UserPrincipal user = Attributes.getOwner(dir); + + // create file with initial ACL + System.out.println("-- create file with initial ACL --"); + Path file = dir.resolve("gus"); + List<AclEntry> fileAcl = Arrays.asList( + AclEntry.newBuilder() + .setType(AclEntryType.ALLOW) + .setPrincipal(user) + .setPermissions(SYNCHRONIZE, READ_DATA, WRITE_DATA, + READ_ATTRIBUTES, READ_ACL, WRITE_ATTRIBUTES, DELETE) + .build()); + file.createFile(asAclAttribute(fileAcl)); + assertEquals(Attributes.getAcl(file), fileAcl); + + // create directory with initial ACL + System.out.println("-- create directory with initial ACL --"); + Path subdir = dir.resolve("stuff"); + List<AclEntry> dirAcl = Arrays.asList( + AclEntry.newBuilder() + .setType(AclEntryType.ALLOW) + .setPrincipal(user) + .setPermissions(SYNCHRONIZE, ADD_FILE, DELETE) + .build(), + AclEntry.newBuilder(fileAcl.get(0)) + .setFlags(FILE_INHERIT) + .build()); + subdir.createDirectory(asAclAttribute(dirAcl)); + assertEquals(Attributes.getAcl(subdir), dirAcl); + } + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + if (!dir.getFileStore().supportsFileAttributeView("acl")) { + System.out.println("ACLs not supported - test skipped!"); + return; + } + testReadWrite(dir); + + // only currently feasible on Windows + if (System.getProperty("os.name").startsWith("Windows")) + testCreateFile(dir); + + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/attribute/Attributes/Basic.java b/jdk/test/java/nio/file/attribute/Attributes/Basic.java new file mode 100644 index 00000000000..8dfde80d9a5 --- /dev/null +++ b/jdk/test/java/nio/file/attribute/Attributes/Basic.java @@ -0,0 +1,254 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.attribute.Attributes + * @library ../.. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * Exercises getAttribute/setAttribute/readAttributes methods. + */ + +public class Basic { + + static void assertTrue(boolean okay) { + if (!okay) + throw new RuntimeException("Assertion Failed"); + } + + static void checkEqual(Object o1, Object o2) { + if (o1 == null) { + assertTrue(o2 == null); + } else { + assertTrue (o1.equals(o2)); + } + } + + // Exercise getAttribute/setAttribute/readAttributes on basic attributes + static void checkBasicAttributes(FileRef file, BasicFileAttributes attrs) + throws IOException + { + // getAttribute + checkEqual(attrs.size(), Attributes.getAttribute(file, "size")); + checkEqual(attrs.lastModifiedTime(), + Attributes.getAttribute(file, "basic:lastModifiedTime")); + checkEqual(attrs.lastAccessTime(), + Attributes.getAttribute(file, "lastAccessTime")); + checkEqual(attrs.creationTime(), + Attributes.getAttribute(file, "basic:creationTime")); + assertTrue((Boolean)Attributes.getAttribute(file, "isRegularFile")); + assertTrue(!(Boolean)Attributes.getAttribute(file, "basic:isDirectory")); + assertTrue(!(Boolean)Attributes.getAttribute(file, "isSymbolicLink")); + assertTrue(!(Boolean)Attributes.getAttribute(file, "basic:isOther")); + checkEqual(attrs.linkCount(), + (Integer)Attributes.getAttribute(file, "linkCount")); + checkEqual(attrs.fileKey(), Attributes.getAttribute(file, "basic:fileKey")); + + // setAttribute + if (attrs.resolution() == TimeUnit.MILLISECONDS) { + long modTime = attrs.lastModifiedTime(); + Attributes.setAttribute(file, "basic:lastModifiedTime", 0L); + assertTrue(Attributes.readBasicFileAttributes(file).lastModifiedTime() == 0L); + Attributes.setAttribute(file, "lastModifiedTime", modTime); + assertTrue(Attributes.readBasicFileAttributes(file).lastModifiedTime() == modTime); + } + + // readAttributes + Map<String,?> map; + map = Attributes.readAttributes(file, "*"); + assertTrue(map.size() >= 11); + checkEqual(attrs.isRegularFile(), map.get("isRegularFile")); // check one + + map = Attributes.readAttributes(file, "basic:*"); + assertTrue(map.size() >= 11); + checkEqual(attrs.lastAccessTime(), map.get("lastAccessTime")); // check one + + map = Attributes.readAttributes(file, "size,lastModifiedTime"); + assertTrue(map.size() == 2); + checkEqual(attrs.size(), map.get("size")); + checkEqual(attrs.lastModifiedTime(), map.get("lastModifiedTime")); + + map = Attributes.readAttributes(file, + "basic:lastModifiedTime,lastAccessTime,linkCount,ShouldNotExist"); + assertTrue(map.size() == 3); + checkEqual(attrs.lastModifiedTime(), map.get("lastModifiedTime")); + checkEqual(attrs.lastAccessTime(), map.get("lastAccessTime")); + checkEqual(attrs.lastAccessTime(), map.get("lastAccessTime")); + } + + // Exercise getAttribute/setAttribute/readAttributes on posix attributes + static void checkPosixAttributes(FileRef file, PosixFileAttributes attrs) + throws IOException + { + checkBasicAttributes(file, attrs); + + // getAttribute + checkEqual(attrs.permissions(), + Attributes.getAttribute(file, "posix:permissions")); + checkEqual(attrs.owner(), + Attributes.getAttribute(file, "posix:owner")); + checkEqual(attrs.group(), + Attributes.getAttribute(file, "posix:group")); + + // setAttribute + Set<PosixFilePermission> orig = attrs.permissions(); + Set<PosixFilePermission> newPerms = new HashSet<PosixFilePermission>(orig); + newPerms.remove(PosixFilePermission.OTHERS_READ); + newPerms.remove(PosixFilePermission.OTHERS_WRITE); + newPerms.remove(PosixFilePermission.OTHERS_EXECUTE); + Attributes.setAttribute(file, "posix:permissions", newPerms); + checkEqual(Attributes.readPosixFileAttributes(file).permissions(), newPerms); + Attributes.setAttribute(file, "posix:permissions", orig); + checkEqual(Attributes.readPosixFileAttributes(file).permissions(), orig); + Attributes.setAttribute(file, "posix:owner", attrs.owner()); + Attributes.setAttribute(file, "posix:group", attrs.group()); + + // readAttributes + Map<String,?> map; + map = Attributes.readAttributes(file, "posix:*"); + assertTrue(map.size() >= 14); + checkEqual(attrs.permissions(), map.get("permissions")); // check one + + map = Attributes.readAttributes(file, "posix:size,owner,ShouldNotExist"); + assertTrue(map.size() == 2); + checkEqual(attrs.size(), map.get("size")); + checkEqual(attrs.owner(), map.get("owner")); + } + + // Exercise getAttribute/setAttribute/readAttributes on unix attributes + static void checkUnixAttributes(FileRef file) throws IOException { + // getAttribute + int mode = (Integer)Attributes.getAttribute(file, "unix:mode"); + long ino = (Long)Attributes.getAttribute(file, "unix:ino"); + long dev = (Long)Attributes.getAttribute(file, "unix:dev"); + long rdev = (Long)Attributes.getAttribute(file, "unix:rdev"); + int uid = (Integer)Attributes.getAttribute(file, "unix:uid"); + int gid = (Integer)Attributes.getAttribute(file, "unix:gid"); + long ctime = (Long)Attributes.getAttribute(file, "unix:ctime"); + + // readAttributes + Map<String,?> map; + map = Attributes.readAttributes(file, "unix:*"); + assertTrue(map.size() >= 21); + + map = Attributes.readAttributes(file, "unix:size,uid,gid,ShouldNotExist"); + assertTrue(map.size() == 3); + checkEqual(map.get("size"), + Attributes.readBasicFileAttributes(file).size()); + } + + // Exercise getAttribute/setAttribute/readAttributes on dos attributes + static void checkDosAttributes(FileRef file, DosFileAttributes attrs) + throws IOException + { + checkBasicAttributes(file, attrs); + + // getAttribute + checkEqual(attrs.isReadOnly(), + Attributes.getAttribute(file, "dos:readonly")); + checkEqual(attrs.isHidden(), + Attributes.getAttribute(file, "dos:hidden")); + checkEqual(attrs.isSystem(), + Attributes.getAttribute(file, "dos:system")); + checkEqual(attrs.isArchive(), + Attributes.getAttribute(file, "dos:archive")); + + // setAttribute + boolean value; + + value = attrs.isReadOnly(); + Attributes.setAttribute(file, "dos:readonly", !value); + checkEqual(Attributes.readDosFileAttributes(file).isReadOnly(), !value); + Attributes.setAttribute(file, "dos:readonly", value); + checkEqual(Attributes.readDosFileAttributes(file).isReadOnly(), value); + + value = attrs.isHidden(); + Attributes.setAttribute(file, "dos:hidden", !value); + checkEqual(Attributes.readDosFileAttributes(file).isHidden(), !value); + Attributes.setAttribute(file, "dos:hidden", value); + checkEqual(Attributes.readDosFileAttributes(file).isHidden(), value); + + value = attrs.isSystem(); + Attributes.setAttribute(file, "dos:system", !value); + checkEqual(Attributes.readDosFileAttributes(file).isSystem(), !value); + Attributes.setAttribute(file, "dos:system", value); + checkEqual(Attributes.readDosFileAttributes(file).isSystem(), value); + + value = attrs.isArchive(); + Attributes.setAttribute(file, "dos:archive", !value); + checkEqual(Attributes.readDosFileAttributes(file).isArchive(), !value); + Attributes.setAttribute(file, "dos:archive", value); + checkEqual(Attributes.readDosFileAttributes(file).isArchive(), value); + + // readAttributes + Map<String,?> map; + map = Attributes.readAttributes(file, "dos:*"); + assertTrue(map.size() >= 15); + checkEqual(attrs.isReadOnly(), map.get("readonly")); // check one + + map = Attributes.readAttributes(file, "dos:size,hidden,ShouldNotExist"); + assertTrue(map.size() == 2); + checkEqual(attrs.size(), map.get("size")); + checkEqual(attrs.isHidden(), map.get("hidden")); + } + + static void doTests(Path dir) throws IOException { + Path file = dir.resolve("foo").createFile(); + FileStore store = file.getFileStore(); + try { + checkBasicAttributes(file, + Attributes.readBasicFileAttributes(file)); + + if (store.supportsFileAttributeView("posix")) + checkPosixAttributes(file, + Attributes.readPosixFileAttributes(file)); + + if (store.supportsFileAttributeView("unix")) + checkUnixAttributes(file); + + if (store.supportsFileAttributeView("dos")) + checkDosAttributes(file, + Attributes.readDosFileAttributes(file)); + } finally { + file.delete(); + } + } + + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + doTests(dir); + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java b/jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java new file mode 100644 index 00000000000..1cc192f2a45 --- /dev/null +++ b/jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java @@ -0,0 +1,150 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.attribute.BasicFileAttributeView + * @library ../.. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.io.*; + +public class Basic { + + static void check(boolean okay, String msg) { + if (!okay) + throw new RuntimeException(msg); + } + + static void checkAttributesOfDirectory(Path dir) + throws IOException + { + BasicFileAttributes attrs = Attributes.readBasicFileAttributes(dir); + check(attrs.isDirectory(), "is a directory"); + check(!attrs.isRegularFile(), "is not a regular file"); + check(!attrs.isSymbolicLink(), "is not a link"); + check(!attrs.isOther(), "is not other"); + check(attrs.linkCount() >= 1, "should be at least 1"); + + // last-modified-time should match java.io.File + if (attrs.resolution() == TimeUnit.MILLISECONDS) { + File f = new File(dir.toString()); + check(f.lastModified() == attrs.lastModifiedTime(), + "last-modified time should be the same"); + } + } + + static void checkAttributesOfFile(Path dir, Path file) + throws IOException + { + BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file); + check(attrs.isRegularFile(), "is a regular file"); + check(!attrs.isDirectory(), "is not a directory"); + check(!attrs.isSymbolicLink(), "is not a link"); + check(!attrs.isOther(), "is not other"); + check(attrs.linkCount() >= 1, "should be at least 1"); + + // size and last-modified-time should match java.io.File + File f = new File(file.toString()); + check(f.length() == attrs.size(), "size should be the same"); + if (attrs.resolution() == TimeUnit.MILLISECONDS) { + check(f.lastModified() == attrs.lastModifiedTime(), + "last-modified time should be the same"); + } + + // copy last-modified time and file create time from directory to file, + // re-read attribtues, and check they match + BasicFileAttributeView view = + file.getFileAttributeView(BasicFileAttributeView.class); + BasicFileAttributes dirAttrs = Attributes.readBasicFileAttributes(dir); + view.setTimes(dirAttrs.lastModifiedTime(), null, null, dirAttrs.resolution()); + if (dirAttrs.creationTime() != -1L) { + view.setTimes(null, null, dirAttrs.creationTime(), dirAttrs.resolution()); + } + attrs = view.readAttributes(); + check(attrs.lastModifiedTime() == dirAttrs.lastModifiedTime(), + "last-modified time should be equal"); + if (dirAttrs.creationTime() != -1L) { + check(attrs.creationTime() == dirAttrs.creationTime(), + "create time should be the same"); + } + + // security tests + check (!(attrs instanceof PosixFileAttributes), + "should not be able to cast to PosixFileAttributes"); + } + + static void checkAttributesOfLink(Path link) + throws IOException + { + BasicFileAttributes attrs = Attributes + .readBasicFileAttributes(link, LinkOption.NOFOLLOW_LINKS); + check(attrs.isSymbolicLink(), "is a link"); + check(!attrs.isDirectory(), "is a directory"); + check(!attrs.isRegularFile(), "is not a regular file"); + check(!attrs.isOther(), "is not other"); + check(attrs.linkCount() >= 1, "should be at least 1"); + } + + static void attributeReadWriteTests(Path dir) + throws IOException + { + // create file + Path file = dir.resolve("foo"); + OutputStream out = file.newOutputStream(); + try { + out.write("this is not an empty file".getBytes("UTF-8")); + } finally { + out.close(); + } + + // check attributes of directory and file + checkAttributesOfDirectory(dir); + checkAttributesOfFile(dir, file); + + // symbolic links may be supported + Path link = dir.resolve("link"); + try { + link.createSymbolicLink( file ); + } catch (UnsupportedOperationException x) { + return; + } catch (IOException x) { + return; + } + checkAttributesOfLink(link); + } + + public static void main(String[] args) throws IOException { + // create temporary directory to run tests + Path dir = TestUtil.createTemporaryDirectory(); + try { + attributeReadWriteTests(dir); + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/attribute/DosFileAttributeView/Basic.java b/jdk/test/java/nio/file/attribute/DosFileAttributeView/Basic.java new file mode 100644 index 00000000000..3c8a296188b --- /dev/null +++ b/jdk/test/java/nio/file/attribute/DosFileAttributeView/Basic.java @@ -0,0 +1,155 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.attribute.DosFileAttributeView + * @library ../.. + */ + +import java.nio.file.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; +import java.util.*; +import java.io.IOException; + +public class Basic { + + static void check(boolean okay) { + if (!okay) + throw new RuntimeException("Test failed"); + } + + // exercise each setter/getter method, leaving all attributes unset + static void testAttributes(DosFileAttributeView view) throws IOException { + view.setReadOnly(true); + check(view.readAttributes().isReadOnly()); + view.setReadOnly(false); + check(!view.readAttributes().isReadOnly()); + view.setHidden(true); + check(view.readAttributes().isHidden()); + view.setHidden(false); + check(!view.readAttributes().isHidden()); + view.setArchive(true); + check(view.readAttributes().isArchive()); + view.setArchive(false); + check(!view.readAttributes().isArchive()); + view.setSystem(true); + check(view.readAttributes().isSystem()); + view.setSystem(false); + check(!view.readAttributes().isSystem()); + } + + // set the value of all attributes + static void setAll(DosFileAttributeView view, boolean value) + throws IOException + { + view.setReadOnly(value); + view.setHidden(value); + view.setArchive(value); + view.setSystem(value); + } + + // read and write FAT attributes + static void readWriteTests(Path dir) throws IOException { + + // create "foo" and test that we can read/write each FAT attribute + Path file = dir.resolve("foo"); + file.newOutputStream().close(); + try { + testAttributes(file + .getFileAttributeView(DosFileAttributeView.class)); + + // Following tests use a symbolic link so skip if not supported + if (!TestUtil.supportsLinks(dir)) + return; + + Path link = dir.resolve("link").createSymbolicLink(file); + + // test following links + testAttributes(link + .getFileAttributeView(DosFileAttributeView.class)); + + // test not following links + try { + try { + testAttributes(link + .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS)); + } catch (IOException x) { + // access to link attributes not supported + return; + } + + // set all attributes on link + // run test on target of link (which leaves them all un-set) + // check that attributes of link remain all set + setAll(link + .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS), true); + testAttributes(link + .getFileAttributeView(DosFileAttributeView.class)); + DosFileAttributes attrs = Attributes.readDosFileAttributes(link, NOFOLLOW_LINKS); + check(attrs.isReadOnly()); + check(attrs.isHidden()); + check(attrs.isArchive()); + check(attrs.isSystem()); + setAll(link + .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS), false); + + // set all attributes on target + // run test on link (which leaves them all un-set) + // check that attributes of target remain all set + setAll(link + .getFileAttributeView(DosFileAttributeView.class), true); + testAttributes(link + .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS)); + attrs = Attributes.readDosFileAttributes(link); + check(attrs.isReadOnly()); + check(attrs.isHidden()); + check(attrs.isArchive()); + check(attrs.isSystem()); + setAll(link + .getFileAttributeView(DosFileAttributeView.class), false); + } finally { + TestUtil.deleteUnchecked(link); + } + } finally { + TestUtil.deleteUnchecked(file); + } + } + + public static void main(String[] args) throws IOException { + // create temporary directory to run tests + Path dir = TestUtil.createTemporaryDirectory(); + + try { + // skip test if DOS file attributes not supported + if (!dir.getFileStore().supportsFileAttributeView("dos")) { + System.out.println("DOS file attribute not supported."); + return; + } + readWriteTests(dir); + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java b/jdk/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java new file mode 100644 index 00000000000..993e8c1ddec --- /dev/null +++ b/jdk/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java @@ -0,0 +1,171 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.attribute.FileStoreAttributeView + * @library ../.. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * Simple unit test for FileStoreAttributeView that checks that the disk space + * attribtues are "close" to the equivalent values reported by java.io.File. + */ + +public class Basic { + + static final long K = 1024L; + static final long G = 1024L * 1024L * 1024L; + + /** + * Print out the disk space information for the given file system + */ + static void printFileStore(FileStore fs) throws IOException { + FileStoreSpaceAttributeView view = + fs.getFileStoreAttributeView(FileStoreSpaceAttributeView.class); + FileStoreSpaceAttributes attrs = view.readAttributes(); + + long total = attrs.totalSpace() / K; + long used = (attrs.totalSpace() - attrs.unallocatedSpace()) / K; + long avail = attrs.usableSpace() / K; + + String s = fs.toString(); + if (s.length() > 20) { + System.out.println(s); + s = ""; + } + System.out.format("%-20s %12d %12d %12d\n", s, total, used, avail); + } + + /** + * Check that two values are within 1GB of each other + */ + static void checkWithin1GB(long value1, long value2) { + long diff = Math.abs(value1 - value2); + if (diff > G) + throw new RuntimeException("values differ by more than 1GB"); + } + + /** + * Check disk space on the file system of the given file + */ + static void checkSpace(Path file) throws IOException { + System.out.println(" -- check space -- "); + System.out.println(file); + + FileStore fs = file.getFileStore(); + System.out.format("Filesystem: %s\n", fs); + + // get values reported by java.io.File + File f = new File(file.toString()); + long total = f.getTotalSpace(); + long free = f.getFreeSpace(); + long usable = f.getUsableSpace(); + System.out.println("java.io.File"); + System.out.format(" Total: %d\n", total); + System.out.format(" Free: %d\n", free); + System.out.format(" Usable: %d\n", usable); + + // get values reported by the FileStoreSpaceAttributeView + FileStoreSpaceAttributes attrs = fs + .getFileStoreAttributeView(FileStoreSpaceAttributeView.class) + .readAttributes(); + System.out.println("java.nio.file.FileStoreSpaceAttributeView:"); + System.out.format(" Total: %d\n", attrs.totalSpace()); + System.out.format(" Free: %d\n", attrs.unallocatedSpace()); + System.out.format(" Usable: %d\n", attrs.usableSpace()); + + // check values are "close" + checkWithin1GB(total, attrs.totalSpace()); + checkWithin1GB(free, attrs.unallocatedSpace()); + checkWithin1GB(usable, attrs.usableSpace()); + + // get values by name (and in bulk) + FileStoreAttributeView view = fs.getFileStoreAttributeView("space"); + checkWithin1GB(total, (Long)view.getAttribute("totalSpace")); + checkWithin1GB(free, (Long)view.getAttribute("unallocatedSpace")); + checkWithin1GB(usable, (Long)view.getAttribute("usableSpace")); + Map<String,?> map = view.readAttributes("*"); + checkWithin1GB(total, (Long)map.get("totalSpace")); + checkWithin1GB(free, (Long)map.get("unallocatedSpace")); + checkWithin1GB(usable, (Long)map.get("usableSpace")); + map = view.readAttributes("totalSpace", "unallocatedSpace", "usableSpace"); + checkWithin1GB(total, (Long)map.get("totalSpace")); + checkWithin1GB(free, (Long)map.get("unallocatedSpace")); + checkWithin1GB(usable, (Long)map.get("usableSpace")); + } + + /** + * Check (Windows-specific) volume attributes + */ + static void checkVolumeAttributes() throws IOException { + System.out.println(" -- volumes -- "); + for (FileStore store: FileSystems.getDefault().getFileStores()) { + FileStoreAttributeView view = store.getFileStoreAttributeView("volume"); + if (view == null) + continue; + Map<String,?> attrs = view.readAttributes("*"); + int vsn = (Integer)attrs.get("vsn"); + boolean compressed = (Boolean)attrs.get("compressed"); + boolean removable = (Boolean)attrs.get("removable"); + boolean cdrom = (Boolean)attrs.get("cdrom"); + String type; + if (removable) type = "removable"; + else if (cdrom) type = "cdrom"; + else type = "unknown"; + System.out.format("%s (%s) vsn:%x compressed:%b%n", store.name(), + type, vsn, compressed); + } + + } + + public static void main(String[] args) throws IOException { + // print out the disk space information for all file systems + FileSystem fs = FileSystems.getDefault(); + for (FileStore store: fs.getFileStores()) { + printFileStore(store); + } + + Path dir = TestUtil.createTemporaryDirectory(); + try { + // check space using directory + checkSpace(dir); + + // check space using file + Path file = dir.resolve("foo").createFile(); + checkSpace(file); + + // volume attributes (Windows specific) + checkVolumeAttributes(); + + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java b/jdk/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java new file mode 100644 index 00000000000..2ee059bb95d --- /dev/null +++ b/jdk/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java @@ -0,0 +1,398 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.attribute.PosixFileAttributeView + * @library ../.. + */ + +import java.nio.file.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; + +/** + * Unit test for PosixFileAttributeView, passing silently if this attribute + * view is not available. + */ + +public class Basic { + + /** + * Use view to update permission to the given mode and check that the + * permissions have been updated. + */ + static void testPermissions(PosixFileAttributeView view, String mode) + throws IOException + { + System.out.format("change mode: %s\n", mode); + Set<PosixFilePermission> perms = PosixFilePermissions.fromString(mode); + + // change permissions and re-read them. + view.setPermissions(perms); + Set<PosixFilePermission> current = view.readAttributes().permissions(); + if (!current.equals(perms)) { + throw new RuntimeException("Actual permissions: " + + PosixFilePermissions.toString(current) + ", expected: " + + PosixFilePermissions.toString(perms)); + } + + // repeat test using setAttribute/getAttribute + view.setAttribute("permissions", perms); + current = (Set<PosixFilePermission>)view.getAttribute("permissions"); + if (!current.equals(perms)) { + throw new RuntimeException("Actual permissions: " + + PosixFilePermissions.toString(current) + ", expected: " + + PosixFilePermissions.toString(perms)); + } + } + + /** + * Check that the actual permissions of a file match or make it more + * secure than requested + */ + static void checkSecure(Set<PosixFilePermission> requested, + Set<PosixFilePermission> actual) + { + for (PosixFilePermission perm: actual) { + if (!requested.contains(perm)) { + throw new RuntimeException("Actual permissions: " + + PosixFilePermissions.toString(actual) + ", requested: " + + PosixFilePermissions.toString(requested) + + " - file is less secure than requested"); + } + } + } + + /** + * Create file with given mode and check that the file is created with a + * mode that is not less secure + */ + static void createWithPermissions(Path file, + String mode) + throws IOException + { + Set<PosixFilePermission> requested = PosixFilePermissions.fromString(mode); + FileAttribute<Set<PosixFilePermission>> attr = + PosixFilePermissions.asFileAttribute(requested); + System.out.format("create file with mode: %s\n", mode); + + EnumSet<StandardOpenOption> options = EnumSet.of(StandardOpenOption.CREATE_NEW, + StandardOpenOption.WRITE); + file.newOutputStream(options, attr).close(); + try { + checkSecure(requested, file + .getFileAttributeView(PosixFileAttributeView.class) + .readAttributes() + .permissions()); + } finally { + file.delete(false); + } + + System.out.format("create directory with mode: %s\n", mode); + file.createDirectory(attr); + try { + checkSecure(requested, file + .getFileAttributeView(PosixFileAttributeView.class) + .readAttributes() + .permissions()); + } finally { + file.delete(false); + } + } + + /** + * Test the setPermissions/permissions methods. + */ + static void permissionTests(Path dir) + throws IOException + { + System.out.println("-- Permission Tests --"); + + // create file and test updating and reading its permissions + Path file = dir.resolve("foo"); + System.out.format("create %s\n", file); + file.newOutputStream().close(); + try { + // get initial permissions so that we can restore them later + PosixFileAttributeView view = file + .getFileAttributeView(PosixFileAttributeView.class); + Set<PosixFilePermission> save = view.readAttributes() + .permissions(); + + // test various modes + try { + testPermissions(view, "---------"); + testPermissions(view, "r--------"); + testPermissions(view, "-w-------"); + testPermissions(view, "--x------"); + testPermissions(view, "rwx------"); + testPermissions(view, "---r-----"); + testPermissions(view, "----w----"); + testPermissions(view, "-----x---"); + testPermissions(view, "---rwx---"); + testPermissions(view, "------r--"); + testPermissions(view, "-------w-"); + testPermissions(view, "--------x"); + testPermissions(view, "------rwx"); + testPermissions(view, "r--r-----"); + testPermissions(view, "r--r--r--"); + testPermissions(view, "rw-rw----"); + testPermissions(view, "rwxrwx---"); + testPermissions(view, "rw-rw-r--"); + testPermissions(view, "r-xr-x---"); + testPermissions(view, "r-xr-xr-x"); + testPermissions(view, "rwxrwxrwx"); + } finally { + view.setPermissions(save); + } + } finally { + file.delete(false); + } + + // create link (to file that doesn't exist) and test reading of + // permissions + if (TestUtil.supportsLinks(dir)) { + Path link = dir.resolve("link"); + System.out.format("create link %s\n", link); + link.createSymbolicLink(file); + try { + PosixFileAttributes attrs = Attributes + .readPosixFileAttributes(link, NOFOLLOW_LINKS); + if (!attrs.isSymbolicLink()) { + throw new RuntimeException("not a link"); + } + } finally { + link.delete(false); + } + } + + System.out.println("OKAY"); + } + + /** + * Test creating a file and directory with initial permissios + */ + static void createTests(Path dir) + throws IOException + { + System.out.println("-- Create Tests --"); + + Path file = dir.resolve("foo"); + + createWithPermissions(file, "---------"); + createWithPermissions(file, "r--------"); + createWithPermissions(file, "-w-------"); + createWithPermissions(file, "--x------"); + createWithPermissions(file, "rwx------"); + createWithPermissions(file, "---r-----"); + createWithPermissions(file, "----w----"); + createWithPermissions(file, "-----x---"); + createWithPermissions(file, "---rwx---"); + createWithPermissions(file, "------r--"); + createWithPermissions(file, "-------w-"); + createWithPermissions(file, "--------x"); + createWithPermissions(file, "------rwx"); + createWithPermissions(file, "r--r-----"); + createWithPermissions(file, "r--r--r--"); + createWithPermissions(file, "rw-rw----"); + createWithPermissions(file, "rwxrwx---"); + createWithPermissions(file, "rw-rw-r--"); + createWithPermissions(file, "r-xr-x---"); + createWithPermissions(file, "r-xr-xr-x"); + createWithPermissions(file, "rwxrwxrwx"); + + System.out.println("OKAY"); + } + + /** + * Test setOwner/setGroup methods - this test simply exercises the + * methods to avoid configuration. + */ + static void ownerTests(Path dir) + throws IOException + { + System.out.println("-- Owner Tests --"); + + Path file = dir.resolve("gus"); + System.out.format("create %s\n", file); + + file.newOutputStream().close(); + try { + + // read attributes of directory to get owner/group + PosixFileAttributeView view = file + .getFileAttributeView(PosixFileAttributeView.class); + PosixFileAttributes attrs = view.readAttributes(); + + // set to existing owner/group + view.setOwner(attrs.owner()); + view.setGroup(attrs.group()); + + // repeat test using setAttribute + Map<String,?> map = view.readAttributes("owner","group"); + view.setAttribute("owner", map.get("owner")); + view.setAttribute("group", map.get("group")); + + } finally { + file.delete(false); + } + + System.out.println("OKAY"); + } + + /** + * Test the lookupPrincipalByName/lookupPrincipalByGroupName methods + */ + static void lookupPrincipalTests(Path dir) + throws IOException + { + System.out.println("-- Lookup UserPrincipal Tests --"); + + UserPrincipalLookupService lookupService = dir.getFileSystem() + .getUserPrincipalLookupService(); + + // read attributes of directory to get owner/group + PosixFileAttributes attrs = Attributes.readPosixFileAttributes(dir); + + // lookup owner and check it matches file's owner + System.out.format("lookup: %s\n", attrs.owner().getName()); + try { + UserPrincipal owner = lookupService.lookupPrincipalByName(attrs.owner().getName()); + if (owner instanceof GroupPrincipal) + throw new RuntimeException("owner is a group?"); + if (!owner.equals(attrs.owner())) + throw new RuntimeException("owner different from file owner"); + } catch (UserPrincipalNotFoundException x) { + System.out.println("user not found - test skipped"); + } + + // lookup group and check it matches file's group-owner + System.out.format("lookup group: %s\n", attrs.group().getName()); + try { + GroupPrincipal group = lookupService.lookupPrincipalByGroupName(attrs.group().getName()); + if (!group.equals(attrs.group())) + throw new RuntimeException("group different from file group-owner"); + } catch (UserPrincipalNotFoundException x) { + System.out.println("group not found - test skipped"); + } + + // test that UserPrincipalNotFoundException is thrown + String invalidPrincipal = "scumbag99"; + try { + System.out.format("lookup: %s\n", invalidPrincipal); + lookupService.lookupPrincipalByName(invalidPrincipal); + throw new RuntimeException("'" + invalidPrincipal + "' is a valid user?"); + } catch (UserPrincipalNotFoundException x) { + } + try { + System.out.format("lookup group: %s\n", invalidPrincipal); + lookupService.lookupPrincipalByGroupName("idonotexist"); + throw new RuntimeException("'" + invalidPrincipal + "' is a valid group?"); + } catch (UserPrincipalNotFoundException x) { + } + System.out.println("OKAY"); + } + + /** + * Test various exceptions are thrown as expected + */ + @SuppressWarnings("unchecked") + static void exceptionsTests(Path dir) + throws IOException + { + System.out.println("-- Exceptions --"); + + PosixFileAttributeView view = dir + .getFileAttributeView(PosixFileAttributeView.class); + + // NullPointerException + try { + view.setOwner(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + view.setGroup(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + + UserPrincipalLookupService lookupService = dir.getFileSystem() + .getUserPrincipalLookupService(); + try { + lookupService.lookupPrincipalByName(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + lookupService.lookupPrincipalByGroupName(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + view.setPermissions(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + Set<PosixFilePermission> perms = new HashSet<PosixFilePermission>(); + perms.add(null); + view.setPermissions(perms); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + + // ClassCastException + try { + Set perms = new HashSet(); // raw type + perms.add(new Object()); + view.setPermissions(perms); + throw new RuntimeException("ClassCastException not thrown"); + } catch (ClassCastException x) { + } + + System.out.println("OKAY"); + } + + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + if (!dir.getFileStore().supportsFileAttributeView("posix")) { + System.out.println("PosixFileAttributeView not supported"); + return; + } + + permissionTests(dir); + createTests(dir); + ownerTests(dir); + lookupPrincipalTests(dir); + exceptionsTests(dir); + + } finally { + TestUtil.removeAll(dir); + } + } +} diff --git a/jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java b/jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java new file mode 100644 index 00000000000..ffdb5b86e89 --- /dev/null +++ b/jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java @@ -0,0 +1,273 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.attribute.UserDefinedFileAttributeView + * @library ../.. + */ + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.file.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; +import java.util.Arrays; +import java.util.Map; +import java.util.Random; +import java.io.IOException; + +public class Basic { + + private static Random rand = new Random(); + + private static final String ATTR_NAME = "mime_type"; + private static final String ATTR_VALUE = "text/plain"; + private static final String ATTR_VALUE2 = "text/html"; + + static interface Task { + void run() throws Exception; + } + + static void tryCatch(Class<? extends Throwable> ex, Task task) { + boolean caught = false; + try { + task.run(); + } catch (Throwable x) { + if (ex.isAssignableFrom(x.getClass())) { + caught = true; + } else { + throw new RuntimeException(x); + } + } + if (!caught) + throw new RuntimeException(ex.getName() + " expected"); + } + + static void expectNullPointerException(Task task) { + tryCatch(NullPointerException.class, task); + } + + static boolean hasAttribute(UserDefinedFileAttributeView view, String attr) + throws IOException + { + for (String name: view.list()) { + if (name.equals(ATTR_NAME)) + return true; + } + return false; + } + + static void test(Path file, LinkOption... options) throws IOException { + final UserDefinedFileAttributeView view = file + .getFileAttributeView(UserDefinedFileAttributeView.class, options); + ByteBuffer buf = rand.nextBoolean() ? + ByteBuffer.allocate(100) : ByteBuffer.allocateDirect(100); + + // Test: write + buf.put(ATTR_VALUE.getBytes()).flip(); + int size = buf.remaining(); + int nwrote = view.write(ATTR_NAME, buf); + if (nwrote != size) + throw new RuntimeException("Unexpected number of bytes written"); + + // Test: size + if (view.size(ATTR_NAME) != size) + throw new RuntimeException("Unexpected size"); + + // Test: read + buf.clear(); + int nread = view.read(ATTR_NAME, buf); + if (nread != size) + throw new RuntimeException("Unexpected number of bytes read"); + buf.flip(); + String value = Charset.defaultCharset().decode(buf).toString(); + if (!value.equals(ATTR_VALUE)) + throw new RuntimeException("Unexpected attribute value"); + + // Test: read with insufficient space + tryCatch(IOException.class, new Task() { + public void run() throws IOException { + view.read(ATTR_NAME, ByteBuffer.allocateDirect(1)); + }}); + + // Test: replace value + buf.clear(); + buf.put(ATTR_VALUE2.getBytes()).flip(); + size = buf.remaining(); + view.write(ATTR_NAME, buf); + if (view.size(ATTR_NAME) != size) + throw new RuntimeException("Unexpected size"); + + // Test: list + if (!hasAttribute(view, ATTR_NAME)) + throw new RuntimeException("Attribute name not in list"); + + // Test: delete + view.delete(ATTR_NAME); + if (hasAttribute(view, ATTR_NAME)) + throw new RuntimeException("Attribute name in list"); + + // Test: dynamic access + byte[] valueAsBytes = ATTR_VALUE.getBytes(); + view.setAttribute(ATTR_NAME, valueAsBytes); + byte[] actualAsBytes = (byte[])view.getAttribute(ATTR_NAME); + if (!Arrays.equals(valueAsBytes, actualAsBytes)) + throw new RuntimeException("Unexpected attribute value"); + Map<String,?> map = view.readAttributes(ATTR_NAME); + if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME))) + throw new RuntimeException("Unexpected attribute value"); + map = view.readAttributes(ATTR_NAME, "*"); + if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME))) + throw new RuntimeException("Unexpected attribute value"); + map = view.readAttributes("DoesNotExist"); + if (!map.isEmpty()) + throw new RuntimeException("Map expected to be empty"); + } + + static void miscTests(Path file) throws IOException { + final UserDefinedFileAttributeView view = file + .getFileAttributeView(UserDefinedFileAttributeView.class); + view.write(ATTR_NAME, ByteBuffer.wrap(ATTR_VALUE.getBytes())); + + // NullPointerException + final ByteBuffer buf = ByteBuffer.allocate(100); + + expectNullPointerException(new Task() { + public void run() throws IOException { + view.read(null, buf); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.read(ATTR_NAME, null); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.write(null, buf); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.write(ATTR_NAME, null); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.size(null); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.delete(null); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.getAttribute(null); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.setAttribute(ATTR_NAME, null); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.setAttribute(null, new byte[0]); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.readAttributes(null); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.readAttributes("*", (String[])null); + }}); + expectNullPointerException(new Task() { + public void run() throws IOException { + view.readAttributes("*", ATTR_NAME, null); + }}); + + // Read-only buffer + tryCatch(IllegalArgumentException.class, new Task() { + public void run() throws IOException { + ByteBuffer buf = ByteBuffer.wrap(ATTR_VALUE.getBytes()).asReadOnlyBuffer(); + view.write(ATTR_NAME, buf); + buf.flip(); + view.read(ATTR_NAME, buf); + }}); + + // Zero bytes remaining + tryCatch(IOException.class, new Task() { + public void run() throws IOException { + ByteBuffer buf = buf = ByteBuffer.allocateDirect(100); + buf.position(buf.capacity()); + view.read(ATTR_NAME, buf); + }}); + } + + public static void main(String[] args) throws IOException { + // create temporary directory to run tests + Path dir = TestUtil.createTemporaryDirectory(); + try { + if (!dir.getFileStore().supportsFileAttributeView("xattr")) { + System.out.println("UserDefinedFileAttributeView not supported - skip test"); + return; + } + + // test access to user defined attributes of regular file + Path file = dir.resolve("foo.html").createFile(); + try { + test(file); + } finally { + file.delete(); + } + + // test access to user define attributes of directory + file = dir.resolve("foo").createDirectory(); + try { + test(file); + } finally { + file.delete(); + } + + // test access to user defined attributes of sym link + if (TestUtil.supportsLinks(dir)) { + Path target = dir.resolve("doesnotexist"); + Path link = dir.resolve("link").createSymbolicLink(target); + try { + test(link, NOFOLLOW_LINKS); + } catch (IOException x) { + // access to attributes of sym link may not be supported + } finally { + link.delete(); + } + } + + // misc. tests + try { + file = dir.resolve("foo.txt").createFile(); + miscTests(dir); + } finally { + file.delete(); + } + + } finally { + TestUtil.removeAll(dir); + } + } + } diff --git a/jdk/test/java/nio/file/spi/SetDefaultProvider.java b/jdk/test/java/nio/file/spi/SetDefaultProvider.java new file mode 100644 index 00000000000..fa600b05c9b --- /dev/null +++ b/jdk/test/java/nio/file/spi/SetDefaultProvider.java @@ -0,0 +1,44 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4313887 + * @summary Unit test for java.nio.file.spi.FileSystemProvider + * @build TestProvider SetDefaultProvider + * @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider SetDefaultProvider + */ + +import java.nio.file.*; +import java.nio.file.spi.*; + +public class SetDefaultProvider { + public static void main(String[] args) throws Exception { + Class<?> c = FileSystems.getDefault().provider().getClass(); + + Class<?> expected = Class.forName("TestProvider", false, + ClassLoader.getSystemClassLoader()); + + if (c != expected) + throw new RuntimeException(); + } +} diff --git a/jdk/test/java/nio/file/spi/TestProvider.java b/jdk/test/java/nio/file/spi/TestProvider.java new file mode 100644 index 00000000000..a6868acb63c --- /dev/null +++ b/jdk/test/java/nio/file/spi/TestProvider.java @@ -0,0 +1,128 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.file.spi.FileSystemProvider; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.net.URI; +import java.util.*; +import java.io.IOException; + +public class TestProvider extends FileSystemProvider { + + private final FileSystem theFileSystem; + + public TestProvider(FileSystemProvider defaultProvider) { + theFileSystem = new TestFileSystem(this); + + } + + @Override + public String getScheme() { + return "file"; + } + + @Override + public FileSystem newFileSystem(URI uri, Map<String,?> env) { + throw new RuntimeException("not implemented"); + } + + @Override + public FileSystem getFileSystem(URI uri) { + return theFileSystem; + } + + @Override + public Path getPath(URI uri) { + throw new RuntimeException("not implemented"); + } + + static class TestFileSystem extends FileSystem { + private final TestProvider provider; + + TestFileSystem(TestProvider provider) { + this.provider = provider; + } + + @Override + public FileSystemProvider provider() { + return provider; + } + + @Override + public void close() throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public boolean isOpen() { + throw new RuntimeException("not implemented"); + } + + @Override + public boolean isReadOnly() { + throw new RuntimeException("not implemented"); + } + + @Override + public String getSeparator() { + throw new RuntimeException("not implemented"); + } + + @Override + public Iterable<Path> getRootDirectories() { + throw new RuntimeException("not implemented"); + } + + @Override + public Iterable<FileStore> getFileStores() { + throw new RuntimeException("not implemented"); + } + + @Override + public Set<String> supportedFileAttributeViews() { + throw new RuntimeException("not implemented"); + } + + @Override + public Path getPath(String path) { + throw new RuntimeException("not implemented"); + } + + @Override + public PathMatcher getPathMatcher(String syntaxAndPattern) { + throw new RuntimeException("not implemented"); + } + + @Override + public UserPrincipalLookupService getUserPrincipalLookupService() { + throw new RuntimeException("not implemented"); + } + + @Override + public WatchService newWatchService() throws IOException { + throw new RuntimeException("not implemented"); + } + } + +} diff --git a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java index 301c6a66f4c..0faa5ed7ea6 100644 --- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java +++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 6261402 + * @bug 6261402 6824141 * @summary If rmid has an inherited channel that is not a server * socket (such as it if was started using rsh/rcmd), then it should * function normally. @@ -37,6 +37,7 @@ import java.io.IOException; import java.net.Socket; +import java.net.ProtocolFamily; import java.nio.channels.Channel; import java.nio.channels.DatagramChannel; import java.nio.channels.Pipe; @@ -137,6 +138,12 @@ public class InheritedChannelNotServerSocket { return provider.openDatagramChannel(); } + public DatagramChannel openDatagramChannel(ProtocolFamily family) + throws IOException + { + return provider.openDatagramChannel(family); + } + public Pipe openPipe() throws IOException { return provider.openPipe(); } diff --git a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java index c37dd6250c5..79265dd8e4a 100644 --- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java +++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4295885 + * @bug 4295885 6824141 * @summary rmid should be startable from inetd * @author Ann Wollrath * @@ -36,6 +36,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; +import java.net.ProtocolFamily; import java.nio.channels.*; import java.nio.channels.spi.*; import java.rmi.Remote; @@ -126,6 +127,12 @@ public class RmidViaInheritedChannel implements Callback { return provider.openDatagramChannel(); } + public DatagramChannel openDatagramChannel(ProtocolFamily family) + throws IOException + { + return provider.openDatagramChannel(family); + } + public Pipe openPipe() throws IOException { diff --git a/jdk/test/java/security/Permission/ToString.java b/jdk/test/java/security/Permission/ToString.java new file mode 100644 index 00000000000..cf2ffa11dbd --- /dev/null +++ b/jdk/test/java/security/Permission/ToString.java @@ -0,0 +1,101 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6549506 + * @summary Specification of Permission.toString() method contradicts with + * JDK implementation + */ + +import java.security.*; + +public class ToString { + + public static void main(String[]args) throws Exception { + DummyWritePermission dummyPerm = new DummyWritePermission(); + NullActionPermission nullActionPerm = new NullActionPermission(); + System.out.println(dummyPerm.toString()); + System.out.println(dummyPerm.getDescription()); + System.out.println(nullActionPerm.toString()); + System.out.println(nullActionPerm.getDescription()); + if (!dummyPerm.toString().equals(dummyPerm.getDescription())) { + throw new Exception("The expected permission.toString() is " + + dummyPerm.getDescription() + ", but " + + dummyPerm.toString() + " returned!"); + } + + if (!nullActionPerm.toString().equals(nullActionPerm.getDescription())) { + throw new Exception("The expected permission.toString() is " + + nullActionPerm.getDescription() + ", but " + + nullActionPerm.toString() + " returned!"); + } + } + + private static abstract class SimplePermission extends Permission { + public SimplePermission(String name) { + super(name); + } + + public boolean implies(Permission permission) { + return false; + } + + public boolean equals(Object obj) { + return false; + } + + public int hashCode() { + return 13; + } + } + + private static class DummyWritePermission extends SimplePermission { + public DummyWritePermission() { + super("permit to"); + } + + public String getActions() { + return "write"; + } + + public String getDescription() { + return "(\"ToString$DummyWritePermission\" \"permit to\" \"write\")"; + } + } + + private static class NullActionPermission extends SimplePermission { + public NullActionPermission() { + super("permit to"); + } + + public String getActions() { + return null; + } + + public String getDescription() { + return "(\"ToString$NullActionPermission\" \"permit to\")"; + } + } + +} diff --git a/jdk/test/java/security/Security/ClassLoaderDeadlock/CreateSerialized.java b/jdk/test/java/security/Security/ClassLoaderDeadlock/CreateSerialized.java new file mode 100644 index 00000000000..89595ed428e --- /dev/null +++ b/jdk/test/java/security/Security/ClassLoaderDeadlock/CreateSerialized.java @@ -0,0 +1,35 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +import java.io.*; +import sun.misc.*; + +public class CreateSerialized { + public static void main(String[] args) throws Exception { + Object o = new com.sun.crypto.provider.SunJCE(); + + FileOutputStream fos = new FileOutputStream("object.tmp"); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(fos); + objectOutputStream.writeObject(o); + fos.close(); + } +} diff --git a/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.java b/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.java new file mode 100644 index 00000000000..b5938d1de88 --- /dev/null +++ b/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.java @@ -0,0 +1,70 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +import java.io.*; +import javax.xml.parsers.DocumentBuilderFactory; +import java.security.*; + +public class Deadlock2 { + public static void main(String[] args) throws Exception { + File file = new File("object.tmp"); + final byte[] bytes = new byte[(int) file.length()]; + FileInputStream fileInputStream = new FileInputStream(file); + int read = fileInputStream.read(bytes); + if (read != file.length()) { + throw new Exception("Didn't read all"); + } + Thread.sleep(1000); + + Runnable xmlRunnable = new Runnable() { + public void run() { + try { + DocumentBuilderFactory.newInstance(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + Runnable readObjectRunnable = new Runnable() { + public void run() { + try { + ObjectInputStream objectInputStream = + new ObjectInputStream(new ByteArrayInputStream(bytes)); + Object o = objectInputStream.readObject(); + System.out.println(o.getClass()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + Thread thread1 = new Thread(readObjectRunnable, "Read Object"); + Thread thread2 = new Thread(xmlRunnable, "XML"); + + thread1.start(); + thread2.start(); + + thread1.join(); + thread2.join(); + } +} diff --git a/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.sh b/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.sh new file mode 100644 index 00000000000..750e2a7d3a1 --- /dev/null +++ b/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.sh @@ -0,0 +1,99 @@ +#!/bin/sh + +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + + +# @test +# @bug 6440846 +# @summary make sure we do not deadlock between ExtClassLoader and AppClassLoader +# @author Valerie Peng +# @run shell/timeout=20 Deadlock2.sh + +# set a few environment variables so that the shell-script can run stand-alone +# in the source directory + +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi + +if [ "${TESTCLASSES}" = "" ] ; then + TESTCLASSES="." +fi + +if [ "${TESTJAVA}" = "" ] ; then + echo "TESTJAVA not set. Test cannot execute." + echo "FAILED!!!" + exit 1 +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + SunOS ) + PATHSEP=":" + FILESEP="/" + ;; + Linux ) + PATHSEP=":" + FILESEP="/" + ;; + Windows* ) + PATHSEP=";" + FILESEP="\\" + ;; + * ) + echo "Unrecognized system!" + exit 1; + ;; +esac + +# remove old class files +cd ${TESTCLASSES} +rm -f Deadlock2*.class +if [ -d testlib ] ; then + rm -rf testlib +fi +cp -r ${TESTJAVA}${FILESEP}lib${FILESEP}ext testlib + +# compile and package the test program +${TESTJAVA}${FILESEP}bin${FILESEP}javac \ + -d ${TESTCLASSES} \ + ${TESTSRC}${FILESEP}CreateSerialized.java \ + ${TESTSRC}${FILESEP}Deadlock2.java + +${TESTJAVA}${FILESEP}bin${FILESEP}jar \ + -cvf testlib${FILESEP}Deadlock2.jar \ + Deadlock2*.class + +rm Deadlock2*.class + +# create serialized object and run the test +${TESTJAVA}${FILESEP}bin${FILESEP}java CreateSerialized +${TESTJAVA}${FILESEP}bin${FILESEP}java -Djava.ext.dirs=${TESTCLASSES}${FILESEP}testlib Deadlock2 +STATUS=$? + +# clean up +rm object.tmp CreateSerialized.class +rm -rf testlib +exit ${STATUS} diff --git a/jdk/test/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java b/jdk/test/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java new file mode 100644 index 00000000000..56367cd2ae3 --- /dev/null +++ b/jdk/test/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java @@ -0,0 +1,265 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6383095 + * @summary CRL revoked certificate failures masked by OCSP failures + * + * Note that the certificate validity is from Mar 16 14:55:35 2009 GMT to + * Dec 1 14:55:35 2028 GMT, please update it with newer certificate if + * expires. + * + * @author Xuelei Fan + */ + +/* + * Certificates used in the test. + * + * end entity certificate: + * Data: + * Version: 3 (0x2) + * Serial Number: 25 (0x19) + * Signature Algorithm: md5WithRSAEncryption + * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Mar 16 14:55:35 2009 GMT + * Not After : Dec 1 14:55:35 2028 GMT + * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, + * CN=localhost + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * RSA Public Key: (1024 bit) + * Modulus (1024 bit): + * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: + * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: + * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: + * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: + * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: + * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: + * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: + * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: + * 75:8d:f5:82:ac:43:92:44:1b + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Basic Constraints: + * CA:FALSE + * X509v3 Key Usage: + * Digital Signature, Non Repudiation, Key Encipherment + * X509v3 Subject Key Identifier: + * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 + * X509v3 Authority Key Identifier: + * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 + * Signature Algorithm: md5WithRSAEncryption + * + * + * trusted certificate authority: + * Data: + * Version: 3 (0x2) + * Serial Number: 0 (0x0) + * Signature Algorithm: md5WithRSAEncryption + * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Dec 8 02:43:36 2008 GMT + * Not After : Aug 25 02:43:36 2028 GMT + * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * RSA Public Key: (1024 bit) + * Modulus (1024 bit): + * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: + * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: + * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: + * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: + * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: + * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: + * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: + * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: + * 89:2a:95:12:4c:d8:09:2a:e9 + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Subject Key Identifier: + * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 + * X509v3 Authority Key Identifier: + * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 + * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org + * X509v3 Basic Constraints: + * CA:TRUE + * Signature Algorithm: md5WithRSAEncryption + * + * CRL: + * Certificate Revocation List (CRL): + * Version 2 (0x1) + * Signature Algorithm: md5WithRSAEncryption + * Issuer: /C=US/ST=Some-State/L=Some-City/O=Some-Org + * Last Update: Mar 16 16:27:14 2009 GMT + * Next Update: May 15 16:27:14 2028 GMT + * CRL extensions: + * X509v3 CRL Number: + * 2 + * Revoked Certificates: + * Serial Number: 19 + * Revocation Date: Mar 16 16:22:08 2009 GMT + * CRL entry extensions: + * X509v3 CRL Reason Code: + * Superseded + * Signature Algorithm: md5WithRSAEncryption + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; +import java.security.InvalidAlgorithmParameterException; +import java.security.cert.CertPathValidatorException.BasicReason; + +public class FailoverToCRL { + + static String trusedCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + + "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + + "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + + "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + + "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + + "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + + "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + + "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + + "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + + "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + + "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + + "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + + "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + + "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + + "6Mvf0r1PNTY2hwTJLJmKtg==\n" + + "-----END CERTIFICATE-----"; + + static String targetCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIICizCCAfSgAwIBAgIBGTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + + "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + + "EwhTb21lLU9yZzAeFw0wOTAzMTYxNDU1MzVaFw0yODEyMDExNDU1MzVaMHIxCzAJ\n" + + "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + + "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + + "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + + "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + + "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + + "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjWjBYMAkGA1UdEwQCMAAw\n" + + "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + + "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDANBgkqhkiG9w0BAQQFAAOBgQBv\n" + + "p7JjCDOrMBNun46xs4Gz7Y4ygM5VHaFP0oO7369twvRSu0pCuIdZd5OIMPFeRqQw\n" + + "PA68ZdhYVR0pG5W7isV+jB+Dfge/IOgOA85sZ/6FlP3PBRW+YMQKKdRr5So3ook9\n" + + "PimQ7rbxRAofPECv20IUKFBbOUkU+gFcn+WbTKYxBw==\n" + + "-----END CERTIFICATE-----"; + + static String crlStr = + "-----BEGIN X509 CRL-----\n" + + "MIIBRTCBrwIBATANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzETMBEGA1UE\n" + + "CBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQKEwhTb21l\n" + + "LU9yZxcNMDkwMzE2MTYyNzE0WhcNMjgwNTE1MTYyNzE0WjAiMCACARkXDTA5MDMx\n" + + "NjE2MjIwOFowDDAKBgNVHRUEAwoBBKAOMAwwCgYDVR0UBAMCAQIwDQYJKoZIhvcN\n" + + "AQEEBQADgYEAMixJI9vBwYpOGosn46+T/MTEtlm2S5pIVT/xPDrHkCPfw8l4Zrgp\n" + + "dGPuUkglWdrGdxY9MNRUj2YFNfdZi6zZ7JF6XbkDHYOAKYgPDJRjS/0VcBntn5RJ\n" + + "sQfZsBqc9fFSP8gknRRn3LT41kr9xNRxTT1t3YYjv7J3zkMYyInqeUA=\n" + + "-----END X509 CRL-----"; + + + private static CertPath generateCertificatePath() + throws CertificateException { + // generate certificate from cert strings + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is = + new ByteArrayInputStream(targetCertStr.getBytes()); + Certificate targetCert = cf.generateCertificate(is); + + // generate certification path + List<Certificate> list = Arrays.asList(new Certificate[] {targetCert}); + + return cf.generateCertPath(list); + } + + private static Set<TrustAnchor> generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is = + new ByteArrayInputStream(trusedCertStr.getBytes()); + Certificate trusedCert = cf.generateCertificate(is); + + // generate a trust anchor + TrustAnchor anchor = new TrustAnchor((X509Certificate)trusedCert, null); + + return Collections.singleton(anchor); + } + + private static CertStore generateCertificateStore() throws Exception { + // generate CRL from CRL string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is = + new ByteArrayInputStream(crlStr.getBytes()); + + // generate a cert store + Collection<? extends CRL> crls = cf.generateCRLs(is); + return CertStore.getInstance("Collection", + new CollectionCertStoreParameters(crls)); + } + + public static void main(String args[]) throws Exception { + CertPath path = generateCertificatePath(); + Set<TrustAnchor> anchors = generateTrustAnchors(); + CertStore crls = generateCertificateStore(); + + PKIXParameters params = new PKIXParameters(anchors); + + // add the CRL store + params.addCertStore(crls); + + // Activate certificate revocation checking + params.setRevocationEnabled(true); + + // Activate OCSP + Security.setProperty("ocsp.enable", "true"); + System.setProperty("com.sun.security.enableCRLDP", "true"); + + // Ensure that the ocsp.responderURL property is not set. + if (Security.getProperty("ocsp.responderURL") != null) { + throw new + Exception("The ocsp.responderURL property must not be set"); + } + + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + + try { + validator.validate(path, params); + } catch (CertPathValidatorException cpve) { + if (cpve.getReason() != BasicReason.REVOKED) { + throw new Exception( + "unexpect exception, should be a REVOKED CPVE", cpve); + } + } + } +} diff --git a/jdk/test/java/security/cert/CertificateFactory/BadX509CertData.java b/jdk/test/java/security/cert/CertificateFactory/BadX509CertData.java index 6141afd9ade..87f81314578 100644 --- a/jdk/test/java/security/cert/CertificateFactory/BadX509CertData.java +++ b/jdk/test/java/security/cert/CertificateFactory/BadX509CertData.java @@ -1,5 +1,5 @@ /* - * Copyright 2000 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ public class BadX509CertData { InputStream is = new ByteArrayInputStream(data.getBytes("ISO8859_1")); try { Certificate cert = factory.generateCertificate(is); - } catch (CertificateParsingException ce) { + } catch (CertificateException ce) { return; } throw new Exception("CertificateFactory.generateCertificate() did " diff --git a/jdk/test/java/security/cert/CertificateFactory/openssl/OpenSSLCert.java b/jdk/test/java/security/cert/CertificateFactory/openssl/OpenSSLCert.java new file mode 100644 index 00000000000..5ea5b0bade1 --- /dev/null +++ b/jdk/test/java/security/cert/CertificateFactory/openssl/OpenSSLCert.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test + * @bug 6535697 + * @summary keytool can be more flexible on format of PEM-encoded + * X.509 certificates + */ + +import java.io.*; +import java.util.Arrays; +import java.security.cert.CertificateFactory; + +public class OpenSSLCert { + static final String OUTFILE = "6535697.test"; + + public static void main(String[] args) throws Exception { + test("open"); + test("pem"); + test("open", "open"); + test("open", "pem"); + test("pem", "pem"); + test("pem", "open"); + test("open", "pem", "open"); + test("pem", "open", "pem"); + } + + static void test(String... files) throws Exception { + FileOutputStream fout = new FileOutputStream(OUTFILE); + for (String file: files) { + FileInputStream fin = new FileInputStream( + new File(System.getProperty("test.src", "."), file)); + byte[] buffer = new byte[4096]; + while (true) { + int len = fin.read(buffer); + if (len < 0) break; + fout.write(buffer, 0, len); + } + fin.close(); + } + fout.close(); + System.out.println("Testing " + Arrays.toString(files) + "..."); + if (CertificateFactory.getInstance("X509") + .generateCertificates(new FileInputStream(OUTFILE)) + .size() != files.length) { + throw new Exception("Not same number"); + } + } +} diff --git a/jdk/test/java/security/cert/CertificateFactory/openssl/open b/jdk/test/java/security/cert/CertificateFactory/openssl/open new file mode 100644 index 00000000000..c9b0d5e5aa0 --- /dev/null +++ b/jdk/test/java/security/cert/CertificateFactory/openssl/open @@ -0,0 +1,72 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1174535938 (0x4601ff02) + Signature Algorithm: dsaWithSHA1 + Issuer: C=EA, ST=Moon, L=Backside, O=A-B-C, OU=Office, CN=Me + Validity + Not Before: Mar 22 03:58:58 2007 GMT + Not After : Jun 20 03:58:58 2007 GMT + Subject: C=EA, ST=Moon, L=Backside, O=A-B-C, OU=Office, CN=Me + Subject Public Key Info: + Public Key Algorithm: dsaEncryption + DSA Public Key: + pub: + 00:c5:ce:e8:be:f0:de:27:9c:88:92:21:28:cf:a5: + 38:8d:c1:5f:e5:90:d2:0b:ea:d4:12:ca:86:b8:04: + 57:1d:41:74:3e:52:2d:87:b8:76:7b:d2:95:d7:67: + 30:76:35:47:fb:e9:86:bf:05:3f:9b:f2:6e:3a:96: + 9a:58:e1:05:44:78:02:31:ee:5f:67:6c:44:d2:95: + 8f:72:62:a4:3e:27:1c:f3:94:8a:1e:0b:98:4c:c0: + 9c:f4:3d:17:6d:36:e4:a0:12:04:01:e4:38:9e:bd: + 86:99:7b:84:43:9b:58:68:ef:ce:3d:85:e3:93:d1: + 1f:1a:18:a4:1e:59:ca:80:2e + P: + 00:fd:7f:53:81:1d:75:12:29:52:df:4a:9c:2e:ec: + e4:e7:f6:11:b7:52:3c:ef:44:00:c3:1e:3f:80:b6: + 51:26:69:45:5d:40:22:51:fb:59:3d:8d:58:fa:bf: + c5:f5:ba:30:f6:cb:9b:55:6c:d7:81:3b:80:1d:34: + 6f:f2:66:60:b7:6b:99:50:a5:a4:9f:9f:e8:04:7b: + 10:22:c2:4f:bb:a9:d7:fe:b7:c6:1b:f8:3b:57:e7: + c6:a8:a6:15:0f:04:fb:83:f6:d3:c5:1e:c3:02:35: + 54:13:5a:16:91:32:f6:75:f3:ae:2b:61:d7:2a:ef: + f2:22:03:19:9d:d1:48:01:c7 + Q: + 00:97:60:50:8f:15:23:0b:cc:b2:92:b9:82:a2:eb: + 84:0b:f0:58:1c:f5 + G: + 00:f7:e1:a0:85:d6:9b:3d:de:cb:bc:ab:5c:36:b8: + 57:b9:79:94:af:bb:fa:3a:ea:82:f9:57:4c:0b:3d: + 07:82:67:51:59:57:8e:ba:d4:59:4f:e6:71:07:10: + 81:80:b4:49:16:71:23:e8:4c:28:16:13:b7:cf:09: + 32:8c:c8:a6:e1:3c:16:7a:8b:54:7c:8d:28:e0:a3: + ae:1e:2b:b3:a6:75:91:6e:a3:7f:0b:fa:21:35:62: + f1:fb:62:7a:01:24:3b:cc:a4:f1:be:a8:51:90:89: + a8:83:df:e1:5a:e5:9f:06:92:8b:66:5e:80:7b:55: + 25:64:01:4c:3b:fe:cf:49:2a + X509v3 extensions: + X509v3 Subject Key Identifier: + ED:BF:8A:CA:57:05:ED:5C:9A:72:65:69:6C:C1:02:F8:30:02:A4:6B + Signature Algorithm: dsaWithSHA1 + 30:2d:02:15:00:85:38:a6:79:d4:70:c8:e1:d8:25:2f:87:f0: + 74:3d:26:59:4c:71:ef:02:14:15:32:10:1d:c0:d1:ce:18:f4: + 8b:ea:c0:8b:d7:da:ba:52:3a:0d:f7 +-----BEGIN CERTIFICATE----- +MIIDGDCCAtWgAwIBAgIERgH/AjALBgcqhkjOOAQDBQAwXTELMAkGA1UEBhMCRUEx +DTALBgNVBAgTBE1vb24xETAPBgNVBAcTCEJhY2tzaWRlMQ4wDAYDVQQKEwVBLUIt +QzEPMA0GA1UECxMGT2ZmaWNlMQswCQYDVQQDEwJNZTAeFw0wNzAzMjIwMzU4NTha +Fw0wNzA2MjAwMzU4NThaMF0xCzAJBgNVBAYTAkVBMQ0wCwYDVQQIEwRNb29uMREw +DwYDVQQHEwhCYWNrc2lkZTEOMAwGA1UEChMFQS1CLUMxDzANBgNVBAsTBk9mZmlj +ZTELMAkGA1UEAxMCTWUwggG4MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS +30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuA +HTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVU +E1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKB +gQD34aCF1ps93su8q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGA +tEkWcSPoTCgWE7fPCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoB +JDvMpPG+qFGQiaiD3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhQACgYEAxc7ovvDe +J5yIkiEoz6U4jcFf5ZDSC+rUEsqGuARXHUF0PlIth7h2e9KV12cwdjVH++mGvwU/ +m/JuOpaaWOEFRHgCMe5fZ2xE0pWPcmKkPicc85SKHguYTMCc9D0XbTbkoBIEAeQ4 +nr2GmXuEQ5tYaO/OPYXjk9EfGhikHlnKgC6jITAfMB0GA1UdDgQWBBTtv4rKVwXt +XJpyZWlswQL4MAKkazALBgcqhkjOOAQDBQADMAAwLQIVAIU4pnnUcMjh2CUvh/B0 +PSZZTHHvAhQVMhAdwNHOGPSL6sCL19q6UjoN9w== +-----END CERTIFICATE----- diff --git a/jdk/test/java/security/cert/CertificateFactory/openssl/pem b/jdk/test/java/security/cert/CertificateFactory/openssl/pem new file mode 100644 index 00000000000..8601bf37256 --- /dev/null +++ b/jdk/test/java/security/cert/CertificateFactory/openssl/pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIDGDCCAtWgAwIBAgIERgH/AjALBgcqhkjOOAQDBQAwXTELMAkGA1UEBhMCRUExDTALBgNVBAgT +BE1vb24xETAPBgNVBAcTCEJhY2tzaWRlMQ4wDAYDVQQKEwVBLUItQzEPMA0GA1UECxMGT2ZmaWNl +MQswCQYDVQQDEwJNZTAeFw0wNzAzMjIwMzU4NThaFw0wNzA2MjAwMzU4NThaMF0xCzAJBgNVBAYT +AkVBMQ0wCwYDVQQIEwRNb29uMREwDwYDVQQHEwhCYWNrc2lkZTEOMAwGA1UEChMFQS1CLUMxDzAN +BgNVBAsTBk9mZmljZTELMAkGA1UEAxMCTWUwggG4MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11 +EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZg +t2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/y +IgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgQD34aCF1ps93su8q1w2uFe5eZSvu/o6 +6oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fPCTKMyKbhPBZ6i1R8jSjgo64eK7Om +dZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhQACgYEA +xc7ovvDeJ5yIkiEoz6U4jcFf5ZDSC+rUEsqGuARXHUF0PlIth7h2e9KV12cwdjVH++mGvwU/m/Ju +OpaaWOEFRHgCMe5fZ2xE0pWPcmKkPicc85SKHguYTMCc9D0XbTbkoBIEAeQ4nr2GmXuEQ5tYaO/O +PYXjk9EfGhikHlnKgC6jITAfMB0GA1UdDgQWBBTtv4rKVwXtXJpyZWlswQL4MAKkazALBgcqhkjO +OAQDBQADMAAwLQIVAIU4pnnUcMjh2CUvh/B0PSZZTHHvAhQVMhAdwNHOGPSL6sCL19q6UjoN9w== +-----END CERTIFICATE----- diff --git a/jdk/test/java/util/Collection/MOAT.java b/jdk/test/java/util/Collection/MOAT.java index 0dd89f35500..f9d30f56217 100644 --- a/jdk/test/java/util/Collection/MOAT.java +++ b/jdk/test/java/util/Collection/MOAT.java @@ -555,6 +555,7 @@ public class MOAT { NavigableMap<Integer,Integer> nm = (NavigableMap<Integer,Integer>) m; + testNavigableMapRemovers(nm); testNavigableMap(nm); testNavigableMap(nm.headMap(6, false)); testNavigableMap(nm.headMap(5, true)); @@ -742,6 +743,97 @@ public class MOAT { equal(it.next(), expected); } + static void equalMaps(Map m1, Map m2) { + equal(m1, m2); + equal(m2, m1); + equal(m1.size(), m2.size()); + equal(m1.isEmpty(), m2.isEmpty()); + equal(m1.toString(), m2.toString()); + check(Arrays.equals(m1.entrySet().toArray(), m2.entrySet().toArray())); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + static void testNavigableMapRemovers(NavigableMap m) + { + final Map emptyMap = new HashMap(); + + final Map singletonMap = new HashMap(); + singletonMap.put(1, 2); + + abstract class NavigableMapView { + abstract NavigableMap view(NavigableMap m); + } + + NavigableMapView[] views = { + new NavigableMapView() { NavigableMap view(NavigableMap m) { + return m; }}, + new NavigableMapView() { NavigableMap view(NavigableMap m) { + return m.headMap(99, true); }}, + new NavigableMapView() { NavigableMap view(NavigableMap m) { + return m.tailMap(-99, false); }}, + new NavigableMapView() { NavigableMap view(NavigableMap m) { + return m.subMap(-99, true, 99, false); }}, + }; + + abstract class Remover { + abstract void remove(NavigableMap m, Object k, Object v); + } + + Remover[] removers = { + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.remove(k), v); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.descendingMap().remove(k), v); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.descendingMap().headMap(-86, false).remove(k), v); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.descendingMap().tailMap(86, true).remove(k), v); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.headMap(86, true).remove(k), v); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.tailMap(-86, true).remove(k), v); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.subMap(-86, false, 86, true).remove(k), v); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.keySet().remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.navigableKeySet().remove(k)); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.navigableKeySet().headSet(86, true).remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.navigableKeySet().tailSet(-86, false).remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.navigableKeySet().subSet(-86, true, 86, false) + .remove(k)); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.descendingKeySet().headSet(-86, false).remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.descendingKeySet().tailSet(86, true).remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.descendingKeySet().subSet(86, true, -86, false) + .remove(k)); }}, + }; + + for (NavigableMapView view : views) { + for (Remover remover : removers) { + try { + m.clear(); + equalMaps(m, emptyMap); + equal(m.put(1, 2), null); + equalMaps(m, singletonMap); + NavigableMap v = view.view(m); + remover.remove(v, 1, 2); + equalMaps(m, emptyMap); + } catch (Throwable t) { unexpected(t); } + } + } + } + private static void testNavigableMap(NavigableMap<Integer,Integer> m) { clear(m); diff --git a/jdk/test/java/util/concurrent/Semaphore/RacingReleases.java b/jdk/test/java/util/concurrent/Semaphore/RacingReleases.java new file mode 100644 index 00000000000..c1c573f443f --- /dev/null +++ b/jdk/test/java/util/concurrent/Semaphore/RacingReleases.java @@ -0,0 +1,116 @@ +/* + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6801020 6803402 + * @summary Try to tickle race conditions in + * AbstractQueuedSynchronizer "shared" code + */ + +import java.util.concurrent.Semaphore; + +public class RacingReleases { + + /** Increase this for better chance of tickling races */ + static final int iterations = 1000; + + public static void test(final boolean fair, + final boolean interruptibly) + throws Throwable { + for (int i = 0; i < iterations; i++) { + final Semaphore sem = new Semaphore(0, fair); + final Throwable[] badness = new Throwable[1]; + Runnable blocker = interruptibly ? + new Runnable() { + public void run() { + try { + sem.acquire(); + } catch (Throwable t) { + badness[0] = t; + throw new Error(t); + }}} + : + new Runnable() { + public void run() { + try { + sem.acquireUninterruptibly(); + } catch (Throwable t) { + badness[0] = t; + throw new Error(t); + }}}; + + Thread b1 = new Thread(blocker); + Thread b2 = new Thread(blocker); + Runnable signaller = new Runnable() { + public void run() { + try { + sem.release(); + } catch (Throwable t) { + badness[0] = t; + throw new Error(t); + }}}; + Thread s1 = new Thread(signaller); + Thread s2 = new Thread(signaller); + Thread[] threads = { b1, b2, s1, s2 }; + java.util.Collections.shuffle(java.util.Arrays.asList(threads)); + for (Thread thread : threads) + thread.start(); + for (Thread thread : threads) { + thread.join(60 * 1000); + if (thread.isAlive()) + throw new Error + (String.format + ("Semaphore stuck: permits %d, thread waiting %s%n", + sem.availablePermits(), + sem.hasQueuedThreads() ? "true" : "false")); + } + if (badness[0] != null) + throw new Error(badness[0]); + if (sem.availablePermits() != 0) + throw new Error(String.valueOf(sem.availablePermits())); + if (sem.hasQueuedThreads()) + throw new Error(String.valueOf(sem.hasQueuedThreads())); + if (sem.getQueueLength() != 0) + throw new Error(String.valueOf(sem.getQueueLength())); + if (sem.isFair() != fair) + throw new Error(String.valueOf(sem.isFair())); + } + } + + public static void main(String[] args) throws Throwable { + for (boolean fair : new boolean[] { true, false }) + for (boolean interruptibly : new boolean[] { true, false }) + test(fair, interruptibly); + } +} diff --git a/jdk/test/java/util/concurrent/TimeUnit/Basic.java b/jdk/test/java/util/concurrent/TimeUnit/Basic.java index 7a956410231..bae284d6c88 100644 --- a/jdk/test/java/util/concurrent/TimeUnit/Basic.java +++ b/jdk/test/java/util/concurrent/TimeUnit/Basic.java @@ -60,10 +60,11 @@ public class Basic { equal(1000L, MICROSECONDS.toNanos(1)); long t0 = System.nanoTime(); - MILLISECONDS.sleep(3); + MILLISECONDS.sleep(3); /* See windows bug 6313903, might not sleep */ long elapsedMillis = (System.nanoTime() - t0)/(1000L * 1000L); System.out.printf("elapsed=%d%n", elapsedMillis); - check(elapsedMillis >= 3); + check(elapsedMillis >= 0); + /* Might not sleep on windows: check(elapsedMillis >= 3); */ check(elapsedMillis < 1000); //---------------------------------------------------------------- diff --git a/jdk/test/java/util/logging/ClassLoaderLeakTest.java b/jdk/test/java/util/logging/ClassLoaderLeakTest.java new file mode 100644 index 00000000000..988041472fc --- /dev/null +++ b/jdk/test/java/util/logging/ClassLoaderLeakTest.java @@ -0,0 +1,190 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6799583 + * + * @summary Test verifes that LogManager shutdown hook does not cause + * an application classloader leaks. + * + * @run main/othervm ClassLoaderLeakTest + */ + +import java.io.File; +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.concurrent.CountDownLatch; +import java.util.logging.Logger; +import java.util.logging.Logger; + +public class ClassLoaderLeakTest { + + private static CountDownLatch doneSignal; + private static CountDownLatch launchSignal; + private static ThreadGroup appsThreadGroup; + private static Throwable launchFailure = null; + + public static void main(String[] args) { + appsThreadGroup = new ThreadGroup("MyAppsThreadGroup"); + doneSignal = new CountDownLatch(1); + launchSignal = new CountDownLatch(1); + + Runnable launcher = new Runnable() { + public void run() { + try { + ClassLoader cl = + Thread.currentThread().getContextClassLoader(); + Class appMain = cl.loadClass("AppTest"); + Method launch = + appMain.getDeclaredMethod("launch", doneSignal.getClass()); + + Constructor c = appMain.getConstructor(); + + Object o = c.newInstance(); + + launch.invoke(o, doneSignal); + + } catch (Throwable e) { + launchFailure = e; + } finally { + launchSignal.countDown(); + } + } + }; + + /* prepare test class loader */ + URL pwd = null; + try { + + pwd = new File(System.getProperty("test.classes",".")).toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException("Test failed.", e); + } + URL[] urls = new URL[] { pwd }; + + MyClassLoader appClassLoader = new MyClassLoader(urls, "test0"); + WeakReference<MyClassLoader> ref = + new WeakReference<MyClassLoader>(appClassLoader); + + + Thread appThread = new Thread(appsThreadGroup, launcher, "AppThread-0"); + appThread.setContextClassLoader(appClassLoader); + + appThread.start(); + appClassLoader = null; + launcher = null; + appThread = null; + + /* wait for laucnh completion */ + try { + launchSignal.await(); + } catch (InterruptedException e) { + } + + /* check if launch failed */ + if (launchFailure != null) { + throw new RuntimeException("Test failed.", launchFailure); + } + + /* wait for test app excution completion */ + try { + doneSignal.await(); + } catch (InterruptedException e) { + } + + /* give a chence to GC */ + waitAndGC(5); + + if (ref.get() != null) { + throw new RuntimeException("Test failed: classloader is still alive"); + } + + System.out.println("Test passed."); + } + + private static class MyClassLoader extends URLClassLoader { + + private static boolean verbose = + Boolean.getBoolean("verboseClassLoading"); + private String uniqClassName; + + public MyClassLoader(URL[] urls, String uniq) { + super(urls); + + uniqClassName = uniq; + } + + public Class loadClass(String name) throws ClassNotFoundException { + if (verbose) { + System.out.printf("%s: load class %s\n", uniqClassName, name); + } + if (uniqClassName.equals(name)) { + return Object.class; + } + return super.loadClass(name); + } + + public String toString() { + return "MyClassLoader(" + uniqClassName + ")"; + } + } + + private static void waitAndGC(int sec) { + int cnt = sec; + System.out.print("Wait "); + while (cnt-- > 0) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + // do GC every 3 seconds + if (cnt % 3 == 2) { + System.gc(); + System.out.print("+"); + } else { + System.out.print("."); + } + //checkErrors(); + } + System.out.println(""); + } +} + + +class AppTest { + public AppTest() { + + } + + public void launch(CountDownLatch done) { + Logger log = Logger.getLogger("app_test_logger"); + log.fine("Test app is launched"); + + done.countDown(); + } +} diff --git a/jdk/test/java/util/logging/LoggingDeadlock2.java b/jdk/test/java/util/logging/LoggingDeadlock2.java index 47831935226..50de62abfcc 100644 --- a/jdk/test/java/util/logging/LoggingDeadlock2.java +++ b/jdk/test/java/util/logging/LoggingDeadlock2.java @@ -24,7 +24,7 @@ /* * @test * @bug 6467152 - * + * @ignore until 6716076 is fixed * @summary deadlock occurs in LogManager initialization and JVM termination * @author Serguei Spitsyn / Hittachi * diff --git a/jdk/test/java/util/regex/BMPTestCases.txt b/jdk/test/java/util/regex/BMPTestCases.txt new file mode 100644 index 00000000000..c50f49628e3 --- /dev/null +++ b/jdk/test/java/util/regex/BMPTestCases.txt @@ -0,0 +1,951 @@ +// +// Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +// CA 95054 USA or visit www.sun.com if you need additional information or +// have any questions. +// +// +// This file contains test cases with BMP characters for regular expressions. +// A test case consists of three lines: +// The first line is a pattern used in the test +// The second line is the input to search for the pattern in +// The third line is a concatentation of the match, the number of groups, +// and the contents of the first four subexpressions. +// Empty lines and lines beginning with comment slashes are ignored. + +// Test unsetting of backed off groups +^(\u3042)?\u3042 +\u3042 +true \u3042 1 + +^(\u3042\u3042(\u3043\u3043)?)+$ +\u3042\u3042\u3043\u3043\u3042\u3042 +true \u3042\u3042\u3043\u3043\u3042\u3042 2 \u3042\u3042 \u3043\u3043 + +((\u3042|\u3043)?\u3043)+ +\u3043 +true \u3043 2 \u3043 + +(\u3042\u3042\u3042)?\u3042\u3042\u3042 +\u3042\u3042\u3042 +true \u3042\u3042\u3042 1 + +^(\u3042(\u3043)?)+$ +\u3042\u3043\u3042 +true \u3042\u3043\u3042 2 \u3042 \u3043 + +^(\u3042(\u3043(\u3044)?)?)?\u3042\u3043\u3044 +\u3042\u3043\u3044 +true \u3042\u3043\u3044 3 + +^(\u3042(\u3043(\u3044))).* +\u3042\u3043\u3044 +true \u3042\u3043\u3044 3 \u3042\u3043\u3044 \u3043\u3044 \u3044 + +// use of x modifier +\u3042\u3043\u3044(?x)\u3043la\u3049 +\u3042\u3043\u3044\u3043la\u3049 +true \u3042\u3043\u3044\u3043la\u3049 0 + +\u3042\u3043\u3044(?x) bla\u3049 +\u3042\u3043\u3044bla\u3049 +true \u3042\u3043\u3044bla\u3049 0 + +\u3042\u3043\u3044(?x) bla\u3049 ble\u3044\u3049 +\u3042\u3043\u3044bla\u3049ble\u3044\u3049 +true \u3042\u3043\u3044bla\u3049ble\u3044\u3049 0 + +\u3042\u3043\u3044(?x) bla\u3049 # ignore comment +\u3042\u3043\u3044bla\u3049 +true \u3042\u3043\u3044bla\u3049 0 + +// Simple alternation +\u3042|\u3043 +\u3042 +true \u3042 0 + +\u3042|\u3043 +\u305B +false 0 + +\u3042|\u3043 +\u3043 +true \u3043 0 + +\u3042|\u3043|\u3044\u3045 +\u3044\u3045 +true \u3044\u3045 0 + +\u3042|\u3042\u3045 +\u3042\u3045 +true \u3042 0 + +\u305B(\u3042|\u3042\u3044)\u3043 +\u305B\u3042\u3044\u3043 +true \u305B\u3042\u3044\u3043 1 \u3042\u3044 + +// Simple char class +[\u3042\u3043\u3044]+ +\u3042\u3043\u3042\u3043\u3042\u3043 +true \u3042\u3043\u3042\u3043\u3042\u3043 0 + +[\u3042\u3043\u3044]+ +\u3045\u3046\u3047\u3048 +false 0 + +[\u3042\u3043\u3044]+[\u3045\u3046\u3047]+[\u3048\u3049\u304A]+ +\u305B\u305B\u305B\u3042\u3042\u3045\u3045\u3048\u3048\u305B\u305B\u305B +true \u3042\u3042\u3045\u3045\u3048\u3048 0 + +// Range char class +[\u3042-\u3048]+ +\u305B\u305B\u305B\u3048\u3048\u3048 +true \u3048\u3048\u3048 0 + +[\u3042-\u3048]+ +mmm +false 0 + +[\u3042-]+ +\u305B\u3042-9\u305B +true \u3042- 0 + +[\u3042-\\u4444]+ +\u305B\u3042-9\u305B +true \u305B\u3042 0 + +// Negated char class +[^\u3042\u3043\u3044]+ +\u3042\u3043\u3042\u3043\u3042\u3043 +false 0 + +[^\u3042\u3043\u3044]+ +\u3042\u3042\u3042\u3043\u3043\u3043\u3044\u3044\u3044\u3045\u3046\u3047\u3048 +true \u3045\u3046\u3047\u3048 0 + +// Making sure a ^ not in first position matches literal ^ +[\u3042\u3043\u3044^\u3043] +\u3043 +true \u3043 0 + +[\u3042\u3043\u3044^\u3043] +^ +true ^ 0 + +// Class union and intersection +[\u3042\u3043\u3044[\u3045\u3046\u3047]] +\u3043 +true \u3043 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]] +\u3046 +true \u3046 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +\u3042 +true \u3042 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +\u3050 +true \u3050 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +4 +true 4 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +\u3046 +false 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +\u3056 +false 0 + +[[\u3042-\u3045][0-9][\u304e-\u3051]] +\u3043 +true \u3043 0 + +[[\u3042-\u3045][0-9][\u304e-\u3051]] +\u305B +false 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]] +\u3042 +true \u3042 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]] +\u3046 +true \u3046 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]] +\u3049 +true \u3049 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]] +m +false 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]m] +m +true m 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]\u3048\u3049\u304A] +\u3042 +true \u3042 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]\u3048\u3049\u304A] +\u3045 +true \u3045 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]\u3048\u3049\u304A] +\u3049 +true \u3049 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]\u3048\u3049\u304A] +w +false 0 + +[\u3042-\u3044&&[\u3045-\u3047]] +\u3042 +false 0 + +[\u3042-\u3044&&[\u3045-\u3047]] +\u3046 +false 0 + +[\u3042-\u3044&&[\u3045-\u3047]] +\u305B +false 0 + +[[\u3042-\u3044]&&[\u3045-\u3047]] +\u3042 +false 0 + +[[\u3042-\u3044]&&[\u3045-\u3047]] +\u3046 +false 0 + +[[\u3042-\u3044]&&[\u3045-\u3047]] +\u305B +false 0 + +[\u3042-\u3044&&\u3045-\u3047] +\u3042 +false 0 + +[\u3042-\u304e&&\u304e-\u305B] +\u304e +true \u304e 0 + +[\u3042-\u304e&&\u304e-\u305B&&\u3042-\u3044] +\u304e +false 0 + +[\u3042-\u304e&&\u304e-\u305B&&\u3042-\u305B] +\u304e +true \u304e 0 + +[[\u3042-\u304e]&&[\u304e-\u305B]] +\u3042 +false 0 + +[[\u3042-\u304e]&&[\u304e-\u305B]] +\u304e +true \u304e 0 + +[[\u3042-\u304e]&&[\u304e-\u305B]] +\u305B +false 0 + +[[\u3042-\u304e]&&[^\u3042-\u3044]] +\u3042 +false 0 + +[[\u3042-\u304e]&&[^\u3042-\u3044]] +\u3045 +true \u3045 0 + +[\u3042-\u304e&&[^\u3042-\u3044]] +\u3042 +false 0 + +[\u3042-\u304e&&[^\u3042-\u3044]] +\u3045 +true \u3045 0 + +[\u3042-\u3044\u3045-\u3047&&[\u3045-\u3047]] +\u3042 +false 0 + +[\u3042-\u3044\u3045-\u3047&&[\u3045-\u3047]] +\u3046 +true \u3046 0 + +[[\u3042-\u3044]&&\u3045-\u3047\u3042-\u3044] +\u3042 +true \u3042 0 + +[[\u3042-\u3044]&&[\u3045-\u3047][\u3042-\u3044]] +\u3042 +true \u3042 0 + +[[\u3042-\u3044][\u3045-\u3047]&&\u3042\u3043\u3044] +\u3042 +true \u3042 0 + +[[\u3042-\u3044][\u3045-\u3047]&&\u3042\u3043\u3044[\u3045\u3046\u3047]] +\u3046 +true \u3046 0 + +[[\u3042-\u3044]&&[\u3043-\u3045]&&[\u3044-\u3046]] +\u3042 +false 0 + +[[\u3042-\u3044]&&[\u3043-\u3045]&&[\u3044-\u3046]] +\u3044 +true \u3044 0 + +[[\u3042-\u3044]&&[\u3043-\u3045][\u3044-\u3046]&&[\u3056-\u305B]] +\u3044 +false 0 + +[\u3042\u3043\u3044[^\u3043\u3044\u3045]] +\u3042 +true \u3042 0 + +[\u3042\u3043\u3044[^\u3043\u3044\u3045]] +\u3045 +false 0 + +[\u3042-\u3044&&\u3042-\u3045&&\u3042-\u3046\u3048\u3049\u304A] +\u3043 +true \u3043 0 + +[\u3042-\u3044&&\u3042-\u3045&&\u3042-\u3046\u3048\u3049\u304A] +\u3048 +false 0 + +[[\u3042[\u3043]]&&[\u3043[\u3042]]] +\u3042 +true \u3042 0 + +[[\u3042]&&[\u3043][\u3044][\u3042]&&[^\u3045]] +\u3042 +true \u3042 0 + +[[\u3042]&&[b][c][\u3042]&&[^d]] +\u3042 +true \u3042 0 + +[[\u3042]&&[\u3043][\u3044][\u3042]&&[^\u3045]] +\u3045 +false 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]] +\u3042 +false 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]] +\u3044 +true \u3044 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]&&[\u3044]] +\u3044 +true \u3044 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]&&[\u3044]&&\u3044] +\u3044 +true \u3044 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]&&[\u3044]&&\u3044&&\u3044] +\u3044 +true \u3044 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]&&[\u3044]&&\u3044&&[\u3044\u3045\u3046]] +\u3044 +true \u3044 0 + +[\u305B[\u3042\u3043\u3044&&\u3043\u3044\u3045]] +\u3044 +true \u3044 0 + +[\u305B[\u3042\u3043\u3044&&\u3043\u3044\u3045]&&[\u3056-\u305B]] +\u305B +true \u305B 0 + +[\u3059[\u3042\u3043\u3044&&\u3043\u3044\u3045[\u305B]]&&[\u3056-\u305B]] +\u305B +false 0 + +[\u3059[[w\u305B]\u3042\u3043\u3044&&\u3043\u3044\u3045[\u305B]]&&[\u3056-\u305B]] +\u305B +true \u305B 0 + +[[\u3042\u3043\u3044]&&[\u3045\u3046\u3047]\u3042\u3043\u3044] +\u3042 +true \u3042 0 + +[[\u3042\u3043\u3044]&&[\u3045\u3046\u3047]\u3059\u305A\u305B[\u3042\u3043\u3044]] +\u3042 +true \u3042 0 + +\pL +\u3042 +true \u3042 0 + +\pL +7 +false 0 + +\p{L} +\u3042 +true \u3042 0 + +\p{IsL} +\u3042 +true \u3042 0 + +\p{InHiragana} +\u3042 +true \u3042 0 + +\p{InHiragana} +\u0370 +false 0 + +\pL\u3043\u3044 +\u3042\u3043\u3044 +true \u3042\u3043\u3044 0 + +\u3042[r\p{InGreek}]\u3044 +\u3042\u0370\u3044 +true \u3042\u0370\u3044 0 + +\u3042\p{InGreek} +\u3042\u0370 +true \u3042\u0370 0 + +\u3042\P{InGreek} +\u3042\u0370 +false 0 + +\u3042\P{InGreek} +\u3042\u3043 +true \u3042\u3043 0 + +\u3042{^InGreek} +- +error + +\u3042\p{^InGreek} +- +error + +\u3042\P{^InGreek} +- +error + +\u3042\p{InGreek} +\u3042\u0370 +true \u3042\u0370 0 + +\u3042[\p{InGreek}]\u3044 +\u3042\u0370\u3044 +true \u3042\u0370\u3044 0 + +\u3042[\P{InGreek}]\u3044 +\u3042\u0370\u3044 +false 0 + +\u3042[\P{InGreek}]\u3044 +\u3042\u3043\u3044 +true \u3042\u3043\u3044 0 + +\u3042[{^InGreek}]\u3044 +\u3042n\u3044 +true \u3042n\u3044 0 + +\u3042[{^InGreek}]\u3044 +\u3042\u305B\u3044 +false 0 + +\u3042[\p{^InGreek}]\u3044 +- +error + +\u3042[\P{^InGreek}]\u3044 +- +error + +\u3042[\p{InGreek}] +\u3042\u0370 +true \u3042\u0370 0 + +\u3042[r\p{InGreek}]\u3044 +\u3042r\u3044 +true \u3042r\u3044 0 + +\u3042[\p{InGreek}r]\u3044 +\u3042r\u3044 +true \u3042r\u3044 0 + +\u3042[r\p{InGreek}]\u3044 +\u3042r\u3044 +true \u3042r\u3044 0 + +\u3042[^\p{InGreek}]\u3044 +\u3042\u0370\u3044 +false 0 + +\u3042[^\P{InGreek}]\u3044 +\u3042\u0370\u3044 +true \u3042\u0370\u3044 0 + +\u3042[\p{InGreek}&&[^\u0370]]\u3044 +\u3042\u0370\u3044 +false 0 + +// Test the dot metacharacter +\u3042.\u3044.+ +\u3042#\u3044%& +true \u3042#\u3044%& 0 + +\u3042\u3043. +\u3042\u3043\n +false 0 + +(?s)\u3042\u3043. +\u3042\u3043\n +true \u3042\u3043\n 0 + +\u3042[\p{L}&&[\P{InGreek}]]\u3044 +\u3042\u6000\u3044 +true \u3042\u6000\u3044 0 + +\u3042[\p{L}&&[\P{InGreek}]]\u3044 +\u3042r\u3044 +true \u3042r\u3044 0 + +\u3042[\p{L}&&[\P{InGreek}]]\u3044 +\u3042\u0370\u3044 +false 0 + +\u3042\p{InGreek}\u3044 +\u3042\u0370\u3044 +true \u3042\u0370\u3044 0 + +\u3042\p{Sc} +\u3042$ +true \u3042$ 0 + +\W\w\W +rrrr#\u3048\u3048\u3048 +false 0 + +\u3042\u3043\u3044[\s\u3045\u3046\u3047]* +\u3042\u3043\u3044 \u3045\u3046\u3047 +true \u3042\u3043\u3044 \u3045\u3046\u3047 0 + +\u3042\u3043\u3044[\s\u305A-\u305B]* +\u3042\u3043\u3044 \u305A \u305B +true \u3042\u3043\u3044 \u305A \u305B 0 + +\u3042\u3043\u3044[\u3042-\u3045\s\u304e-\u3051]* +\u3042\u3043\u3044\u3042\u3042 \u304e\u304f \u3051 +true \u3042\u3043\u3044\u3042\u3042 \u304e\u304f \u3051 0 + +// Test the whitespace escape sequence +\u3042\u3043\s\u3044 +\u3042\u3043 \u3044 +true \u3042\u3043 \u3044 0 + +\s\s\s +\u3043l\u3042\u3049 \u3046rr +false 0 + +\S\S\s +\u3043l\u3042\u3049 \u3046rr +true \u3042\u3049 0 + +// Test the digit escape sequence +\u3042\u3043\d\u3044 +\u3042\u30439\u3044 +true \u3042\u30439\u3044 0 + +\d\d\d +\u3043l\u3042\u304945 +false 0 + +// Test the caret metacharacter +^\u3042\u3043\u3044 +\u3042\u3043\u3044\u3045\u3046\u3047 +true \u3042\u3043\u3044 0 + +^\u3042\u3043\u3044 +\u3043\u3044\u3045\u3042\u3043\u3044 +false 0 + +// Greedy ? metacharacter +\u3042?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +\u3042?\u3043 +\u3043 +true \u3043 0 + +\u3042?\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +// Reluctant ? metacharacter +\u3042??\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +\u3042??\u3043 +\u3043 +true \u3043 0 + +\u3042??\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.??\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +// Possessive ? metacharacter +\u3042?+\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +\u3042?+\u3043 +\u3043 +true \u3043 0 + +\u3042?+\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.?+\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +// Greedy + metacharacter +\u3042+\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +\u3042+\u3043 +\u3043 +false 0 + +\u3042+\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.+\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +// Reluctant + metacharacter +\u3042+?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +\u3042+?\u3043 +\u3043 +false 0 + +\u3042+?\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.+?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +// Possessive + metacharacter +\u3042++\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +\u3042++\u3043 +\u3043 +false 0 + +\u3042++\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.++\u3043 +\u3042\u3042\u3042\u3042\u3043 +false 0 + +// Greedy Repetition +\u3042{2,3} +\u3042 +false 0 + +\u3042{2,3} +\u3042\u3042 +true \u3042\u3042 0 + +\u3042{2,3} +\u3042\u3042\u3042 +true \u3042\u3042\u3042 0 + +\u3042{2,3} +\u3042\u3042\u3042\u3042 +true \u3042\u3042\u3042 0 + +\u3042{3,} +\u305B\u305B\u305B\u3042\u3042\u3042\u3042\u305B\u305B\u305B +true \u3042\u3042\u3042\u3042 0 + +\u3042{3,} +\u305B\u305B\u305B\u3042\u3042\u305B\u305B\u305B +false 0 + +// Reluctant Repetition +\u3042{2,3}? +\u3042 +false 0 + +\u3042{2,3}? +\u3042\u3042 +true \u3042\u3042 0 + +\u3042{2,3}? +\u3042\u3042\u3042 +true \u3042\u3042 0 + +\u3042{2,3}? +\u3042\u3042\u3042\u3042 +true \u3042\u3042 0 + +// Zero width Positive lookahead +\u3042\u3043\u3044(?=\u3045) +\u305B\u305B\u305B\u3042\u3043\u3044\u3045 +true \u3042\u3043\u3044 0 + +\u3042\u3043\u3044(?=\u3045) +\u305B\u305B\u305B\u3042\u3043\u3044\u3046\u3045 +false 0 + +// Zero width Negative lookahead +\u3042\u3043\u3044(?!\u3045) +\u305B\u305B\u3042\u3043\u3044\u3045 +false 0 + +\u3042\u3043\u3044(?!\u3045) +\u305B\u305B\u3042\u3043\u3044\u3046\u3045 +true \u3042\u3043\u3044 0 + +// Zero width Positive lookbehind +\u3042(?<=\u3042) +###\u3042\u3043\u3044 +true \u3042 0 + +\u3042(?<=\u3042) +###\u3043\u3044### +false 0 + +// Zero width Negative lookbehind +(?<!\u3042)\w +###\u3042\u3043\u3044a### +true a 0 + +(?<!\u3042)\u3044 +\u3043\u3044 +true \u3044 0 + +(?<!\u3042)\u3044 +\u3042\u3044 +false 0 + +// Nondeterministic group +(\u3042+\u3043)+ +\u3042\u3043\u3042\u3043\u3042\u3043 +true \u3042\u3043\u3042\u3043\u3042\u3043 1 \u3042\u3043 + +(\u3042|\u3043)+ +\u3044\u3044\u3044\u3044\u3045 +false 1 + +// Deterministic group +(\u3042\u3043)+ +\u3042\u3043\u3042\u3043\u3042\u3043 +true \u3042\u3043\u3042\u3043\u3042\u3043 1 \u3042\u3043 + +(\u3042\u3043)+ +\u3042\u3044\u3044\u3044\u3044\u3045 +false 1 + +(\u3042\u3043)* +\u3042\u3043\u3042\u3043\u3042\u3043 +true \u3042\u3043\u3042\u3043\u3042\u3043 1 \u3042\u3043 + +(\u3042\u3043)(\u3044\u3045*) +\u305B\u305B\u305B\u3042\u3043\u3044\u305B\u305B\u305B +true \u3042\u3043\u3044 2 \u3042\u3043 \u3044 + +\u3042\u3043\u3044(\u3045)*\u3042\u3043\u3044 +\u3042\u3043\u3044\u3045\u3045\u3045\u3045\u3045\u3042\u3043\u3044 +true \u3042\u3043\u3044\u3045\u3045\u3045\u3045\u3045\u3042\u3043\u3044 1 \u3045 + +// Back references +(\u3042*)\u3043\u3044\1 +\u305B\u305B\u305B\u3042\u3042\u3043\u3044\u3042\u3042\u305B\u305B\u305B +true \u3042\u3042\u3043\u3044\u3042\u3042 1 \u3042\u3042 + +(\u3042*)\u3043\u3044\1 +\u305B\u305B\u305B\u3042\u3042\u3043\u3044\u3042\u305B\u305B\u305B +true \u3042\u3043\u3044\u3042 1 \u3042 + +(\u3048t*)(\u3045\u3045\u3046)*(\u305A\u3056)\1\3(\u3057\u3057) +\u305B\u305B\u305B\u3048tt\u3045\u3045\u3046\u3045\u3045\u3046\u305A\u3056\u3048tt\u305A\u3056\u3057\u3057\u305B\u305B\u305B +true \u3048tt\u3045\u3045\u3046\u3045\u3045\u3046\u305A\u3056\u3048tt\u305A\u3056\u3057\u3057 4 \u3048tt \u3045\u3045\u3046 \u305A\u3056 \u3057\u3057 + +// Greedy * metacharacter +\u3042*\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +\u3042*\u3043 +\u3043 +true \u3043 0 + +\u3042*\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.*\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +// Reluctant * metacharacter +\u3042*?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +\u3042*?\u3043 +\u3043 +true \u3043 0 + +\u3042*?\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.*?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +// Possessive * metacharacter +\u3042*+\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +\u3042*+\u3043 +\u3043 +true \u3043 0 + +\u3042*+\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.*+\u3043 +\u3042\u3042\u3042\u3042\u3043 +false 0 + +// Case insensitivity +(?iu)\uFF46\uFF4F\uFF4F\uFF42\uFF41\uFF52 +\uFF46\uFF2F\uFF4F\uFF42\uFF21\uFF52 +true \uFF46\uFF2F\uFF4F\uFF42\uFF21\uFF52 0 + +\uFF46(?iu)\uFF4F\uFF4F\uFF42\uFF41\uFF52 +\uFF46\uFF2F\uFF4F\uFF42\uFF21\uFF52 +true \uFF46\uFF2F\uFF4F\uFF42\uFF21\uFF52 0 + +\uFF46\uFF4F\uFF4F(?iu)\uFF42\uFF41\uFF52 +\uFF46\uFF2F\uFF4F\uFF42\uFF21\uFF52 +false 0 + +(?iu)\uFF46\uFF4F\uFF4F[\uFF42\uFF41\uFF52]+ +\uFF46\uFF4F\uFF2F\uFF42\uFF21\uFF52 +true \uFF46\uFF4F\uFF2F\uFF42\uFF21\uFF52 0 + +(?iu)\uFF46\uFF4F\uFF4F[\uFF41-\uFF52]+ +\uFF46\uFF4F\uFF2F\uFF42\uFF21\uFF52 +true \uFF46\uFF4F\uFF2F\uFF42\uFF21\uFF52 0 + +// Disable metacharacters- test both length <=3 and >3 +// So that the BM optimization is part of test +\Q***\E\u3042\u3043\u3044 +***\u3042\u3043\u3044 +true ***\u3042\u3043\u3044 0 + +\u3043l\Q***\E\u3042\u3043\u3044 +\u3043l***\u3042\u3043\u3044 +true \u3043l***\u3042\u3043\u3044 0 + +\Q***\u3042\u3043\u3044 +***\u3042\u3043\u3044 +true ***\u3042\u3043\u3044 0 + +\u3043l\u3042\u3049\Q***\E\u3042\u3043\u3044 +\u3043l\u3042\u3049***\u3042\u3043\u3044 +true \u3043l\u3042\u3049***\u3042\u3043\u3044 0 + +\Q***\u3042\u3043\u3044 +***\u3042\u3043\u3044 +true ***\u3042\u3043\u3044 0 + +\Q*\u3042\u3043 +*\u3042\u3043 +true *\u3042\u3043 0 + +\u3043l\u3042\u3049\Q***\u3042\u3043\u3044 +\u3043l\u3042\u3049***\u3042\u3043\u3044 +true \u3043l\u3042\u3049***\u3042\u3043\u3044 0 + +\u3043l\u3042\Q***\u3042\u3043\u3044 +\u3043l\u3042***\u3042\u3043\u3044 +true \u3043l\u3042***\u3042\u3043\u3044 0 + +[\043]+ +\u3043l\u3042\u3049\u3043l\u3042\u3049#\u3043le\u3044\u3049 +true # 0 + +[\042-\044]+ +\u3043l\u3042\u3049\u3043l\u3042\u3049#\u3043le\u3044\u3049 +true # 0 + +[\u1234-\u1236] +\u3043l\u3042\u3049\u3043l\u3042\u3049\u1235\u3043le\u3044\u3049 +true \u1235 0 + +[^\043]* +\u3043l\u3042\u3049\u3043l\u3042\u3049#\u3043le\u3044\u3049 +true \u3043l\u3042\u3049\u3043l\u3042\u3049 0 diff --git a/jdk/test/java/util/regex/RegExTest.java b/jdk/test/java/util/regex/RegExTest.java new file mode 100644 index 00000000000..17621184a53 --- /dev/null +++ b/jdk/test/java/util/regex/RegExTest.java @@ -0,0 +1,3516 @@ +/* + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @summary tests RegExp framework + * @author Mike McCloskey + * @bug 4481568 4482696 4495089 4504687 4527731 4599621 4631553 4619345 + * 4630911 4672616 4711773 4727935 4750573 4792284 4803197 4757029 4808962 + * 4872664 4803179 4892980 4900747 4945394 4938995 4979006 4994840 4997476 + * 5013885 5003322 4988891 5098443 5110268 6173522 4829857 5027748 6376940 + * 6358731 6178785 6284152 6231989 6497148 6486934 6233084 6504326 6635133 + * 6350801 6676425 + */ + +import java.util.regex.*; +import java.util.Random; +import java.io.*; +import java.util.*; +import java.nio.CharBuffer; + +/** + * This is a test class created to check the operation of + * the Pattern and Matcher classes. + */ +public class RegExTest { + + private static Random generator = new Random(); + private static boolean failure = false; + private static int failCount = 0; + + /** + * Main to interpret arguments and run several tests. + * + */ + public static void main(String[] args) throws Exception { + // Most of the tests are in a file + processFile("TestCases.txt"); + //processFile("PerlCases.txt"); + processFile("BMPTestCases.txt"); + processFile("SupplementaryTestCases.txt"); + + // These test many randomly generated char patterns + bm(); + slice(); + + // These are hard to put into the file + escapes(); + blankInput(); + + // Substitition tests on randomly generated sequences + globalSubstitute(); + stringbufferSubstitute(); + substitutionBasher(); + + // Canonical Equivalence + ceTest(); + + // Anchors + anchorTest(); + + // boolean match calls + matchesTest(); + lookingAtTest(); + + // Pattern API + patternMatchesTest(); + + // Misc + lookbehindTest(); + nullArgumentTest(); + backRefTest(); + groupCaptureTest(); + caretTest(); + charClassTest(); + emptyPatternTest(); + findIntTest(); + group0Test(); + longPatternTest(); + octalTest(); + ampersandTest(); + negationTest(); + splitTest(); + appendTest(); + caseFoldingTest(); + commentsTest(); + unixLinesTest(); + replaceFirstTest(); + gTest(); + zTest(); + serializeTest(); + reluctantRepetitionTest(); + multilineDollarTest(); + dollarAtEndTest(); + caretBetweenTerminatorsTest(); + // This RFE rejected in Tiger numOccurrencesTest(); + javaCharClassTest(); + nonCaptureRepetitionTest(); + notCapturedGroupCurlyMatchTest(); + escapedSegmentTest(); + literalPatternTest(); + literalReplacementTest(); + regionTest(); + toStringTest(); + negatedCharClassTest(); + findFromTest(); + boundsTest(); + unicodeWordBoundsTest(); + caretAtEndTest(); + wordSearchTest(); + hitEndTest(); + toMatchResultTest(); + surrogatesInClassTest(); + namedGroupCaptureTest(); + + if (failure) + throw new RuntimeException("Failure in the RE handling."); + else + System.err.println("OKAY: All tests passed."); + } + + // Utility functions + + private static String getRandomAlphaString(int length) { + StringBuffer buf = new StringBuffer(length); + for (int i=0; i<length; i++) { + char randChar = (char)(97 + generator.nextInt(26)); + buf.append(randChar); + } + return buf.toString(); + } + + private static void check(Matcher m, String expected) { + m.find(); + if (!m.group().equals(expected)) + failCount++; + } + + private static void check(Matcher m, String result, boolean expected) { + m.find(); + if (m.group().equals(result)) + failCount += (expected) ? 0 : 1; + else + failCount += (expected) ? 1 : 0; + } + + private static void check(Pattern p, String s, boolean expected) { + Matcher matcher = p.matcher(s); + if (matcher.find()) + failCount += (expected) ? 0 : 1; + else + failCount += (expected) ? 1 : 0; + } + + private static void check(String p, char c, boolean expected) { + String propertyPattern = expected ? "\\p" + p : "\\P" + p; + Pattern pattern = Pattern.compile(propertyPattern); + char[] ca = new char[1]; ca[0] = c; + Matcher matcher = pattern.matcher(new String(ca)); + if (!matcher.find()) + failCount++; + } + + private static void check(String p, int codePoint, boolean expected) { + String propertyPattern = expected ? "\\p" + p : "\\P" + p; + Pattern pattern = Pattern.compile(propertyPattern); + char[] ca = Character.toChars(codePoint); + Matcher matcher = pattern.matcher(new String(ca)); + if (!matcher.find()) + failCount++; + } + + private static void check(String p, int flag, String input, String s, + boolean expected) + { + Pattern pattern = Pattern.compile(p, flag); + Matcher matcher = pattern.matcher(input); + if (expected) + check(matcher, s, expected); + else + check(pattern, input, false); + } + + private static void report(String testName) { + int spacesToAdd = 30 - testName.length(); + StringBuffer paddedNameBuffer = new StringBuffer(testName); + for (int i=0; i<spacesToAdd; i++) + paddedNameBuffer.append(" "); + String paddedName = paddedNameBuffer.toString(); + System.err.println(paddedName + ": " + + (failCount==0 ? "Passed":"Failed("+failCount+")")); + if (failCount > 0) + failure = true; + failCount = 0; + } + + /** + * Converts ASCII alphabet characters [A-Za-z] in the given 's' to + * supplementary characters. This method does NOT fully take care + * of the regex syntax. + */ + private static String toSupplementaries(String s) { + int length = s.length(); + StringBuffer sb = new StringBuffer(length * 2); + + for (int i = 0; i < length; ) { + char c = s.charAt(i++); + if (c == '\\') { + sb.append(c); + if (i < length) { + c = s.charAt(i++); + sb.append(c); + if (c == 'u') { + // assume no syntax error + sb.append(s.charAt(i++)); + sb.append(s.charAt(i++)); + sb.append(s.charAt(i++)); + sb.append(s.charAt(i++)); + } + } + } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + sb.append('\ud800').append((char)('\udc00'+c)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + // Regular expression tests + + // This is for bug 6178785 + // Test if an expected NPE gets thrown when passing in a null argument + private static boolean check(Runnable test) { + try { + test.run(); + failCount++; + return false; + } catch (NullPointerException npe) { + return true; + } + } + + private static void nullArgumentTest() { + check(new Runnable() { public void run() { Pattern.compile(null); }}); + check(new Runnable() { public void run() { Pattern.matches(null, null); }}); + check(new Runnable() { public void run() { Pattern.matches("xyz", null);}}); + check(new Runnable() { public void run() { Pattern.quote(null);}}); + check(new Runnable() { public void run() { Pattern.compile("xyz").split(null);}}); + check(new Runnable() { public void run() { Pattern.compile("xyz").matcher(null);}}); + + final Matcher m = Pattern.compile("xyz").matcher("xyz"); + m.matches(); + check(new Runnable() { public void run() { m.appendTail(null);}}); + check(new Runnable() { public void run() { m.replaceAll(null);}}); + check(new Runnable() { public void run() { m.replaceFirst(null);}}); + check(new Runnable() { public void run() { m.appendReplacement(null, null);}}); + check(new Runnable() { public void run() { m.reset(null);}}); + check(new Runnable() { public void run() { Matcher.quoteReplacement(null);}}); + //check(new Runnable() { public void run() { m.usePattern(null);}}); + + report("Null Argument"); + } + + // This is for bug6635133 + // Test if surrogate pair in Unicode escapes can be handled correctly. + private static void surrogatesInClassTest() throws Exception { + Pattern pattern = Pattern.compile("[\\ud834\\udd21-\\ud834\\udd24]"); + Matcher matcher = pattern.matcher("\ud834\udd22"); + if (!matcher.find()) + failCount++; + } + + // This is for bug 4988891 + // Test toMatchResult to see that it is a copy of the Matcher + // that is not affected by subsequent operations on the original + private static void toMatchResultTest() throws Exception { + Pattern pattern = Pattern.compile("squid"); + Matcher matcher = pattern.matcher( + "agiantsquidofdestinyasmallsquidoffate"); + matcher.find(); + int matcherStart1 = matcher.start(); + MatchResult mr = matcher.toMatchResult(); + if (mr == matcher) + failCount++; + int resultStart1 = mr.start(); + if (matcherStart1 != resultStart1) + failCount++; + matcher.find(); + int matcherStart2 = matcher.start(); + int resultStart2 = mr.start(); + if (matcherStart2 == resultStart2) + failCount++; + if (resultStart1 != resultStart2) + failCount++; + MatchResult mr2 = matcher.toMatchResult(); + if (mr == mr2) + failCount++; + if (mr2.start() != matcherStart2) + failCount++; + report("toMatchResult is a copy"); + } + + // This is for bug 5013885 + // Must test a slice to see if it reports hitEnd correctly + private static void hitEndTest() throws Exception { + // Basic test of Slice node + Pattern p = Pattern.compile("^squidattack"); + Matcher m = p.matcher("squack"); + m.find(); + if (m.hitEnd()) + failCount++; + m.reset("squid"); + m.find(); + if (!m.hitEnd()) + failCount++; + + // Test Slice, SliceA and SliceU nodes + for (int i=0; i<3; i++) { + int flags = 0; + if (i==1) flags = Pattern.CASE_INSENSITIVE; + if (i==2) flags = Pattern.UNICODE_CASE; + p = Pattern.compile("^abc", flags); + m = p.matcher("ad"); + m.find(); + if (m.hitEnd()) + failCount++; + m.reset("ab"); + m.find(); + if (!m.hitEnd()) + failCount++; + } + + // Test Boyer-Moore node + p = Pattern.compile("catattack"); + m = p.matcher("attack"); + m.find(); + if (!m.hitEnd()) + failCount++; + + p = Pattern.compile("catattack"); + m = p.matcher("attackattackattackcatatta"); + m.find(); + if (!m.hitEnd()) + failCount++; + + report("hitEnd from a Slice"); + } + + // This is for bug 4997476 + // It is weird code submitted by customer demonstrating a regression + private static void wordSearchTest() throws Exception { + String testString = new String("word1 word2 word3"); + Pattern p = Pattern.compile("\\b"); + Matcher m = p.matcher(testString); + int position = 0; + int start = 0; + while (m.find(position)) { + start = m.start(); + if (start == testString.length()) + break; + if (m.find(start+1)) { + position = m.start(); + } else { + position = testString.length(); + } + if (testString.substring(start, position).equals(" ")) + continue; + if (!testString.substring(start, position-1).startsWith("word")) + failCount++; + } + report("Customer word search"); + } + + // This is for bug 4994840 + private static void caretAtEndTest() throws Exception { + // Problem only occurs with multiline patterns + // containing a beginning-of-line caret "^" followed + // by an expression that also matches the empty string. + Pattern pattern = Pattern.compile("^x?", Pattern.MULTILINE); + Matcher matcher = pattern.matcher("\r"); + matcher.find(); + matcher.find(); + report("Caret at end"); + } + + // This test is for 4979006 + // Check to see if word boundary construct properly handles unicode + // non spacing marks + private static void unicodeWordBoundsTest() throws Exception { + String spaces = " "; + String wordChar = "a"; + String nsm = "\u030a"; + + assert (Character.getType('\u030a') == Character.NON_SPACING_MARK); + + Pattern pattern = Pattern.compile("\\b"); + Matcher matcher = pattern.matcher(""); + // S=other B=word character N=non spacing mark .=word boundary + // SS.BB.SS + String input = spaces + wordChar + wordChar + spaces; + twoFindIndexes(input, matcher, 2, 4); + // SS.BBN.SS + input = spaces + wordChar +wordChar + nsm + spaces; + twoFindIndexes(input, matcher, 2, 5); + // SS.BN.SS + input = spaces + wordChar + nsm + spaces; + twoFindIndexes(input, matcher, 2, 4); + // SS.BNN.SS + input = spaces + wordChar + nsm + nsm + spaces; + twoFindIndexes(input, matcher, 2, 5); + // SSN.BB.SS + input = spaces + nsm + wordChar + wordChar + spaces; + twoFindIndexes(input, matcher, 3, 5); + // SS.BNB.SS + input = spaces + wordChar + nsm + wordChar + spaces; + twoFindIndexes(input, matcher, 2, 5); + // SSNNSS + input = spaces + nsm + nsm + spaces; + matcher.reset(input); + if (matcher.find()) + failCount++; + // SSN.BBN.SS + input = spaces + nsm + wordChar + wordChar + nsm + spaces; + twoFindIndexes(input, matcher, 3, 6); + + report("Unicode word boundary"); + } + + private static void twoFindIndexes(String input, Matcher matcher, int a, + int b) throws Exception + { + matcher.reset(input); + matcher.find(); + if (matcher.start() != a) + failCount++; + matcher.find(); + if (matcher.start() != b) + failCount++; + } + + // This test is for 6284152 + static void check(String regex, String input, String[] expected) { + List<String> result = new ArrayList<String>(); + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(input); + while (m.find()) { + result.add(m.group()); + } + if (!Arrays.asList(expected).equals(result)) + failCount++; + } + + private static void lookbehindTest() throws Exception { + //Positive + check("(?<=%.{0,5})foo\\d", + "%foo1\n%bar foo2\n%bar foo3\n%blahblah foo4\nfoo5", + new String[]{"foo1", "foo2", "foo3"}); + + //boundary at end of the lookbehind sub-regex should work consistently + //with the boundary just after the lookbehind sub-regex + check("(?<=.*\\b)foo", "abcd foo", new String[]{"foo"}); + check("(?<=.*)\\bfoo", "abcd foo", new String[]{"foo"}); + check("(?<!abc )\\bfoo", "abc foo", new String[0]); + check("(?<!abc \\b)foo", "abc foo", new String[0]); + + //Negative + check("(?<!%.{0,5})foo\\d", + "%foo1\n%bar foo2\n%bar foo3\n%blahblah foo4\nfoo5", + new String[] {"foo4", "foo5"}); + + //Positive greedy + check("(?<=%b{1,4})foo", "%bbbbfoo", new String[] {"foo"}); + + //Positive reluctant + check("(?<=%b{1,4}?)foo", "%bbbbfoo", new String[] {"foo"}); + + //supplementary + check("(?<=%b{1,4})fo\ud800\udc00o", "%bbbbfo\ud800\udc00o", + new String[] {"fo\ud800\udc00o"}); + check("(?<=%b{1,4}?)fo\ud800\udc00o", "%bbbbfo\ud800\udc00o", + new String[] {"fo\ud800\udc00o"}); + check("(?<!%b{1,4})fo\ud800\udc00o", "%afo\ud800\udc00o", + new String[] {"fo\ud800\udc00o"}); + check("(?<!%b{1,4}?)fo\ud800\udc00o", "%afo\ud800\udc00o", + new String[] {"fo\ud800\udc00o"}); + report("Lookbehind"); + } + + // This test is for 4938995 + // Check to see if weak region boundaries are transparent to + // lookahead and lookbehind constructs + private static void boundsTest() throws Exception { + String fullMessage = "catdogcat"; + Pattern pattern = Pattern.compile("(?<=cat)dog(?=cat)"); + Matcher matcher = pattern.matcher("catdogca"); + matcher.useTransparentBounds(true); + if (matcher.find()) + failCount++; + matcher.reset("atdogcat"); + if (matcher.find()) + failCount++; + matcher.reset(fullMessage); + if (!matcher.find()) + failCount++; + matcher.reset(fullMessage); + matcher.region(0,9); + if (!matcher.find()) + failCount++; + matcher.reset(fullMessage); + matcher.region(0,6); + if (!matcher.find()) + failCount++; + matcher.reset(fullMessage); + matcher.region(3,6); + if (!matcher.find()) + failCount++; + matcher.useTransparentBounds(false); + if (matcher.find()) + failCount++; + + // Negative lookahead/lookbehind + pattern = Pattern.compile("(?<!cat)dog(?!cat)"); + matcher = pattern.matcher("dogcat"); + matcher.useTransparentBounds(true); + matcher.region(0,3); + if (matcher.find()) + failCount++; + matcher.reset("catdog"); + matcher.region(3,6); + if (matcher.find()) + failCount++; + matcher.useTransparentBounds(false); + matcher.reset("dogcat"); + matcher.region(0,3); + if (!matcher.find()) + failCount++; + matcher.reset("catdog"); + matcher.region(3,6); + if (!matcher.find()) + failCount++; + + report("Region bounds transparency"); + } + + // This test is for 4945394 + private static void findFromTest() throws Exception { + String message = "This is 40 $0 message."; + Pattern pat = Pattern.compile("\\$0"); + Matcher match = pat.matcher(message); + if (!match.find()) + failCount++; + if (match.find()) + failCount++; + if (match.find()) + failCount++; + report("Check for alternating find"); + } + + // This test is for 4872664 and 4892980 + private static void negatedCharClassTest() throws Exception { + Pattern pattern = Pattern.compile("[^>]"); + Matcher matcher = pattern.matcher("\u203A"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("[^fr]"); + matcher = pattern.matcher("a"); + if (!matcher.find()) + failCount++; + matcher.reset("\u203A"); + if (!matcher.find()) + failCount++; + String s = "for"; + String result[] = s.split("[^fr]"); + if (!result[0].equals("f")) + failCount++; + if (!result[1].equals("r")) + failCount++; + s = "f\u203Ar"; + result = s.split("[^fr]"); + if (!result[0].equals("f")) + failCount++; + if (!result[1].equals("r")) + failCount++; + + // Test adding to bits, subtracting a node, then adding to bits again + pattern = Pattern.compile("[^f\u203Ar]"); + matcher = pattern.matcher("a"); + if (!matcher.find()) + failCount++; + matcher.reset("f"); + if (matcher.find()) + failCount++; + matcher.reset("\u203A"); + if (matcher.find()) + failCount++; + matcher.reset("r"); + if (matcher.find()) + failCount++; + matcher.reset("\u203B"); + if (!matcher.find()) + failCount++; + + // Test subtracting a node, adding to bits, subtracting again + pattern = Pattern.compile("[^\u203Ar\u203B]"); + matcher = pattern.matcher("a"); + if (!matcher.find()) + failCount++; + matcher.reset("\u203A"); + if (matcher.find()) + failCount++; + matcher.reset("r"); + if (matcher.find()) + failCount++; + matcher.reset("\u203B"); + if (matcher.find()) + failCount++; + matcher.reset("\u203C"); + if (!matcher.find()) + failCount++; + + report("Negated Character Class"); + } + + // This test is for 4628291 + private static void toStringTest() throws Exception { + Pattern pattern = Pattern.compile("b+"); + if (pattern.toString() != "b+") + failCount++; + Matcher matcher = pattern.matcher("aaabbbccc"); + String matcherString = matcher.toString(); // unspecified + matcher.find(); + matcherString = matcher.toString(); // unspecified + matcher.region(0,3); + matcherString = matcher.toString(); // unspecified + matcher.reset(); + matcherString = matcher.toString(); // unspecified + report("toString"); + } + + // This test is for 4808962 + private static void literalPatternTest() throws Exception { + int flags = Pattern.LITERAL; + + Pattern pattern = Pattern.compile("abc\\t$^", flags); + check(pattern, "abc\\t$^", true); + + pattern = Pattern.compile(Pattern.quote("abc\\t$^")); + check(pattern, "abc\\t$^", true); + + pattern = Pattern.compile("\\Qa^$bcabc\\E", flags); + check(pattern, "\\Qa^$bcabc\\E", true); + check(pattern, "a^$bcabc", false); + + pattern = Pattern.compile("\\\\Q\\\\E"); + check(pattern, "\\Q\\E", true); + + pattern = Pattern.compile("\\Qabc\\Eefg\\\\Q\\\\Ehij"); + check(pattern, "abcefg\\Q\\Ehij", true); + + pattern = Pattern.compile("\\\\\\Q\\\\E"); + check(pattern, "\\\\\\\\", true); + + pattern = Pattern.compile(Pattern.quote("\\Qa^$bcabc\\E")); + check(pattern, "\\Qa^$bcabc\\E", true); + check(pattern, "a^$bcabc", false); + + pattern = Pattern.compile(Pattern.quote("\\Qabc\\Edef")); + check(pattern, "\\Qabc\\Edef", true); + check(pattern, "abcdef", false); + + pattern = Pattern.compile(Pattern.quote("abc\\Edef")); + check(pattern, "abc\\Edef", true); + check(pattern, "abcdef", false); + + pattern = Pattern.compile(Pattern.quote("\\E")); + check(pattern, "\\E", true); + + pattern = Pattern.compile("((((abc.+?:)", flags); + check(pattern, "((((abc.+?:)", true); + + flags |= Pattern.MULTILINE; + + pattern = Pattern.compile("^cat$", flags); + check(pattern, "abc^cat$def", true); + check(pattern, "cat", false); + + flags |= Pattern.CASE_INSENSITIVE; + + pattern = Pattern.compile("abcdef", flags); + check(pattern, "ABCDEF", true); + check(pattern, "AbCdEf", true); + + flags |= Pattern.DOTALL; + + pattern = Pattern.compile("a...b", flags); + check(pattern, "A...b", true); + check(pattern, "Axxxb", false); + + flags |= Pattern.CANON_EQ; + + Pattern p = Pattern.compile("testa\u030a", flags); + check(pattern, "testa\u030a", false); + check(pattern, "test\u00e5", false); + + // Supplementary character test + flags = Pattern.LITERAL; + + pattern = Pattern.compile(toSupplementaries("abc\\t$^"), flags); + check(pattern, toSupplementaries("abc\\t$^"), true); + + pattern = Pattern.compile(Pattern.quote(toSupplementaries("abc\\t$^"))); + check(pattern, toSupplementaries("abc\\t$^"), true); + + pattern = Pattern.compile(toSupplementaries("\\Qa^$bcabc\\E"), flags); + check(pattern, toSupplementaries("\\Qa^$bcabc\\E"), true); + check(pattern, toSupplementaries("a^$bcabc"), false); + + pattern = Pattern.compile(Pattern.quote(toSupplementaries("\\Qa^$bcabc\\E"))); + check(pattern, toSupplementaries("\\Qa^$bcabc\\E"), true); + check(pattern, toSupplementaries("a^$bcabc"), false); + + pattern = Pattern.compile(Pattern.quote(toSupplementaries("\\Qabc\\Edef"))); + check(pattern, toSupplementaries("\\Qabc\\Edef"), true); + check(pattern, toSupplementaries("abcdef"), false); + + pattern = Pattern.compile(Pattern.quote(toSupplementaries("abc\\Edef"))); + check(pattern, toSupplementaries("abc\\Edef"), true); + check(pattern, toSupplementaries("abcdef"), false); + + pattern = Pattern.compile(toSupplementaries("((((abc.+?:)"), flags); + check(pattern, toSupplementaries("((((abc.+?:)"), true); + + flags |= Pattern.MULTILINE; + + pattern = Pattern.compile(toSupplementaries("^cat$"), flags); + check(pattern, toSupplementaries("abc^cat$def"), true); + check(pattern, toSupplementaries("cat"), false); + + flags |= Pattern.DOTALL; + + // note: this is case-sensitive. + pattern = Pattern.compile(toSupplementaries("a...b"), flags); + check(pattern, toSupplementaries("a...b"), true); + check(pattern, toSupplementaries("axxxb"), false); + + flags |= Pattern.CANON_EQ; + + String t = toSupplementaries("test"); + p = Pattern.compile(t + "a\u030a", flags); + check(pattern, t + "a\u030a", false); + check(pattern, t + "\u00e5", false); + + report("Literal pattern"); + } + + // This test is for 4803179 + // This test is also for 4808962, replacement parts + private static void literalReplacementTest() throws Exception { + int flags = Pattern.LITERAL; + + Pattern pattern = Pattern.compile("abc", flags); + Matcher matcher = pattern.matcher("zzzabczzz"); + String replaceTest = "$0"; + String result = matcher.replaceAll(replaceTest); + if (!result.equals("zzzabczzz")) + failCount++; + + matcher.reset(); + String literalReplacement = matcher.quoteReplacement(replaceTest); + result = matcher.replaceAll(literalReplacement); + if (!result.equals("zzz$0zzz")) + failCount++; + + matcher.reset(); + replaceTest = "\\t$\\$"; + literalReplacement = matcher.quoteReplacement(replaceTest); + result = matcher.replaceAll(literalReplacement); + if (!result.equals("zzz\\t$\\$zzz")) + failCount++; + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("abc"), flags); + matcher = pattern.matcher(toSupplementaries("zzzabczzz")); + replaceTest = "$0"; + result = matcher.replaceAll(replaceTest); + if (!result.equals(toSupplementaries("zzzabczzz"))) + failCount++; + + matcher.reset(); + literalReplacement = matcher.quoteReplacement(replaceTest); + result = matcher.replaceAll(literalReplacement); + if (!result.equals(toSupplementaries("zzz$0zzz"))) + failCount++; + + matcher.reset(); + replaceTest = "\\t$\\$"; + literalReplacement = matcher.quoteReplacement(replaceTest); + result = matcher.replaceAll(literalReplacement); + if (!result.equals(toSupplementaries("zzz\\t$\\$zzz"))) + failCount++; + + report("Literal replacement"); + } + + // This test is for 4757029 + private static void regionTest() throws Exception { + Pattern pattern = Pattern.compile("abc"); + Matcher matcher = pattern.matcher("abcdefabc"); + + matcher.region(0,9); + if (!matcher.find()) + failCount++; + if (!matcher.find()) + failCount++; + matcher.region(0,3); + if (!matcher.find()) + failCount++; + matcher.region(3,6); + if (matcher.find()) + failCount++; + matcher.region(0,2); + if (matcher.find()) + failCount++; + + expectRegionFail(matcher, 1, -1); + expectRegionFail(matcher, -1, -1); + expectRegionFail(matcher, -1, 1); + expectRegionFail(matcher, 5, 3); + expectRegionFail(matcher, 5, 12); + expectRegionFail(matcher, 12, 12); + + pattern = Pattern.compile("^abc$"); + matcher = pattern.matcher("zzzabczzz"); + matcher.region(0,9); + if (matcher.find()) + failCount++; + matcher.region(3,6); + if (!matcher.find()) + failCount++; + matcher.region(3,6); + matcher.useAnchoringBounds(false); + if (matcher.find()) + failCount++; + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("abc")); + matcher = pattern.matcher(toSupplementaries("abcdefabc")); + matcher.region(0,9*2); + if (!matcher.find()) + failCount++; + if (!matcher.find()) + failCount++; + matcher.region(0,3*2); + if (!matcher.find()) + failCount++; + matcher.region(1,3*2); + if (matcher.find()) + failCount++; + matcher.region(3*2,6*2); + if (matcher.find()) + failCount++; + matcher.region(0,2*2); + if (matcher.find()) + failCount++; + matcher.region(0,2*2+1); + if (matcher.find()) + failCount++; + + expectRegionFail(matcher, 1*2, -1); + expectRegionFail(matcher, -1, -1); + expectRegionFail(matcher, -1, 1*2); + expectRegionFail(matcher, 5*2, 3*2); + expectRegionFail(matcher, 5*2, 12*2); + expectRegionFail(matcher, 12*2, 12*2); + + pattern = Pattern.compile(toSupplementaries("^abc$")); + matcher = pattern.matcher(toSupplementaries("zzzabczzz")); + matcher.region(0,9*2); + if (matcher.find()) + failCount++; + matcher.region(3*2,6*2); + if (!matcher.find()) + failCount++; + matcher.region(3*2+1,6*2); + if (matcher.find()) + failCount++; + matcher.region(3*2,6*2-1); + if (matcher.find()) + failCount++; + matcher.region(3*2,6*2); + matcher.useAnchoringBounds(false); + if (matcher.find()) + failCount++; + report("Regions"); + } + + private static void expectRegionFail(Matcher matcher, int index1, + int index2) + { + try { + matcher.region(index1, index2); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } catch (IllegalStateException ise) { + // Correct result + } + } + + // This test is for 4803197 + private static void escapedSegmentTest() throws Exception { + + Pattern pattern = Pattern.compile("\\Qdir1\\dir2\\E"); + check(pattern, "dir1\\dir2", true); + + pattern = Pattern.compile("\\Qdir1\\dir2\\\\E"); + check(pattern, "dir1\\dir2\\", true); + + pattern = Pattern.compile("(\\Qdir1\\dir2\\\\E)"); + check(pattern, "dir1\\dir2\\", true); + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("\\Qdir1\\dir2\\E")); + check(pattern, toSupplementaries("dir1\\dir2"), true); + + pattern = Pattern.compile(toSupplementaries("\\Qdir1\\dir2")+"\\\\E"); + check(pattern, toSupplementaries("dir1\\dir2\\"), true); + + pattern = Pattern.compile(toSupplementaries("(\\Qdir1\\dir2")+"\\\\E)"); + check(pattern, toSupplementaries("dir1\\dir2\\"), true); + + report("Escaped segment"); + } + + // This test is for 4792284 + private static void nonCaptureRepetitionTest() throws Exception { + String input = "abcdefgh;"; + + String[] patterns = new String[] { + "(?:\\w{4})+;", + "(?:\\w{8})*;", + "(?:\\w{2}){2,4};", + "(?:\\w{4}){2,};", // only matches the + ".*?(?:\\w{5})+;", // specified minimum + ".*?(?:\\w{9})*;", // number of reps - OK + "(?:\\w{4})+?;", // lazy repetition - OK + "(?:\\w{4})++;", // possessive repetition - OK + "(?:\\w{2,}?)+;", // non-deterministic - OK + "(\\w{4})+;", // capturing group - OK + }; + + for (int i = 0; i < patterns.length; i++) { + // Check find() + check(patterns[i], 0, input, input, true); + // Check matches() + Pattern p = Pattern.compile(patterns[i]); + Matcher m = p.matcher(input); + + if (m.matches()) { + if (!m.group(0).equals(input)) + failCount++; + } else { + failCount++; + } + } + + report("Non capturing repetition"); + } + + // This test is for 6358731 + private static void notCapturedGroupCurlyMatchTest() throws Exception { + Pattern pattern = Pattern.compile("(abc)+|(abcd)+"); + Matcher matcher = pattern.matcher("abcd"); + if (!matcher.matches() || + matcher.group(1) != null || + !matcher.group(2).equals("abcd")) { + failCount++; + } + report("Not captured GroupCurly"); + } + + // This test is for 4706545 + private static void javaCharClassTest() throws Exception { + for (int i=0; i<1000; i++) { + char c = (char)generator.nextInt(); + check("{javaLowerCase}", c, Character.isLowerCase(c)); + check("{javaUpperCase}", c, Character.isUpperCase(c)); + check("{javaUpperCase}+", c, Character.isUpperCase(c)); + check("{javaTitleCase}", c, Character.isTitleCase(c)); + check("{javaDigit}", c, Character.isDigit(c)); + check("{javaDefined}", c, Character.isDefined(c)); + check("{javaLetter}", c, Character.isLetter(c)); + check("{javaLetterOrDigit}", c, Character.isLetterOrDigit(c)); + check("{javaJavaIdentifierStart}", c, + Character.isJavaIdentifierStart(c)); + check("{javaJavaIdentifierPart}", c, + Character.isJavaIdentifierPart(c)); + check("{javaUnicodeIdentifierStart}", c, + Character.isUnicodeIdentifierStart(c)); + check("{javaUnicodeIdentifierPart}", c, + Character.isUnicodeIdentifierPart(c)); + check("{javaIdentifierIgnorable}", c, + Character.isIdentifierIgnorable(c)); + check("{javaSpaceChar}", c, Character.isSpaceChar(c)); + check("{javaWhitespace}", c, Character.isWhitespace(c)); + check("{javaISOControl}", c, Character.isISOControl(c)); + check("{javaMirrored}", c, Character.isMirrored(c)); + + } + + // Supplementary character test + for (int i=0; i<1000; i++) { + int c = generator.nextInt(Character.MAX_CODE_POINT + - Character.MIN_SUPPLEMENTARY_CODE_POINT) + + Character.MIN_SUPPLEMENTARY_CODE_POINT; + check("{javaLowerCase}", c, Character.isLowerCase(c)); + check("{javaUpperCase}", c, Character.isUpperCase(c)); + check("{javaUpperCase}+", c, Character.isUpperCase(c)); + check("{javaTitleCase}", c, Character.isTitleCase(c)); + check("{javaDigit}", c, Character.isDigit(c)); + check("{javaDefined}", c, Character.isDefined(c)); + check("{javaLetter}", c, Character.isLetter(c)); + check("{javaLetterOrDigit}", c, Character.isLetterOrDigit(c)); + check("{javaJavaIdentifierStart}", c, + Character.isJavaIdentifierStart(c)); + check("{javaJavaIdentifierPart}", c, + Character.isJavaIdentifierPart(c)); + check("{javaUnicodeIdentifierStart}", c, + Character.isUnicodeIdentifierStart(c)); + check("{javaUnicodeIdentifierPart}", c, + Character.isUnicodeIdentifierPart(c)); + check("{javaIdentifierIgnorable}", c, + Character.isIdentifierIgnorable(c)); + check("{javaSpaceChar}", c, Character.isSpaceChar(c)); + check("{javaWhitespace}", c, Character.isWhitespace(c)); + check("{javaISOControl}", c, Character.isISOControl(c)); + check("{javaMirrored}", c, Character.isMirrored(c)); + } + + report("Java character classes"); + } + + // This test is for 4523620 + /* + private static void numOccurrencesTest() throws Exception { + Pattern pattern = Pattern.compile("aaa"); + + if (pattern.numOccurrences("aaaaaa", false) != 2) + failCount++; + if (pattern.numOccurrences("aaaaaa", true) != 4) + failCount++; + + pattern = Pattern.compile("^"); + if (pattern.numOccurrences("aaaaaa", false) != 1) + failCount++; + if (pattern.numOccurrences("aaaaaa", true) != 1) + failCount++; + + report("Number of Occurrences"); + } + */ + + // This test is for 4776374 + private static void caretBetweenTerminatorsTest() throws Exception { + int flags1 = Pattern.DOTALL; + int flags2 = Pattern.DOTALL | Pattern.UNIX_LINES; + int flags3 = Pattern.DOTALL | Pattern.UNIX_LINES | Pattern.MULTILINE; + int flags4 = Pattern.DOTALL | Pattern.MULTILINE; + + check("^....", flags1, "test\ntest", "test", true); + check(".....^", flags1, "test\ntest", "test", false); + check(".....^", flags1, "test\n", "test", false); + check("....^", flags1, "test\r\n", "test", false); + + check("^....", flags2, "test\ntest", "test", true); + check("....^", flags2, "test\ntest", "test", false); + check(".....^", flags2, "test\n", "test", false); + check("....^", flags2, "test\r\n", "test", false); + + check("^....", flags3, "test\ntest", "test", true); + check(".....^", flags3, "test\ntest", "test\n", true); + check(".....^", flags3, "test\u0085test", "test\u0085", false); + check(".....^", flags3, "test\n", "test", false); + check(".....^", flags3, "test\r\n", "test", false); + check("......^", flags3, "test\r\ntest", "test\r\n", true); + + check("^....", flags4, "test\ntest", "test", true); + check(".....^", flags3, "test\ntest", "test\n", true); + check(".....^", flags4, "test\u0085test", "test\u0085", true); + check(".....^", flags4, "test\n", "test\n", false); + check(".....^", flags4, "test\r\n", "test\r", false); + + // Supplementary character test + String t = toSupplementaries("test"); + check("^....", flags1, t+"\n"+t, t, true); + check(".....^", flags1, t+"\n"+t, t, false); + check(".....^", flags1, t+"\n", t, false); + check("....^", flags1, t+"\r\n", t, false); + + check("^....", flags2, t+"\n"+t, t, true); + check("....^", flags2, t+"\n"+t, t, false); + check(".....^", flags2, t+"\n", t, false); + check("....^", flags2, t+"\r\n", t, false); + + check("^....", flags3, t+"\n"+t, t, true); + check(".....^", flags3, t+"\n"+t, t+"\n", true); + check(".....^", flags3, t+"\u0085"+t, t+"\u0085", false); + check(".....^", flags3, t+"\n", t, false); + check(".....^", flags3, t+"\r\n", t, false); + check("......^", flags3, t+"\r\n"+t, t+"\r\n", true); + + check("^....", flags4, t+"\n"+t, t, true); + check(".....^", flags3, t+"\n"+t, t+"\n", true); + check(".....^", flags4, t+"\u0085"+t, t+"\u0085", true); + check(".....^", flags4, t+"\n", t+"\n", false); + check(".....^", flags4, t+"\r\n", t+"\r", false); + + report("Caret between terminators"); + } + + // This test is for 4727935 + private static void dollarAtEndTest() throws Exception { + int flags1 = Pattern.DOTALL; + int flags2 = Pattern.DOTALL | Pattern.UNIX_LINES; + int flags3 = Pattern.DOTALL | Pattern.MULTILINE; + + check("....$", flags1, "test\n", "test", true); + check("....$", flags1, "test\r\n", "test", true); + check(".....$", flags1, "test\n", "test\n", true); + check(".....$", flags1, "test\u0085", "test\u0085", true); + check("....$", flags1, "test\u0085", "test", true); + + check("....$", flags2, "test\n", "test", true); + check(".....$", flags2, "test\n", "test\n", true); + check(".....$", flags2, "test\u0085", "test\u0085", true); + check("....$", flags2, "test\u0085", "est\u0085", true); + + check("....$.blah", flags3, "test\nblah", "test\nblah", true); + check(".....$.blah", flags3, "test\n\nblah", "test\n\nblah", true); + check("....$blah", flags3, "test\nblah", "!!!!", false); + check(".....$blah", flags3, "test\nblah", "!!!!", false); + + // Supplementary character test + String t = toSupplementaries("test"); + String b = toSupplementaries("blah"); + check("....$", flags1, t+"\n", t, true); + check("....$", flags1, t+"\r\n", t, true); + check(".....$", flags1, t+"\n", t+"\n", true); + check(".....$", flags1, t+"\u0085", t+"\u0085", true); + check("....$", flags1, t+"\u0085", t, true); + + check("....$", flags2, t+"\n", t, true); + check(".....$", flags2, t+"\n", t+"\n", true); + check(".....$", flags2, t+"\u0085", t+"\u0085", true); + check("....$", flags2, t+"\u0085", toSupplementaries("est\u0085"), true); + + check("....$."+b, flags3, t+"\n"+b, t+"\n"+b, true); + check(".....$."+b, flags3, t+"\n\n"+b, t+"\n\n"+b, true); + check("....$"+b, flags3, t+"\n"+b, "!!!!", false); + check(".....$"+b, flags3, t+"\n"+b, "!!!!", false); + + report("Dollar at End"); + } + + // This test is for 4711773 + private static void multilineDollarTest() throws Exception { + Pattern findCR = Pattern.compile("$", Pattern.MULTILINE); + Matcher matcher = findCR.matcher("first bit\nsecond bit"); + matcher.find(); + if (matcher.start(0) != 9) + failCount++; + matcher.find(); + if (matcher.start(0) != 20) + failCount++; + + // Supplementary character test + matcher = findCR.matcher(toSupplementaries("first bit\n second bit")); // double BMP chars + matcher.find(); + if (matcher.start(0) != 9*2) + failCount++; + matcher.find(); + if (matcher.start(0) != 20*2) + failCount++; + + report("Multiline Dollar"); + } + + private static void reluctantRepetitionTest() throws Exception { + Pattern p = Pattern.compile("1(\\s\\S+?){1,3}?[\\s,]2"); + check(p, "1 word word word 2", true); + check(p, "1 wor wo w 2", true); + check(p, "1 word word 2", true); + check(p, "1 word 2", true); + check(p, "1 wo w w 2", true); + check(p, "1 wo w 2", true); + check(p, "1 wor w 2", true); + + p = Pattern.compile("([a-z])+?c"); + Matcher m = p.matcher("ababcdefdec"); + check(m, "ababc"); + + // Supplementary character test + p = Pattern.compile(toSupplementaries("([a-z])+?c")); + m = p.matcher(toSupplementaries("ababcdefdec")); + check(m, toSupplementaries("ababc")); + + report("Reluctant Repetition"); + } + + private static void serializeTest() throws Exception { + String patternStr = "(b)"; + String matchStr = "b"; + Pattern pattern = Pattern.compile(patternStr); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(pattern); + oos.close(); + ObjectInputStream ois = new ObjectInputStream( + new ByteArrayInputStream(baos.toByteArray())); + Pattern serializedPattern = (Pattern)ois.readObject(); + ois.close(); + Matcher matcher = serializedPattern.matcher(matchStr); + if (!matcher.matches()) + failCount++; + if (matcher.groupCount() != 1) + failCount++; + + report("Serialization"); + } + + private static void gTest() { + Pattern pattern = Pattern.compile("\\G\\w"); + Matcher matcher = pattern.matcher("abc#x#x"); + matcher.find(); + matcher.find(); + matcher.find(); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("\\GA*"); + matcher = pattern.matcher("1A2AA3"); + matcher.find(); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("\\GA*"); + matcher = pattern.matcher("1A2AA3"); + if (!matcher.find(1)) + failCount++; + matcher.find(); + if (matcher.find()) + failCount++; + + report("\\G"); + } + + private static void zTest() { + Pattern pattern = Pattern.compile("foo\\Z"); + // Positives + check(pattern, "foo\u0085", true); + check(pattern, "foo\u2028", true); + check(pattern, "foo\u2029", true); + check(pattern, "foo\n", true); + check(pattern, "foo\r", true); + check(pattern, "foo\r\n", true); + // Negatives + check(pattern, "fooo", false); + check(pattern, "foo\n\r", false); + + pattern = Pattern.compile("foo\\Z", Pattern.UNIX_LINES); + // Positives + check(pattern, "foo", true); + check(pattern, "foo\n", true); + // Negatives + check(pattern, "foo\r", false); + check(pattern, "foo\u0085", false); + check(pattern, "foo\u2028", false); + check(pattern, "foo\u2029", false); + + report("\\Z"); + } + + private static void replaceFirstTest() { + Pattern pattern = Pattern.compile("(ab)(c*)"); + Matcher matcher = pattern.matcher("abccczzzabcczzzabccc"); + if (!matcher.replaceFirst("test").equals("testzzzabcczzzabccc")) + failCount++; + + matcher.reset("zzzabccczzzabcczzzabccczzz"); + if (!matcher.replaceFirst("test").equals("zzztestzzzabcczzzabccczzz")) + failCount++; + + matcher.reset("zzzabccczzzabcczzzabccczzz"); + String result = matcher.replaceFirst("$1"); + if (!result.equals("zzzabzzzabcczzzabccczzz")) + failCount++; + + matcher.reset("zzzabccczzzabcczzzabccczzz"); + result = matcher.replaceFirst("$2"); + if (!result.equals("zzzccczzzabcczzzabccczzz")) + failCount++; + + pattern = Pattern.compile("a*"); + matcher = pattern.matcher("aaaaaaaaaa"); + if (!matcher.replaceFirst("test").equals("test")) + failCount++; + + pattern = Pattern.compile("a+"); + matcher = pattern.matcher("zzzaaaaaaaaaa"); + if (!matcher.replaceFirst("test").equals("zzztest")) + failCount++; + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("(ab)(c*)")); + matcher = pattern.matcher(toSupplementaries("abccczzzabcczzzabccc")); + if (!matcher.replaceFirst(toSupplementaries("test")) + .equals(toSupplementaries("testzzzabcczzzabccc"))) + failCount++; + + matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + if (!matcher.replaceFirst(toSupplementaries("test")). + equals(toSupplementaries("zzztestzzzabcczzzabccczzz"))) + failCount++; + + matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + result = matcher.replaceFirst("$1"); + if (!result.equals(toSupplementaries("zzzabzzzabcczzzabccczzz"))) + failCount++; + + matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + result = matcher.replaceFirst("$2"); + if (!result.equals(toSupplementaries("zzzccczzzabcczzzabccczzz"))) + failCount++; + + pattern = Pattern.compile(toSupplementaries("a*")); + matcher = pattern.matcher(toSupplementaries("aaaaaaaaaa")); + if (!matcher.replaceFirst(toSupplementaries("test")).equals(toSupplementaries("test"))) + failCount++; + + pattern = Pattern.compile(toSupplementaries("a+")); + matcher = pattern.matcher(toSupplementaries("zzzaaaaaaaaaa")); + if (!matcher.replaceFirst(toSupplementaries("test")).equals(toSupplementaries("zzztest"))) + failCount++; + + report("Replace First"); + } + + private static void unixLinesTest() { + Pattern pattern = Pattern.compile(".*"); + Matcher matcher = pattern.matcher("aa\u2028blah"); + matcher.find(); + if (!matcher.group(0).equals("aa")) + failCount++; + + pattern = Pattern.compile(".*", Pattern.UNIX_LINES); + matcher = pattern.matcher("aa\u2028blah"); + matcher.find(); + if (!matcher.group(0).equals("aa\u2028blah")) + failCount++; + + pattern = Pattern.compile("[az]$", + Pattern.MULTILINE | Pattern.UNIX_LINES); + matcher = pattern.matcher("aa\u2028zz"); + check(matcher, "a\u2028", false); + + // Supplementary character test + pattern = Pattern.compile(".*"); + matcher = pattern.matcher(toSupplementaries("aa\u2028blah")); + matcher.find(); + if (!matcher.group(0).equals(toSupplementaries("aa"))) + failCount++; + + pattern = Pattern.compile(".*", Pattern.UNIX_LINES); + matcher = pattern.matcher(toSupplementaries("aa\u2028blah")); + matcher.find(); + if (!matcher.group(0).equals(toSupplementaries("aa\u2028blah"))) + failCount++; + + pattern = Pattern.compile(toSupplementaries("[az]$"), + Pattern.MULTILINE | Pattern.UNIX_LINES); + matcher = pattern.matcher(toSupplementaries("aa\u2028zz")); + check(matcher, toSupplementaries("a\u2028"), false); + + report("Unix Lines"); + } + + private static void commentsTest() { + int flags = Pattern.COMMENTS; + + Pattern pattern = Pattern.compile("aa \\# aa", flags); + Matcher matcher = pattern.matcher("aa#aa"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah", flags); + matcher = pattern.matcher("aa"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa blah", flags); + matcher = pattern.matcher("aablah"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah blech ", flags); + matcher = pattern.matcher("aa"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah\n ", flags); + matcher = pattern.matcher("aa"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah\nbc # blech", flags); + matcher = pattern.matcher("aabc"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah\nbc# blech", flags); + matcher = pattern.matcher("aabc"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah\nbc\\# blech", flags); + matcher = pattern.matcher("aabc#blech"); + if (!matcher.matches()) + failCount++; + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("aa \\# aa"), flags); + matcher = pattern.matcher(toSupplementaries("aa#aa")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah"), flags); + matcher = pattern.matcher(toSupplementaries("aa")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa blah"), flags); + matcher = pattern.matcher(toSupplementaries("aablah")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah blech "), flags); + matcher = pattern.matcher(toSupplementaries("aa")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah\n "), flags); + matcher = pattern.matcher(toSupplementaries("aa")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah\nbc # blech"), flags); + matcher = pattern.matcher(toSupplementaries("aabc")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah\nbc# blech"), flags); + matcher = pattern.matcher(toSupplementaries("aabc")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah\nbc\\# blech"), flags); + matcher = pattern.matcher(toSupplementaries("aabc#blech")); + if (!matcher.matches()) + failCount++; + + report("Comments"); + } + + private static void caseFoldingTest() { // bug 4504687 + int flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE; + Pattern pattern = Pattern.compile("aa", flags); + Matcher matcher = pattern.matcher("ab"); + if (matcher.matches()) + failCount++; + + pattern = Pattern.compile("aA", flags); + matcher = pattern.matcher("ab"); + if (matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa", flags); + matcher = pattern.matcher("aB"); + if (matcher.matches()) + failCount++; + matcher = pattern.matcher("Ab"); + if (matcher.matches()) + failCount++; + + // ASCII "a" + // Latin-1 Supplement "a" + grave + // Cyrillic "a" + String[] patterns = new String[] { + //single + "a", "\u00e0", "\u0430", + //slice + "ab", "\u00e0\u00e1", "\u0430\u0431", + //class single + "[a]", "[\u00e0]", "[\u0430]", + //class range + "[a-b]", "[\u00e0-\u00e5]", "[\u0430-\u0431]", + //back reference + "(a)\\1", "(\u00e0)\\1", "(\u0430)\\1" + }; + + String[] texts = new String[] { + "A", "\u00c0", "\u0410", + "AB", "\u00c0\u00c1", "\u0410\u0411", + "A", "\u00c0", "\u0410", + "B", "\u00c2", "\u0411", + "aA", "\u00e0\u00c0", "\u0430\u0410" + }; + + boolean[] expected = new boolean[] { + true, false, false, + true, false, false, + true, false, false, + true, false, false, + true, false, false + }; + + flags = Pattern.CASE_INSENSITIVE; + for (int i = 0; i < patterns.length; i++) { + pattern = Pattern.compile(patterns[i], flags); + matcher = pattern.matcher(texts[i]); + if (matcher.matches() != expected[i]) { + System.out.println("<1> Failed at " + i); + failCount++; + } + } + + flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE; + for (int i = 0; i < patterns.length; i++) { + pattern = Pattern.compile(patterns[i], flags); + matcher = pattern.matcher(texts[i]); + if (!matcher.matches()) { + System.out.println("<2> Failed at " + i); + failCount++; + } + } + // flag unicode_case alone should do nothing + flags = Pattern.UNICODE_CASE; + for (int i = 0; i < patterns.length; i++) { + pattern = Pattern.compile(patterns[i], flags); + matcher = pattern.matcher(texts[i]); + if (matcher.matches()) { + System.out.println("<3> Failed at " + i); + failCount++; + } + } + + // Special cases: i, I, u+0131 and u+0130 + flags = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE; + pattern = Pattern.compile("[h-j]+", flags); + if (!pattern.matcher("\u0131\u0130").matches()) + failCount++; + report("Case Folding"); + } + + private static void appendTest() { + Pattern pattern = Pattern.compile("(ab)(cd)"); + Matcher matcher = pattern.matcher("abcd"); + String result = matcher.replaceAll("$2$1"); + if (!result.equals("cdab")) + failCount++; + + String s1 = "Swap all: first = 123, second = 456"; + String s2 = "Swap one: first = 123, second = 456"; + String r = "$3$2$1"; + pattern = Pattern.compile("([a-z]+)( *= *)([0-9]+)"); + matcher = pattern.matcher(s1); + + result = matcher.replaceAll(r); + if (!result.equals("Swap all: 123 = first, 456 = second")) + failCount++; + + matcher = pattern.matcher(s2); + + if (matcher.find()) { + StringBuffer sb = new StringBuffer(); + matcher.appendReplacement(sb, r); + matcher.appendTail(sb); + result = sb.toString(); + if (!result.equals("Swap one: 123 = first, second = 456")) + failCount++; + } + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("(ab)(cd)")); + matcher = pattern.matcher(toSupplementaries("abcd")); + result = matcher.replaceAll("$2$1"); + if (!result.equals(toSupplementaries("cdab"))) + failCount++; + + s1 = toSupplementaries("Swap all: first = 123, second = 456"); + s2 = toSupplementaries("Swap one: first = 123, second = 456"); + r = toSupplementaries("$3$2$1"); + pattern = Pattern.compile(toSupplementaries("([a-z]+)( *= *)([0-9]+)")); + matcher = pattern.matcher(s1); + + result = matcher.replaceAll(r); + if (!result.equals(toSupplementaries("Swap all: 123 = first, 456 = second"))) + failCount++; + + matcher = pattern.matcher(s2); + + if (matcher.find()) { + StringBuffer sb = new StringBuffer(); + matcher.appendReplacement(sb, r); + matcher.appendTail(sb); + result = sb.toString(); + if (!result.equals(toSupplementaries("Swap one: 123 = first, second = 456"))) + failCount++; + } + report("Append"); + } + + private static void splitTest() { + Pattern pattern = Pattern.compile(":"); + String[] result = pattern.split("foo:and:boo", 2); + if (!result[0].equals("foo")) + failCount++; + if (!result[1].equals("and:boo")) + failCount++; + // Supplementary character test + Pattern patternX = Pattern.compile(toSupplementaries("X")); + result = patternX.split(toSupplementaries("fooXandXboo"), 2); + if (!result[0].equals(toSupplementaries("foo"))) + failCount++; + if (!result[1].equals(toSupplementaries("andXboo"))) + failCount++; + + CharBuffer cb = CharBuffer.allocate(100); + cb.put("foo:and:boo"); + cb.flip(); + result = pattern.split(cb); + if (!result[0].equals("foo")) + failCount++; + if (!result[1].equals("and")) + failCount++; + if (!result[2].equals("boo")) + failCount++; + + // Supplementary character test + CharBuffer cbs = CharBuffer.allocate(100); + cbs.put(toSupplementaries("fooXandXboo")); + cbs.flip(); + result = patternX.split(cbs); + if (!result[0].equals(toSupplementaries("foo"))) + failCount++; + if (!result[1].equals(toSupplementaries("and"))) + failCount++; + if (!result[2].equals(toSupplementaries("boo"))) + failCount++; + + String source = "0123456789"; + for (int limit=-2; limit<3; limit++) { + for (int x=0; x<10; x++) { + result = source.split(Integer.toString(x), limit); + int expectedLength = limit < 1 ? 2 : limit; + + if ((limit == 0) && (x == 9)) { + // expected dropping of "" + if (result.length != 1) + failCount++; + if (!result[0].equals("012345678")) { + failCount++; + } + } else { + if (result.length != expectedLength) { + failCount++; + } + if (!result[0].equals(source.substring(0,x))) { + if (limit != 1) { + failCount++; + } else { + if (!result[0].equals(source.substring(0,10))) { + failCount++; + } + } + } + if (expectedLength > 1) { // Check segment 2 + if (!result[1].equals(source.substring(x+1,10))) + failCount++; + } + } + } + } + // Check the case for no match found + for (int limit=-2; limit<3; limit++) { + result = source.split("e", limit); + if (result.length != 1) + failCount++; + if (!result[0].equals(source)) + failCount++; + } + // Check the case for limit == 0, source = ""; + source = ""; + result = source.split("e", 0); + if (result.length != 1) + failCount++; + if (!result[0].equals(source)) + failCount++; + + report("Split"); + } + + private static void negationTest() { + Pattern pattern = Pattern.compile("[\\[@^]+"); + Matcher matcher = pattern.matcher("@@@@[[[[^^^^"); + if (!matcher.find()) + failCount++; + if (!matcher.group(0).equals("@@@@[[[[^^^^")) + failCount++; + pattern = Pattern.compile("[@\\[^]+"); + matcher = pattern.matcher("@@@@[[[[^^^^"); + if (!matcher.find()) + failCount++; + if (!matcher.group(0).equals("@@@@[[[[^^^^")) + failCount++; + pattern = Pattern.compile("[@\\[^@]+"); + matcher = pattern.matcher("@@@@[[[[^^^^"); + if (!matcher.find()) + failCount++; + if (!matcher.group(0).equals("@@@@[[[[^^^^")) + failCount++; + + pattern = Pattern.compile("\\)"); + matcher = pattern.matcher("xxx)xxx"); + if (!matcher.find()) + failCount++; + + report("Negation"); + } + + private static void ampersandTest() { + Pattern pattern = Pattern.compile("[&@]+"); + check(pattern, "@@@@&&&&", true); + + pattern = Pattern.compile("[@&]+"); + check(pattern, "@@@@&&&&", true); + + pattern = Pattern.compile("[@\\&]+"); + check(pattern, "@@@@&&&&", true); + + report("Ampersand"); + } + + private static void octalTest() throws Exception { + Pattern pattern = Pattern.compile("\\u0007"); + Matcher matcher = pattern.matcher("\u0007"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\07"); + matcher = pattern.matcher("\u0007"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\007"); + matcher = pattern.matcher("\u0007"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\0007"); + matcher = pattern.matcher("\u0007"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\040"); + matcher = pattern.matcher("\u0020"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\0403"); + matcher = pattern.matcher("\u00203"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\0103"); + matcher = pattern.matcher("\u0043"); + if (!matcher.matches()) + failCount++; + + report("Octal"); + } + + private static void longPatternTest() throws Exception { + try { + Pattern pattern = Pattern.compile( + "a 32-character-long pattern xxxx"); + pattern = Pattern.compile("a 33-character-long pattern xxxxx"); + pattern = Pattern.compile("a thirty four character long regex"); + StringBuffer patternToBe = new StringBuffer(101); + for (int i=0; i<100; i++) + patternToBe.append((char)(97 + i%26)); + pattern = Pattern.compile(patternToBe.toString()); + } catch (PatternSyntaxException e) { + failCount++; + } + + // Supplementary character test + try { + Pattern pattern = Pattern.compile( + toSupplementaries("a 32-character-long pattern xxxx")); + pattern = Pattern.compile(toSupplementaries("a 33-character-long pattern xxxxx")); + pattern = Pattern.compile(toSupplementaries("a thirty four character long regex")); + StringBuffer patternToBe = new StringBuffer(101*2); + for (int i=0; i<100; i++) + patternToBe.append(Character.toChars(Character.MIN_SUPPLEMENTARY_CODE_POINT + + 97 + i%26)); + pattern = Pattern.compile(patternToBe.toString()); + } catch (PatternSyntaxException e) { + failCount++; + } + report("LongPattern"); + } + + private static void group0Test() throws Exception { + Pattern pattern = Pattern.compile("(tes)ting"); + Matcher matcher = pattern.matcher("testing"); + check(matcher, "testing"); + + matcher.reset("testing"); + if (matcher.lookingAt()) { + if (!matcher.group(0).equals("testing")) + failCount++; + } else { + failCount++; + } + + matcher.reset("testing"); + if (matcher.matches()) { + if (!matcher.group(0).equals("testing")) + failCount++; + } else { + failCount++; + } + + pattern = Pattern.compile("(tes)ting"); + matcher = pattern.matcher("testing"); + if (matcher.lookingAt()) { + if (!matcher.group(0).equals("testing")) + failCount++; + } else { + failCount++; + } + + pattern = Pattern.compile("^(tes)ting"); + matcher = pattern.matcher("testing"); + if (matcher.matches()) { + if (!matcher.group(0).equals("testing")) + failCount++; + } else { + failCount++; + } + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("(tes)ting")); + matcher = pattern.matcher(toSupplementaries("testing")); + check(matcher, toSupplementaries("testing")); + + matcher.reset(toSupplementaries("testing")); + if (matcher.lookingAt()) { + if (!matcher.group(0).equals(toSupplementaries("testing"))) + failCount++; + } else { + failCount++; + } + + matcher.reset(toSupplementaries("testing")); + if (matcher.matches()) { + if (!matcher.group(0).equals(toSupplementaries("testing"))) + failCount++; + } else { + failCount++; + } + + pattern = Pattern.compile(toSupplementaries("(tes)ting")); + matcher = pattern.matcher(toSupplementaries("testing")); + if (matcher.lookingAt()) { + if (!matcher.group(0).equals(toSupplementaries("testing"))) + failCount++; + } else { + failCount++; + } + + pattern = Pattern.compile(toSupplementaries("^(tes)ting")); + matcher = pattern.matcher(toSupplementaries("testing")); + if (matcher.matches()) { + if (!matcher.group(0).equals(toSupplementaries("testing"))) + failCount++; + } else { + failCount++; + } + + report("Group0"); + } + + private static void findIntTest() throws Exception { + Pattern p = Pattern.compile("blah"); + Matcher m = p.matcher("zzzzblahzzzzzblah"); + boolean result = m.find(2); + if (!result) + failCount++; + + p = Pattern.compile("$"); + m = p.matcher("1234567890"); + result = m.find(10); + if (!result) + failCount++; + try { + result = m.find(11); + failCount++; + } catch (IndexOutOfBoundsException e) { + // correct result + } + + // Supplementary character test + p = Pattern.compile(toSupplementaries("blah")); + m = p.matcher(toSupplementaries("zzzzblahzzzzzblah")); + result = m.find(2); + if (!result) + failCount++; + + report("FindInt"); + } + + private static void emptyPatternTest() throws Exception { + Pattern p = Pattern.compile(""); + Matcher m = p.matcher("foo"); + + // Should find empty pattern at beginning of input + boolean result = m.find(); + if (result != true) + failCount++; + if (m.start() != 0) + failCount++; + + // Should not match entire input if input is not empty + m.reset(); + result = m.matches(); + if (result == true) + failCount++; + + try { + m.start(0); + failCount++; + } catch (IllegalStateException e) { + // Correct result + } + + // Should match entire input if input is empty + m.reset(""); + result = m.matches(); + if (result != true) + failCount++; + + result = Pattern.matches("", ""); + if (result != true) + failCount++; + + result = Pattern.matches("", "foo"); + if (result == true) + failCount++; + report("EmptyPattern"); + } + + private static void charClassTest() throws Exception { + Pattern pattern = Pattern.compile("blah[ab]]blech"); + check(pattern, "blahb]blech", true); + + pattern = Pattern.compile("[abc[def]]"); + check(pattern, "b", true); + + // Supplementary character tests + pattern = Pattern.compile(toSupplementaries("blah[ab]]blech")); + check(pattern, toSupplementaries("blahb]blech"), true); + + pattern = Pattern.compile(toSupplementaries("[abc[def]]")); + check(pattern, toSupplementaries("b"), true); + + try { + // u00ff when UNICODE_CASE + pattern = Pattern.compile("[ab\u00ffcd]", + Pattern.CASE_INSENSITIVE| + Pattern.UNICODE_CASE); + check(pattern, "ab\u00ffcd", true); + check(pattern, "Ab\u0178Cd", true); + + // u00b5 when UNICODE_CASE + pattern = Pattern.compile("[ab\u00b5cd]", + Pattern.CASE_INSENSITIVE| + Pattern.UNICODE_CASE); + check(pattern, "ab\u00b5cd", true); + check(pattern, "Ab\u039cCd", true); + } catch (Exception e) { failCount++; } + + /* Special cases + (1)LatinSmallLetterLongS u+017f + (2)LatinSmallLetterDotlessI u+0131 + (3)LatineCapitalLetterIWithDotAbove u+0130 + (4)KelvinSign u+212a + (5)AngstromSign u+212b + */ + int flags = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE; + pattern = Pattern.compile("[sik\u00c5]+", flags); + if (!pattern.matcher("\u017f\u0130\u0131\u212a\u212b").matches()) + failCount++; + + report("CharClass"); + } + + private static void caretTest() throws Exception { + Pattern pattern = Pattern.compile("\\w*"); + Matcher matcher = pattern.matcher("a#bc#def##g"); + check(matcher, "a"); + check(matcher, ""); + check(matcher, "bc"); + check(matcher, ""); + check(matcher, "def"); + check(matcher, ""); + check(matcher, ""); + check(matcher, "g"); + check(matcher, ""); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("^\\w*"); + matcher = pattern.matcher("a#bc#def##g"); + check(matcher, "a"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("\\w"); + matcher = pattern.matcher("abc##x"); + check(matcher, "a"); + check(matcher, "b"); + check(matcher, "c"); + check(matcher, "x"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("^\\w"); + matcher = pattern.matcher("abc##x"); + check(matcher, "a"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("\\A\\p{Alpha}{3}"); + matcher = pattern.matcher("abcdef-ghi\njklmno"); + check(matcher, "abc"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("^\\p{Alpha}{3}", Pattern.MULTILINE); + matcher = pattern.matcher("abcdef-ghi\njklmno"); + check(matcher, "abc"); + check(matcher, "jkl"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("^", Pattern.MULTILINE); + matcher = pattern.matcher("this is some text"); + String result = matcher.replaceAll("X"); + if (!result.equals("Xthis is some text")) + failCount++; + + pattern = Pattern.compile("^"); + matcher = pattern.matcher("this is some text"); + result = matcher.replaceAll("X"); + if (!result.equals("Xthis is some text")) + failCount++; + + pattern = Pattern.compile("^", Pattern.MULTILINE | Pattern.UNIX_LINES); + matcher = pattern.matcher("this is some text\n"); + result = matcher.replaceAll("X"); + if (!result.equals("Xthis is some text\n")) + failCount++; + + report("Caret"); + } + + private static void groupCaptureTest() throws Exception { + // Independent group + Pattern pattern = Pattern.compile("x+(?>y+)z+"); + Matcher matcher = pattern.matcher("xxxyyyzzz"); + matcher.find(); + try { + String blah = matcher.group(1); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Good result + } + // Pure group + pattern = Pattern.compile("x+(?:y+)z+"); + matcher = pattern.matcher("xxxyyyzzz"); + matcher.find(); + try { + String blah = matcher.group(1); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Good result + } + + // Supplementary character tests + // Independent group + pattern = Pattern.compile(toSupplementaries("x+(?>y+)z+")); + matcher = pattern.matcher(toSupplementaries("xxxyyyzzz")); + matcher.find(); + try { + String blah = matcher.group(1); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Good result + } + // Pure group + pattern = Pattern.compile(toSupplementaries("x+(?:y+)z+")); + matcher = pattern.matcher(toSupplementaries("xxxyyyzzz")); + matcher.find(); + try { + String blah = matcher.group(1); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Good result + } + + report("GroupCapture"); + } + + private static void backRefTest() throws Exception { + Pattern pattern = Pattern.compile("(a*)bc\\1"); + check(pattern, "zzzaabcazzz", true); + + pattern = Pattern.compile("(a*)bc\\1"); + check(pattern, "zzzaabcaazzz", true); + + pattern = Pattern.compile("(abc)(def)\\1"); + check(pattern, "abcdefabc", true); + + pattern = Pattern.compile("(abc)(def)\\3"); + check(pattern, "abcdefabc", false); + + try { + for (int i = 1; i < 10; i++) { + // Make sure backref 1-9 are always accepted + pattern = Pattern.compile("abcdef\\" + i); + // and fail to match if the target group does not exit + check(pattern, "abcdef", false); + } + } catch(PatternSyntaxException e) { + failCount++; + } + + pattern = Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)\\11"); + check(pattern, "abcdefghija", false); + check(pattern, "abcdefghija1", true); + + pattern = Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11"); + check(pattern, "abcdefghijkk", true); + + pattern = Pattern.compile("(a)bcdefghij\\11"); + check(pattern, "abcdefghija1", true); + + // Supplementary character tests + pattern = Pattern.compile(toSupplementaries("(a*)bc\\1")); + check(pattern, toSupplementaries("zzzaabcazzz"), true); + + pattern = Pattern.compile(toSupplementaries("(a*)bc\\1")); + check(pattern, toSupplementaries("zzzaabcaazzz"), true); + + pattern = Pattern.compile(toSupplementaries("(abc)(def)\\1")); + check(pattern, toSupplementaries("abcdefabc"), true); + + pattern = Pattern.compile(toSupplementaries("(abc)(def)\\3")); + check(pattern, toSupplementaries("abcdefabc"), false); + + pattern = Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)\\11")); + check(pattern, toSupplementaries("abcdefghija"), false); + check(pattern, toSupplementaries("abcdefghija1"), true); + + pattern = Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11")); + check(pattern, toSupplementaries("abcdefghijkk"), true); + + report("BackRef"); + } + + /** + * Unicode Technical Report #18, section 2.6 End of Line + * There is no empty line to be matched in the sequence \u000D\u000A + * but there is an empty line in the sequence \u000A\u000D. + */ + private static void anchorTest() throws Exception { + Pattern p = Pattern.compile("^.*$", Pattern.MULTILINE); + Matcher m = p.matcher("blah1\r\nblah2"); + m.find(); + m.find(); + if (!m.group().equals("blah2")) + failCount++; + + m.reset("blah1\n\rblah2"); + m.find(); + m.find(); + m.find(); + if (!m.group().equals("blah2")) + failCount++; + + // Test behavior of $ with \r\n at end of input + p = Pattern.compile(".+$"); + m = p.matcher("blah1\r\n"); + if (!m.find()) + failCount++; + if (!m.group().equals("blah1")) + failCount++; + if (m.find()) + failCount++; + + // Test behavior of $ with \r\n at end of input in multiline + p = Pattern.compile(".+$", Pattern.MULTILINE); + m = p.matcher("blah1\r\n"); + if (!m.find()) + failCount++; + if (m.find()) + failCount++; + + // Test for $ recognition of \u0085 for bug 4527731 + p = Pattern.compile(".+$", Pattern.MULTILINE); + m = p.matcher("blah1\u0085"); + if (!m.find()) + failCount++; + + // Supplementary character test + p = Pattern.compile("^.*$", Pattern.MULTILINE); + m = p.matcher(toSupplementaries("blah1\r\nblah2")); + m.find(); + m.find(); + if (!m.group().equals(toSupplementaries("blah2"))) + failCount++; + + m.reset(toSupplementaries("blah1\n\rblah2")); + m.find(); + m.find(); + m.find(); + if (!m.group().equals(toSupplementaries("blah2"))) + failCount++; + + // Test behavior of $ with \r\n at end of input + p = Pattern.compile(".+$"); + m = p.matcher(toSupplementaries("blah1\r\n")); + if (!m.find()) + failCount++; + if (!m.group().equals(toSupplementaries("blah1"))) + failCount++; + if (m.find()) + failCount++; + + // Test behavior of $ with \r\n at end of input in multiline + p = Pattern.compile(".+$", Pattern.MULTILINE); + m = p.matcher(toSupplementaries("blah1\r\n")); + if (!m.find()) + failCount++; + if (m.find()) + failCount++; + + // Test for $ recognition of \u0085 for bug 4527731 + p = Pattern.compile(".+$", Pattern.MULTILINE); + m = p.matcher(toSupplementaries("blah1\u0085")); + if (!m.find()) + failCount++; + + report("Anchors"); + } + + /** + * A basic sanity test of Matcher.lookingAt(). + */ + private static void lookingAtTest() throws Exception { + Pattern p = Pattern.compile("(ab)(c*)"); + Matcher m = p.matcher("abccczzzabcczzzabccc"); + + if (!m.lookingAt()) + failCount++; + + if (!m.group().equals(m.group(0))) + failCount++; + + m = p.matcher("zzzabccczzzabcczzzabccczzz"); + if (m.lookingAt()) + failCount++; + + // Supplementary character test + p = Pattern.compile(toSupplementaries("(ab)(c*)")); + m = p.matcher(toSupplementaries("abccczzzabcczzzabccc")); + + if (!m.lookingAt()) + failCount++; + + if (!m.group().equals(m.group(0))) + failCount++; + + m = p.matcher(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + if (m.lookingAt()) + failCount++; + + report("Looking At"); + } + + /** + * A basic sanity test of Matcher.matches(). + */ + private static void matchesTest() throws Exception { + // matches() + Pattern p = Pattern.compile("ulb(c*)"); + Matcher m = p.matcher("ulbcccccc"); + if (!m.matches()) + failCount++; + + // find() but not matches() + m.reset("zzzulbcccccc"); + if (m.matches()) + failCount++; + + // lookingAt() but not matches() + m.reset("ulbccccccdef"); + if (m.matches()) + failCount++; + + // matches() + p = Pattern.compile("a|ad"); + m = p.matcher("ad"); + if (!m.matches()) + failCount++; + + // Supplementary character test + // matches() + p = Pattern.compile(toSupplementaries("ulb(c*)")); + m = p.matcher(toSupplementaries("ulbcccccc")); + if (!m.matches()) + failCount++; + + // find() but not matches() + m.reset(toSupplementaries("zzzulbcccccc")); + if (m.matches()) + failCount++; + + // lookingAt() but not matches() + m.reset(toSupplementaries("ulbccccccdef")); + if (m.matches()) + failCount++; + + // matches() + p = Pattern.compile(toSupplementaries("a|ad")); + m = p.matcher(toSupplementaries("ad")); + if (!m.matches()) + failCount++; + + report("Matches"); + } + + /** + * A basic sanity test of Pattern.matches(). + */ + private static void patternMatchesTest() throws Exception { + // matches() + if (!Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbcccccc"))) + failCount++; + + // find() but not matches() + if (Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("zzzulbcccccc"))) + failCount++; + + // lookingAt() but not matches() + if (Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbccccccdef"))) + failCount++; + + // Supplementary character test + // matches() + if (!Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbcccccc"))) + failCount++; + + // find() but not matches() + if (Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("zzzulbcccccc"))) + failCount++; + + // lookingAt() but not matches() + if (Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbccccccdef"))) + failCount++; + + report("Pattern Matches"); + } + + /** + * Canonical equivalence testing. Tests the ability of the engine + * to match sequences that are not explicitly specified in the + * pattern when they are considered equivalent by the Unicode Standard. + */ + private static void ceTest() throws Exception { + // Decomposed char outside char classes + Pattern p = Pattern.compile("testa\u030a", Pattern.CANON_EQ); + Matcher m = p.matcher("test\u00e5"); + if (!m.matches()) + failCount++; + + m.reset("testa\u030a"); + if (!m.matches()) + failCount++; + + // Composed char outside char classes + p = Pattern.compile("test\u00e5", Pattern.CANON_EQ); + m = p.matcher("test\u00e5"); + if (!m.matches()) + failCount++; + + m.reset("testa\u030a"); + if (!m.find()) + failCount++; + + // Decomposed char inside a char class + p = Pattern.compile("test[abca\u030a]", Pattern.CANON_EQ); + m = p.matcher("test\u00e5"); + if (!m.find()) + failCount++; + + m.reset("testa\u030a"); + if (!m.find()) + failCount++; + + // Composed char inside a char class + p = Pattern.compile("test[abc\u00e5def\u00e0]", Pattern.CANON_EQ); + m = p.matcher("test\u00e5"); + if (!m.find()) + failCount++; + + m.reset("testa\u0300"); + if (!m.find()) + failCount++; + + m.reset("testa\u030a"); + if (!m.find()) + failCount++; + + // Marks that cannot legally change order and be equivalent + p = Pattern.compile("testa\u0308\u0300", Pattern.CANON_EQ); + check(p, "testa\u0308\u0300", true); + check(p, "testa\u0300\u0308", false); + + // Marks that can legally change order and be equivalent + p = Pattern.compile("testa\u0308\u0323", Pattern.CANON_EQ); + check(p, "testa\u0308\u0323", true); + check(p, "testa\u0323\u0308", true); + + // Test all equivalences of the sequence a\u0308\u0323\u0300 + p = Pattern.compile("testa\u0308\u0323\u0300", Pattern.CANON_EQ); + check(p, "testa\u0308\u0323\u0300", true); + check(p, "testa\u0323\u0308\u0300", true); + check(p, "testa\u0308\u0300\u0323", true); + check(p, "test\u00e4\u0323\u0300", true); + check(p, "test\u00e4\u0300\u0323", true); + + /* + * The following canonical equivalence tests don't work. Bug id: 4916384. + * + // Decomposed hangul (jamos) + p = Pattern.compile("\u1100\u1161", Pattern.CANON_EQ); + m = p.matcher("\u1100\u1161"); + if (!m.matches()) + failCount++; + + m.reset("\uac00"); + if (!m.matches()) + failCount++; + + // Composed hangul + p = Pattern.compile("\uac00", Pattern.CANON_EQ); + m = p.matcher("\u1100\u1161"); + if (!m.matches()) + failCount++; + + m.reset("\uac00"); + if (!m.matches()) + failCount++; + + // Decomposed supplementary outside char classes + p = Pattern.compile("test\ud834\uddbc\ud834\udd6f", Pattern.CANON_EQ); + m = p.matcher("test\ud834\uddc0"); + if (!m.matches()) + failCount++; + + m.reset("test\ud834\uddbc\ud834\udd6f"); + if (!m.matches()) + failCount++; + + // Composed supplementary outside char classes + p = Pattern.compile("test\ud834\uddc0", Pattern.CANON_EQ); + m.reset("test\ud834\uddbc\ud834\udd6f"); + if (!m.matches()) + failCount++; + + m = p.matcher("test\ud834\uddc0"); + if (!m.matches()) + failCount++; + + */ + + report("Canonical Equivalence"); + } + + /** + * A basic sanity test of Matcher.replaceAll(). + */ + private static void globalSubstitute() throws Exception { + // Global substitution with a literal + Pattern p = Pattern.compile("(ab)(c*)"); + Matcher m = p.matcher("abccczzzabcczzzabccc"); + if (!m.replaceAll("test").equals("testzzztestzzztest")) + failCount++; + + m.reset("zzzabccczzzabcczzzabccczzz"); + if (!m.replaceAll("test").equals("zzztestzzztestzzztestzzz")) + failCount++; + + // Global substitution with groups + m.reset("zzzabccczzzabcczzzabccczzz"); + String result = m.replaceAll("$1"); + if (!result.equals("zzzabzzzabzzzabzzz")) + failCount++; + + // Supplementary character test + // Global substitution with a literal + p = Pattern.compile(toSupplementaries("(ab)(c*)")); + m = p.matcher(toSupplementaries("abccczzzabcczzzabccc")); + if (!m.replaceAll(toSupplementaries("test")). + equals(toSupplementaries("testzzztestzzztest"))) + failCount++; + + m.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + if (!m.replaceAll(toSupplementaries("test")). + equals(toSupplementaries("zzztestzzztestzzztestzzz"))) + failCount++; + + // Global substitution with groups + m.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + result = m.replaceAll("$1"); + if (!result.equals(toSupplementaries("zzzabzzzabzzzabzzz"))) + failCount++; + + report("Global Substitution"); + } + + /** + * Tests the usage of Matcher.appendReplacement() with literal + * and group substitutions. + */ + private static void stringbufferSubstitute() throws Exception { + // SB substitution with literal + String blah = "zzzblahzzz"; + Pattern p = Pattern.compile("blah"); + Matcher m = p.matcher(blah); + StringBuffer result = new StringBuffer(); + try { + m.appendReplacement(result, "blech"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "blech"); + if (!result.toString().equals("zzzblech")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzblechzzz")) + failCount++; + + // SB substitution with groups + blah = "zzzabcdzzz"; + p = Pattern.compile("(ab)(cd)*"); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals("zzzab")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabzzz")) + failCount++; + + // SB substitution with 3 groups + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1w$2w$3"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1w$2w$3"); + if (!result.toString().equals("zzzabwcdwef")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabwcdwefzzz")) + failCount++; + + // SB substitution with groups and three matches + // skipping middle match + blah = "zzzabcdzzzabcddzzzabcdzzz"; + p = Pattern.compile("(ab)(cd*)"); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals("zzzab")) + failCount++; + + m.find(); + m.find(); + m.appendReplacement(result, "$2"); + if (!result.toString().equals("zzzabzzzabcddzzzcd")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabzzzabcddzzzcdzzz")) + failCount++; + + // Check to make sure escaped $ is ignored + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, "$1w\\$2w$3"); + if (!result.toString().equals("zzzabw$2wef")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabw$2wefzzz")) + failCount++; + + // Check to make sure a reference to nonexistent group causes error + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + try { + m.appendReplacement(result, "$1w$5w$3"); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } + + // Check double digit group references + blah = "zzz123456789101112zzz"; + p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, "$1w$11w$3"); + if (!result.toString().equals("zzz1w11w3")) + failCount++; + + // Check to make sure it backs off $15 to $1 if only three groups + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, "$1w$15w$3"); + if (!result.toString().equals("zzzabwab5wef")) + failCount++; + + + // Supplementary character test + // SB substitution with literal + blah = toSupplementaries("zzzblahzzz"); + p = Pattern.compile(toSupplementaries("blah")); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, toSupplementaries("blech")); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, toSupplementaries("blech")); + if (!result.toString().equals(toSupplementaries("zzzblech"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzblechzzz"))) + failCount++; + + // SB substitution with groups + blah = toSupplementaries("zzzabcdzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*")); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals(toSupplementaries("zzzab"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabzzz"))) + failCount++; + + // SB substitution with 3 groups + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, toSupplementaries("$1w$2w$3")); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$2w$3")); + if (!result.toString().equals(toSupplementaries("zzzabwcdwef"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabwcdwefzzz"))) + failCount++; + + // SB substitution with groups and three matches + // skipping middle match + blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd*)")); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals(toSupplementaries("zzzab"))) + failCount++; + + m.find(); + m.find(); + m.appendReplacement(result, "$2"); + if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcd"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcdzzz"))) + failCount++; + + // Check to make sure escaped $ is ignored + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w\\$2w$3")); + if (!result.toString().equals(toSupplementaries("zzzabw$2wef"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabw$2wefzzz"))) + failCount++; + + // Check to make sure a reference to nonexistent group causes error + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + try { + m.appendReplacement(result, toSupplementaries("$1w$5w$3")); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } + + // Check double digit group references + blah = toSupplementaries("zzz123456789101112zzz"); + p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$11w$3")); + if (!result.toString().equals(toSupplementaries("zzz1w11w3"))) + failCount++; + + // Check to make sure it backs off $15 to $1 if only three groups + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$15w$3")); + if (!result.toString().equals(toSupplementaries("zzzabwab5wef"))) + failCount++; + + // Check nothing has been appended into the output buffer if + // the replacement string triggers IllegalArgumentException. + p = Pattern.compile("(abc)"); + m = p.matcher("abcd"); + result = new StringBuffer(); + m.find(); + try { + m.appendReplacement(result, ("xyz$g")); + failCount++; + } catch (IllegalArgumentException iae) { + if (result.length() != 0) + failCount++; + } + + report("SB Substitution"); + } + + /* + * 5 groups of characters are created to make a substitution string. + * A base string will be created including random lead chars, the + * substitution string, and random trailing chars. + * A pattern containing the 5 groups is searched for and replaced with: + * random group + random string + random group. + * The results are checked for correctness. + */ + private static void substitutionBasher() { + for (int runs = 0; runs<1000; runs++) { + // Create a base string to work in + int leadingChars = generator.nextInt(10); + StringBuffer baseBuffer = new StringBuffer(100); + String leadingString = getRandomAlphaString(leadingChars); + baseBuffer.append(leadingString); + + // Create 5 groups of random number of random chars + // Create the string to substitute + // Create the pattern string to search for + StringBuffer bufferToSub = new StringBuffer(25); + StringBuffer bufferToPat = new StringBuffer(50); + String[] groups = new String[5]; + for(int i=0; i<5; i++) { + int aGroupSize = generator.nextInt(5)+1; + groups[i] = getRandomAlphaString(aGroupSize); + bufferToSub.append(groups[i]); + bufferToPat.append('('); + bufferToPat.append(groups[i]); + bufferToPat.append(')'); + } + String stringToSub = bufferToSub.toString(); + String pattern = bufferToPat.toString(); + + // Place sub string into working string at random index + baseBuffer.append(stringToSub); + + // Append random chars to end + int trailingChars = generator.nextInt(10); + String trailingString = getRandomAlphaString(trailingChars); + baseBuffer.append(trailingString); + String baseString = baseBuffer.toString(); + + // Create test pattern and matcher + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(baseString); + + // Reject candidate if pattern happens to start early + m.find(); + if (m.start() < leadingChars) + continue; + + // Reject candidate if more than one match + if (m.find()) + continue; + + // Construct a replacement string with : + // random group + random string + random group + StringBuffer bufferToRep = new StringBuffer(); + int groupIndex1 = generator.nextInt(5); + bufferToRep.append("$" + (groupIndex1 + 1)); + String randomMidString = getRandomAlphaString(5); + bufferToRep.append(randomMidString); + int groupIndex2 = generator.nextInt(5); + bufferToRep.append("$" + (groupIndex2 + 1)); + String replacement = bufferToRep.toString(); + + // Do the replacement + String result = m.replaceAll(replacement); + + // Construct expected result + StringBuffer bufferToRes = new StringBuffer(); + bufferToRes.append(leadingString); + bufferToRes.append(groups[groupIndex1]); + bufferToRes.append(randomMidString); + bufferToRes.append(groups[groupIndex2]); + bufferToRes.append(trailingString); + String expectedResult = bufferToRes.toString(); + + // Check results + if (!result.equals(expectedResult)) + failCount++; + } + + report("Substitution Basher"); + } + + /** + * Checks the handling of some escape sequences that the Pattern + * class should process instead of the java compiler. These are + * not in the file because the escapes should be be processed + * by the Pattern class when the regex is compiled. + */ + private static void escapes() throws Exception { + Pattern p = Pattern.compile("\\043"); + Matcher m = p.matcher("#"); + if (!m.find()) + failCount++; + + p = Pattern.compile("\\x23"); + m = p.matcher("#"); + if (!m.find()) + failCount++; + + p = Pattern.compile("\\u0023"); + m = p.matcher("#"); + if (!m.find()) + failCount++; + + report("Escape sequences"); + } + + /** + * Checks the handling of blank input situations. These + * tests are incompatible with my test file format. + */ + private static void blankInput() throws Exception { + Pattern p = Pattern.compile("abc", Pattern.CASE_INSENSITIVE); + Matcher m = p.matcher(""); + if (m.find()) + failCount++; + + p = Pattern.compile("a*", Pattern.CASE_INSENSITIVE); + m = p.matcher(""); + if (!m.find()) + failCount++; + + p = Pattern.compile("abc"); + m = p.matcher(""); + if (m.find()) + failCount++; + + p = Pattern.compile("a*"); + m = p.matcher(""); + if (!m.find()) + failCount++; + + report("Blank input"); + } + + /** + * Tests the Boyer-Moore pattern matching of a character sequence + * on randomly generated patterns. + */ + private static void bm() throws Exception { + doBnM('a'); + report("Boyer Moore (ASCII)"); + + doBnM(Character.MIN_SUPPLEMENTARY_CODE_POINT - 10); + report("Boyer Moore (Supplementary)"); + } + + private static void doBnM(int baseCharacter) throws Exception { + int achar=0; + + for (int i=0; i<100; i++) { + // Create a short pattern to search for + int patternLength = generator.nextInt(7) + 4; + StringBuffer patternBuffer = new StringBuffer(patternLength); + for (int x=0; x<patternLength; x++) { + int ch = baseCharacter + generator.nextInt(26); + if (Character.isSupplementaryCodePoint(ch)) { + patternBuffer.append(Character.toChars(ch)); + } else { + patternBuffer.append((char)ch); + } + } + String pattern = patternBuffer.toString(); + Pattern p = Pattern.compile(pattern); + + // Create a buffer with random ASCII chars that does + // not match the sample + String toSearch = null; + StringBuffer s = null; + Matcher m = p.matcher(""); + do { + s = new StringBuffer(100); + for (int x=0; x<100; x++) { + int ch = baseCharacter + generator.nextInt(26); + if (Character.isSupplementaryCodePoint(ch)) { + s.append(Character.toChars(ch)); + } else { + s.append((char)ch); + } + } + toSearch = s.toString(); + m.reset(toSearch); + } while (m.find()); + + // Insert the pattern at a random spot + int insertIndex = generator.nextInt(99); + if (Character.isLowSurrogate(s.charAt(insertIndex))) + insertIndex++; + s = s.insert(insertIndex, pattern); + toSearch = s.toString(); + + // Make sure that the pattern is found + m.reset(toSearch); + if (!m.find()) + failCount++; + + // Make sure that the match text is the pattern + if (!m.group().equals(pattern)) + failCount++; + + // Make sure match occured at insertion point + if (m.start() != insertIndex) + failCount++; + } + } + + /** + * Tests the matching of slices on randomly generated patterns. + * The Boyer-Moore optimization is not done on these patterns + * because it uses unicode case folding. + */ + private static void slice() throws Exception { + doSlice(Character.MAX_VALUE); + report("Slice"); + + doSlice(Character.MAX_CODE_POINT); + report("Slice (Supplementary)"); + } + + private static void doSlice(int maxCharacter) throws Exception { + Random generator = new Random(); + int achar=0; + + for (int i=0; i<100; i++) { + // Create a short pattern to search for + int patternLength = generator.nextInt(7) + 4; + StringBuffer patternBuffer = new StringBuffer(patternLength); + for (int x=0; x<patternLength; x++) { + int randomChar = 0; + while (!Character.isLetterOrDigit(randomChar)) + randomChar = generator.nextInt(maxCharacter); + if (Character.isSupplementaryCodePoint(randomChar)) { + patternBuffer.append(Character.toChars(randomChar)); + } else { + patternBuffer.append((char) randomChar); + } + } + String pattern = patternBuffer.toString(); + Pattern p = Pattern.compile(pattern, Pattern.UNICODE_CASE); + + // Create a buffer with random chars that does not match the sample + String toSearch = null; + StringBuffer s = null; + Matcher m = p.matcher(""); + do { + s = new StringBuffer(100); + for (int x=0; x<100; x++) { + int randomChar = 0; + while (!Character.isLetterOrDigit(randomChar)) + randomChar = generator.nextInt(maxCharacter); + if (Character.isSupplementaryCodePoint(randomChar)) { + s.append(Character.toChars(randomChar)); + } else { + s.append((char) randomChar); + } + } + toSearch = s.toString(); + m.reset(toSearch); + } while (m.find()); + + // Insert the pattern at a random spot + int insertIndex = generator.nextInt(99); + if (Character.isLowSurrogate(s.charAt(insertIndex))) + insertIndex++; + s = s.insert(insertIndex, pattern); + toSearch = s.toString(); + + // Make sure that the pattern is found + m.reset(toSearch); + if (!m.find()) + failCount++; + + // Make sure that the match text is the pattern + if (!m.group().equals(pattern)) + failCount++; + + // Make sure match occured at insertion point + if (m.start() != insertIndex) + failCount++; + } + } + + private static void explainFailure(String pattern, String data, + String expected, String actual) { + System.err.println("----------------------------------------"); + System.err.println("Pattern = "+pattern); + System.err.println("Data = "+data); + System.err.println("Expected = " + expected); + System.err.println("Actual = " + actual); + } + + private static void explainFailure(String pattern, String data, + Throwable t) { + System.err.println("----------------------------------------"); + System.err.println("Pattern = "+pattern); + System.err.println("Data = "+data); + t.printStackTrace(System.err); + } + + // Testing examples from a file + + /** + * Goes through the file "TestCases.txt" and creates many patterns + * described in the file, matching the patterns against input lines in + * the file, and comparing the results against the correct results + * also found in the file. The file format is described in comments + * at the head of the file. + */ + private static void processFile(String fileName) throws Exception { + File testCases = new File(System.getProperty("test.src", "."), + fileName); + FileInputStream in = new FileInputStream(testCases); + BufferedReader r = new BufferedReader(new InputStreamReader(in)); + + // Process next test case. + String aLine; + while((aLine = r.readLine()) != null) { + // Read a line for pattern + String patternString = grabLine(r); + Pattern p = null; + try { + p = compileTestPattern(patternString); + } catch (PatternSyntaxException e) { + String dataString = grabLine(r); + String expectedResult = grabLine(r); + if (expectedResult.startsWith("error")) + continue; + explainFailure(patternString, dataString, e); + failCount++; + continue; + } + + // Read a line for input string + String dataString = grabLine(r); + Matcher m = p.matcher(dataString); + StringBuffer result = new StringBuffer(); + + // Check for IllegalStateExceptions before a match + failCount += preMatchInvariants(m); + + boolean found = m.find(); + + if (found) + failCount += postTrueMatchInvariants(m); + else + failCount += postFalseMatchInvariants(m); + + if (found) { + result.append("true "); + result.append(m.group(0) + " "); + } else { + result.append("false "); + } + + result.append(m.groupCount()); + + if (found) { + for (int i=1; i<m.groupCount()+1; i++) + if (m.group(i) != null) + result.append(" " +m.group(i)); + } + + // Read a line for the expected result + String expectedResult = grabLine(r); + + if (!result.toString().equals(expectedResult)) { + explainFailure(patternString, dataString, expectedResult, result.toString()); + failCount++; + } + } + + report(fileName); + } + + private static int preMatchInvariants(Matcher m) { + int failCount = 0; + try { + m.start(); + failCount++; + } catch (IllegalStateException ise) {} + try { + m.end(); + failCount++; + } catch (IllegalStateException ise) {} + try { + m.group(); + failCount++; + } catch (IllegalStateException ise) {} + return failCount; + } + + private static int postFalseMatchInvariants(Matcher m) { + int failCount = 0; + try { + m.group(); + failCount++; + } catch (IllegalStateException ise) {} + try { + m.start(); + failCount++; + } catch (IllegalStateException ise) {} + try { + m.end(); + failCount++; + } catch (IllegalStateException ise) {} + return failCount; + } + + private static int postTrueMatchInvariants(Matcher m) { + int failCount = 0; + //assert(m.start() = m.start(0); + if (m.start() != m.start(0)) + failCount++; + //assert(m.end() = m.end(0); + if (m.start() != m.start(0)) + failCount++; + //assert(m.group() = m.group(0); + if (!m.group().equals(m.group(0))) + failCount++; + try { + m.group(50); + failCount++; + } catch (IndexOutOfBoundsException ise) {} + + return failCount; + } + + private static Pattern compileTestPattern(String patternString) { + if (!patternString.startsWith("'")) { + return Pattern.compile(patternString); + } + + int break1 = patternString.lastIndexOf("'"); + String flagString = patternString.substring( + break1+1, patternString.length()); + patternString = patternString.substring(1, break1); + + if (flagString.equals("i")) + return Pattern.compile(patternString, Pattern.CASE_INSENSITIVE); + + if (flagString.equals("m")) + return Pattern.compile(patternString, Pattern.MULTILINE); + + return Pattern.compile(patternString); + } + + /** + * Reads a line from the input file. Keeps reading lines until a non + * empty non comment line is read. If the line contains a \n then + * these two characters are replaced by a newline char. If a \\uxxxx + * sequence is read then the sequence is replaced by the unicode char. + */ + private static String grabLine(BufferedReader r) throws Exception { + int index = 0; + String line = r.readLine(); + while (line.startsWith("//") || line.length() < 1) + line = r.readLine(); + while ((index = line.indexOf("\\n")) != -1) { + StringBuffer temp = new StringBuffer(line); + temp.replace(index, index+2, "\n"); + line = temp.toString(); + } + while ((index = line.indexOf("\\u")) != -1) { + StringBuffer temp = new StringBuffer(line); + String value = temp.substring(index+2, index+6); + char aChar = (char)Integer.parseInt(value, 16); + String unicodeChar = "" + aChar; + temp.replace(index, index+6, unicodeChar); + line = temp.toString(); + } + + return line; + } + + private static void check(Pattern p, String s, String g, String expected) { + Matcher m = p.matcher(s); + m.find(); + if (!m.group(g).equals(expected)) + failCount++; + } + + private static void checkReplaceFirst(String p, String s, String r, String expected) + { + if (!expected.equals(Pattern.compile(p) + .matcher(s) + .replaceFirst(r))) + failCount++; + } + + private static void checkReplaceAll(String p, String s, String r, String expected) + { + if (!expected.equals(Pattern.compile(p) + .matcher(s) + .replaceAll(r))) + failCount++; + } + + private static void checkExpectedFail(String p) { + try { + Pattern.compile(p); + } catch (PatternSyntaxException pse) { + //pse.printStackTrace(); + return; + } + failCount++; + } + + private static void checkExpectedFail(Matcher m, String g) { + m.find(); + try { + m.group(g); + } catch (IllegalArgumentException iae) { + //iae.printStackTrace(); + return; + } catch (NullPointerException npe) { + return; + } + failCount++; + } + + + private static void namedGroupCaptureTest() throws Exception { + check(Pattern.compile("x+(?<gname>y+)z+"), + "xxxyyyzzz", + "gname", + "yyy"); + + check(Pattern.compile("x+(?<8gname>y+)z+"), + "xxxyyyzzz", + "8gname", + "yyy"); + + //backref + Pattern pattern = Pattern.compile("(a*)bc\\1"); + check(pattern, "zzzaabcazzz", true); // found "abca" + + check(Pattern.compile("(?<gname>a*)bc\\k<gname>"), + "zzzaabcaazzz", true); + + check(Pattern.compile("(?<gname>abc)(def)\\k<gname>"), + "abcdefabc", true); + + check(Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(?<gname>k)\\k<gname>"), + "abcdefghijkk", true); + + // Supplementary character tests + check(Pattern.compile("(?<gname>" + toSupplementaries("a*)bc") + "\\k<gname>"), + toSupplementaries("zzzaabcazzz"), true); + + check(Pattern.compile("(?<gname>" + toSupplementaries("a*)bc") + "\\k<gname>"), + toSupplementaries("zzzaabcaazzz"), true); + + check(Pattern.compile("(?<gname>" + toSupplementaries("abc)(def)") + "\\k<gname>"), + toSupplementaries("abcdefabc"), true); + + check(Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)") + + "(?<gname>" + + toSupplementaries("k)") + "\\k<gname>"), + toSupplementaries("abcdefghijkk"), true); + + check(Pattern.compile("x+(?<gname>y+)z+\\k<gname>"), + "xxxyyyzzzyyy", + "gname", + "yyy"); + + //replaceFirst/All + checkReplaceFirst("(?<gn>ab)(c*)", + "abccczzzabcczzzabccc", + "$<gn>", + "abzzzabcczzzabccc"); + + checkReplaceAll("(?<gn>ab)(c*)", + "abccczzzabcczzzabccc", + "$<gn>", + "abzzzabzzzab"); + + + checkReplaceFirst("(?<gn>ab)(c*)", + "zzzabccczzzabcczzzabccczzz", + "$<gn>", + "zzzabzzzabcczzzabccczzz"); + + checkReplaceAll("(?<gn>ab)(c*)", + "zzzabccczzzabcczzzabccczzz", + "$<gn>", + "zzzabzzzabzzzabzzz"); + + checkReplaceFirst("(?<gn1>ab)(?<gn2>c*)", + "zzzabccczzzabcczzzabccczzz", + "$<gn2>", + "zzzccczzzabcczzzabccczzz"); + + checkReplaceAll("(?<gn1>ab)(?<gn2>c*)", + "zzzabccczzzabcczzzabccczzz", + "$<gn2>", + "zzzccczzzcczzzccczzz"); + + //toSupplementaries("(ab)(c*)")); + checkReplaceFirst("(?<gn1>" + toSupplementaries("ab") + + ")(?<gn2>" + toSupplementaries("c") + "*)", + toSupplementaries("abccczzzabcczzzabccc"), + "$<gn1>", + toSupplementaries("abzzzabcczzzabccc")); + + + checkReplaceAll("(?<gn1>" + toSupplementaries("ab") + + ")(?<gn2>" + toSupplementaries("c") + "*)", + toSupplementaries("abccczzzabcczzzabccc"), + "$<gn1>", + toSupplementaries("abzzzabzzzab")); + + checkReplaceFirst("(?<gn1>" + toSupplementaries("ab") + + ")(?<gn2>" + toSupplementaries("c") + "*)", + toSupplementaries("abccczzzabcczzzabccc"), + "$<gn2>", + toSupplementaries("ccczzzabcczzzabccc")); + + + checkReplaceAll("(?<gn1>" + toSupplementaries("ab") + + ")(?<gn2>" + toSupplementaries("c") + "*)", + toSupplementaries("abccczzzabcczzzabccc"), + "$<gn2>", + toSupplementaries("ccczzzcczzzccc")); + + checkReplaceFirst("(?<dog>Dog)AndCat", + "zzzDogAndCatzzzDogAndCatzzz", + "$<dog>", + "zzzDogzzzDogAndCatzzz"); + + + checkReplaceAll("(?<dog>Dog)AndCat", + "zzzDogAndCatzzzDogAndCatzzz", + "$<dog>", + "zzzDogzzzDogzzz"); + + // backref in Matcher & String + if (!"abcdefghij".replaceFirst("cd(?<gn>ef)gh", "$<gn>").equals("abefij") || + !"abbbcbdbefgh".replaceAll("(?<gn>[a-e])b", "$<gn>").equals("abcdefgh")) + failCount++; + + // negative + checkExpectedFail("(?<groupnamehasnoascii.in>abc)(def)"); + checkExpectedFail("(?<groupnamehasnoascii_in>abc)(def)"); + checkExpectedFail("(?<gname>abc)(def)\\k<gnameX>"); + checkExpectedFail("(?<gname>abc)(?<gname>def)\\k<gnameX>"); + checkExpectedFail(Pattern.compile("(?<gname>abc)(def)").matcher("abcdef"), + "gnameX"); + checkExpectedFail(Pattern.compile("(?<gname>abc)(def)").matcher("abcdef"), + null); + report("NamedGroupCapture"); + } +} diff --git a/jdk/test/java/util/regex/SupplementaryTestCases.txt b/jdk/test/java/util/regex/SupplementaryTestCases.txt new file mode 100644 index 00000000000..2f05d4fed46 --- /dev/null +++ b/jdk/test/java/util/regex/SupplementaryTestCases.txt @@ -0,0 +1,1434 @@ +// +// Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +// CA 95054 USA or visit www.sun.com if you need additional information or +// have any questions. +// +// -------------------------------------------------------- +// This file contains test cases with supplementary characters for regular expressions. +// A test case consists of three lines: +// The first line is a pattern used in the test +// The second line is the input to search for the pattern in +// The third line is a concatentation of the match, the number of groups, +// and the contents of the first four subexpressions. +// Empty lines and lines beginning with comment slashes are ignored. + +// Test unsetting of backed off groups +^(\ud800\udc61)?\ud800\udc61 +\ud800\udc61 +true \ud800\udc61 1 + +^(\ud800\udc61\ud800)?\ud800\udc61\ud800 +\ud800\udc61\ud800 +true \ud800\udc61\ud800 1 + +^(\ud800\udc61\ud800\udc61(\ud800\udc62\ud800\udc62)?)+$ +\ud800\udc61\ud800\udc61\ud800\udc62\ud800\udc62\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\udc62\ud800\udc62\ud800\udc61\ud800\udc61 2 \ud800\udc61\ud800\udc61 \ud800\udc62\ud800\udc62 + +^(\ud800\udc61\ud800\udc61\ud800(\ud800\udc62\ud800\udc62\ud800)?)+$ +\ud800\udc61\ud800\udc61\ud800\ud800\udc62\ud800\udc62\ud800\ud800\udc61\ud800\udc61\ud800 +true \ud800\udc61\ud800\udc61\ud800\ud800\udc62\ud800\udc62\ud800\ud800\udc61\ud800\udc61\ud800 2 \ud800\udc61\ud800\udc61\ud800 \ud800\udc62\ud800\udc62\ud800 + +((\ud800\udc61|\ud800\udc62)?\ud800\udc62)+ +\ud800\udc62 +true \ud800\udc62 2 \ud800\udc62 + +((\ud800|\ud800\udc62)?\ud800\udc62)+ +\ud800\udc62 +true \ud800\udc62 2 \ud800\udc62 + +(\ud800\udc61\ud800\udc61\ud800\udc61)?\ud800\udc61\ud800\udc61\ud800\udc61 +\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\udc61 1 + +(\ud800\udc61\ud800\udc61\ud800\ud800\udc61)?\ud800\udc61\ud800\udc61\ud800\ud800\udc61 +\ud800\udc61\ud800\udc61\ud800\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\ud800\udc61 1 + +^(\ud800\udc61\ud800(\ud800\udc62\ud800)?)+$ +\ud800\udc61\ud800\ud800\udc62\ud800\ud800\udc61\ud800 +true \ud800\udc61\ud800\ud800\udc62\ud800\ud800\udc61\ud800 2 \ud800\udc61\ud800 \ud800\udc62\ud800 + +^(\ud800\udc61(\ud800\udc62)?)+$ +\ud800\udc61\ud800\udc62\ud800\udc61 +true \ud800\udc61\ud800\udc62\ud800\udc61 2 \ud800\udc61 \ud800\udc62 + +^(\ud800\udc61\ud800(\ud800\udc62\ud800)?)+$ +\ud800\udc61\ud800\ud800\udc62\ud800\ud800\udc61\ud800 +true \ud800\udc61\ud800\ud800\udc62\ud800\ud800\udc61\ud800 2 \ud800\udc61\ud800 \ud800\udc62\ud800 + +^(\ud800\udc61(\ud800\udc62(\ud800\udc63)?)?)?\ud800\udc61\ud800\udc62\ud800\udc63 +\ud800\udc61\ud800\udc62\ud800\udc63 +true \ud800\udc61\ud800\udc62\ud800\udc63 3 + +^(\ud800\udc61\ud800(\ud800\udc62(\ud800\udc63)?)?)?\ud800\udc61\ud800\ud800\udc62\ud800\udc63 +\ud800\udc61\ud800\ud800\udc62\ud800\udc63 +true \ud800\udc61\ud800\ud800\udc62\ud800\udc63 3 + +^(\ud800\udc61(\ud800\udc02(\ud800\udc63))).* +\ud800\udc61\ud800\udc02\ud800\udc63 +true \ud800\udc61\ud800\udc02\ud800\udc63 3 \ud800\udc61\ud800\udc02\ud800\udc63 \ud800\udc02\ud800\udc63 \ud800\udc63 + +^(\ud800\udc61(\ud800(\ud800\udc63))).* +\ud800\udc61\ud800\ud800\udc63 +true \ud800\udc61\ud800\ud800\udc63 3 \ud800\udc61\ud800\ud800\udc63 \ud800\ud800\udc63 \ud800\udc63 + +// Patterns including no surrogates +(.)([^a])xyz +\ud801\ud800\udc00xyz +true \ud801\ud800\udc00xyz 2 \ud801 \ud800\udc00 + +[^a-z].. +\ud801\ud800\udc00xyz +true \ud801\ud800\udc00x 0 + +.$ +\ud801\ud800\udc00 +true \ud800\udc00 0 + +.$ +\ud801\udc01\ud800\udc00 +true \ud800\udc00 0 + +.$ +\ud801\udc01\ud800\udc00\udcff +true \udcff 0 + +[^x-\uffff][^y-\uffff] +\ud800\udc00pqr +true \ud800\udc00p 0 + +[^x-\uffff]+ +\ud800\udc00pqrx +true \ud800\udc00pqr 0 + +/// The following test cases fail due to use of Start rather than +/// StartS. Disabled for now. +///[a-\uffff] +///\ud800\udc00x +///true x 0 +/// +///[a-\uffff] +///\ud800\udc00 +///false 0 + +// use of x modifier +\ud800\udc61bc(?x)bl\ud800\udc61h +\ud800\udc61bcbl\ud800\udc61h +true \ud800\udc61bcbl\ud800\udc61h 0 + +\ud800\udc61bc(?x) bl\ud800\udc61h +\ud800\udc61bcbl\ud800\udc61h +true \ud800\udc61bcbl\ud800\udc61h 0 + +\ud800\udc61bc(?x) bl\ud800\udc61h blech +\ud800\udc61bcbl\ud800\udc61hblech +true \ud800\udc61bcbl\ud800\udc61hblech 0 + +\ud800\udc61bc(?x) bl\ud800\udc61h # ignore comment +\ud800\udc61bcbl\ud800\udc61h +true \ud800\udc61bcbl\ud800\udc61h 0 + +// Simple alternation +\ud800\udc61|\ud800\udc62 +\ud800\udc61 +true \ud800\udc61 0 + +\ud800\udc61|\ud800\udc62|\ud800 +\ud800\udc61 +true \ud800\udc61 0 + +\ud800\udc61|\ud800 +\ud800\udc62 +false 0 + +\ud800\udc62|\ud800 +\ud800 +true \ud800 0 + +\ud800\udc61|\ud802\udc02 +z +false 0 + +\ud800\udc61|\ud802\udc02 +\ud802\udc02 +true \ud802\udc02 0 + +\ud800\udc61|\ud802\udc02|\ud803\udc03\ud804\udc04 +\ud803\udc03\ud804\udc04 +true \ud803\udc03\ud804\udc04 0 + +\ud800\udc61|\ud800\udc61d +\ud800\udc61d +true \ud800\udc61 0 + +z(\ud800\udc61|\ud800\udc61c)\ud802\udc02 +z\ud800\udc61c\ud802\udc02 +true z\ud800\udc61c\ud802\udc02 1 \ud800\udc61c + +z(\ud800\udc61|\ud800\udc61c|\udc61c)\ud802\udc02 +z\udc61c\ud802\udc02 +true z\udc61c\ud802\udc02 1 \udc61c + +// Simple codepoint class +[\ud800\udc61\ud802\udc02c]+ +\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 0 + +[\ud800\udc61\ud802\udc02c]+ +\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 0 + +[\ud800\udc61\ud802\udc02c\ud800]+ +\ud800\udc61\ud802\udc02\ud800\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud802\udc02\ud800\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 0 + +[\ud800\udc61bc]+ +d\ud800\udc62fg +false 0 + +[\ud800\udc61bc]+[\ud804\udc04ef]+[\ud807\udc07hi]+ +zzz\ud800\udc61\ud800\udc61\ud804\udc04\ud804\udc04\ud807\udc07\ud807\udc07zzz +true \ud800\udc61\ud800\udc61\ud804\udc04\ud804\udc04\ud807\udc07\ud807\udc07 0 + +// Range codepoint class +[\ud801\udc01-\ud807\udc07]+ +\ud8ff\udcff\ud8ff\udcff\ud8ff\udcff\ud807\udc07\ud807\udc07\ud807\udc07 +true \ud807\udc07\ud807\udc07\ud807\udc07 0 + +[\ud801\udc01-\ud807\udc07]+ +mmm +false 0 + +[\ud800\udc61-]+ +z\ud800\udc61-9z +true \ud800\udc61- 0 + +// Negated char class +[^\ud800\udc61\ud802\udc02c]+ +\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 +false 0 + +[^\ud800\udc61\ud802\udc02\ud803\udc03]+ +\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02\ud802\udc02\ud802\udc02\ud803\udc03\ud803\udc03\ud803\udc03\ud804\udc04efg +true \ud804\udc04efg 0 + +[^\ud800\udc61\ud802\udc02\ud803\udc03\ud800]+ +\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02\ud802\udc02\ud802\udc02\ud803\udc03\ud803\udc03\ud803\udc03\ud804\udc04efg +true \ud804\udc04efg 0 + +// Making sure a ^ not in first position matches literal ^ +[\ud801\udc01\ud802\udc02\ud803\udc03^\ud802\udc02] +\ud802\udc02 +true \ud802\udc02 0 + +[\ud801\udc01\ud802\udc02\ud803\udc03^\ud802\udc02] +^ +true ^ 0 + +// Class union and intersection +[\ud801\udc01\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]] +\ud802\udc02 +true \ud802\udc02 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]] +\ud805\udc05 +true \ud805\udc05 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud801\udc01 +true \ud801\udc01 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud80c\udc0c +true \ud80c\udc0c 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +4 +true 4 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud805\udc05 +false 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud816\udc16 +false 0 + +[[\ud801\udc01-\ud804\udc04][0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud802\udc02 +true \ud802\udc02 0 + +[[\ud801\udc01-\ud804\udc04][0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud81a\udc1a +false 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]] +\ud801\udc01 +true \ud801\udc01 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]] +\ud805\udc05 +true \ud805\udc05 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]] +\ud808\udc08 +true \ud808\udc08 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]] +\ud80d\udc0d +false 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]\ud80d\udc0d] +\ud80d\udc0d +true \ud80d\udc0d 0 + +[\ud801\udc01\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]\ud807\udc07\ud808\udc08\ud809\udc09] +\ud801\udc01 +true \ud801\udc01 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]\ud807\udc07\ud808\udc08\ud809\udc09] +\ud804\udc04 +true \ud804\udc04 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]\ud807\udc07\ud808\udc08\ud809\udc09] +\ud808\udc08 +true \ud808\udc08 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]\ud807\udc07\ud808\udc08\ud809\udc09] +\ud816\udc16 +false 0 + +[\ud801\udc01-\ud803\udc03&&[\ud804\udc04-\ud806\udc06]] +\ud801\udc01 +false 0 + +[\ud801\udc01-\ud803\udc03&&[\ud804\udc04-\ud806\udc06]] +\ud805\udc05 +false 0 + +[\ud801\udc01-\ud803\udc03&&[\ud804\udc04-\ud806\udc06]] +\ud81a\udc1a +false 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud804\udc04-\ud806\udc06]] +\ud801\udc01 +false 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud804\udc04-\ud806\udc06]] +\ud805\udc05 +false 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud804\udc04-\ud806\udc06]] +\ud81a\udc1a +false 0 + +[\ud801\udc01-\ud803\udc03&&\ud804\udc04-\ud806\udc06] +\ud801\udc01 +false 0 + +[\ud801\udc01-\ud80d\udc0d&&\ud80d\udc0d-\ud81a\udc1a] +\ud80d\udc0d +true \ud80d\udc0d 0 + +[\ud801\udc01-\ud80d\udc0d&&\ud80d\udc0d-\ud81a\udc1a&&\ud801\udc01-\ud803\udc03] +\ud80d\udc0d +false 0 + +[\ud801\udc01-\ud80d\udc0d&&\ud80d\udc0d-\ud81a\udc1a&&\ud801\udc01-\ud81a\udc1a] +\ud80d\udc0d +true \ud80d\udc0d 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[\ud80d\udc0d-\ud81a\udc1a]] +\ud801\udc01 +false 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[\ud80d\udc0d-\ud81a\udc1a]] +\ud80d\udc0d +true \ud80d\udc0d 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[\ud80d\udc0d-\ud81a\udc1a]] +\ud81a\udc1a +false 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[^\ud801\udc01-\ud803\udc03]] +\ud801\udc01 +false 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[^\ud801\udc01-\ud803\udc03]] +\ud804\udc04 +true \ud804\udc04 0 + +[\ud801\udc01-\ud80d\udc0d&&[^\ud801\udc01-\ud803\udc03]] +\ud801\udc01 +false 0 + +[\ud801\udc01-\ud80d\udc0d&&[^\ud801\udc01-\ud803\udc03]] +\ud804\udc04 +true \ud804\udc04 0 + +[\ud801\udc01-\ud803\udc03\ud804\udc04-\ud806\udc06&&[\ud804\udc04-\ud806\udc06]] +\ud801\udc01 +false 0 + +[\ud801\udc01-\ud803\udc03\ud804\udc04-\ud806\udc06&&[\ud804\udc04-\ud806\udc06]] +\ud805\udc05 +true \ud805\udc05 0 + +[[\ud801\udc01-\ud803\udc03]&&\ud804\udc04-\ud806\udc06\ud801\udc01-\ud803\udc03] +\ud801\udc01 +true \ud801\udc01 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud804\udc04-\ud806\udc06][\ud801\udc01-\ud803\udc03]] +\ud801\udc01 +true \ud801\udc01 0 + +[[\ud801\udc01-\ud803\udc03][\ud804\udc04-\ud806\udc06]&&\ud801\udc01\ud802\udc02\ud803\udc03] +\ud801\udc01 +true \ud801\udc01 0 + +[[\ud801\udc01-\ud803\udc03][\ud804\udc04-\ud806\udc06]&&\ud801\udc01\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]] +\ud805\udc05 +true \ud805\udc05 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud802\udc02-\ud804\udc04]&&[\ud803\udc03-\ud805\udc05]] +\ud801\udc01 +false 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud802\udc02-\ud804\udc04]&&[\ud803\udc03-\ud805\udc05]] +\ud803\udc03 +true \ud803\udc03 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud802\udc02-\ud804\udc04][\ud803\udc03-\ud805\udc05]&&[\ud815\udc15-\ud81a\udc1a]] +\ud803\udc03 +false 0 + +[\ud801\udc01\ud802\udc02\ud803\udc03[^\ud802\udc02\ud803\udc03\ud804\udc04]] +\ud801\udc01 +true \ud801\udc01 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[^\ud802\udc02\ud803\udc03\ud804\udc04]] +\ud804\udc04 +false 0 + +[\ud801\udc01-\ud803\udc03&&\ud801\udc01-\ud804\udc04&&\ud801\udc01-\ud805\udc05\ud807\udc07\ud808\udc08\ud809\udc09] +\ud802\udc02 +true \ud802\udc02 0 + +[\ud801\udc01-\ud803\udc03&&\ud801\udc01-\ud804\udc04&&\ud801\udc01-\ud805\udc05\ud807\udc07\ud808\udc08\ud809\udc09] +\ud807\udc07 +false 0 + +[[\ud801\udc01[\ud802\udc02]]&&[\ud802\udc02[\ud801\udc01]]] +\ud801\udc01 +true \ud801\udc01 0 + +// Unicode isn't supported in clazz() +[[\ud800\udc61]&&[b][c][\ud800\udc61]&&[^d]] +\ud800\udc61 +true \ud800\udc61 0 + +[[\ud800\udc61]&&[\ud802\udc02][\ud800][\ud800\udc61]&&[^\ud804\udc04]] +\ud800\udc61 +true \ud800\udc61 0 + +[[\ud800\udc61]&&[b][\ud800][\ud800\udc61]&&[^\ud804\udc04]] +\ud804\udc04 +false 0 + +[[\ud800\udc61]&&[b][c][\ud800\udc61]&&[^d]] +d +false 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]] +\ud800\udc01 +false 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]] +\ud800\udc03 +true \ud800\udc03 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]&&[\ud800\udc03]] +\ud800\udc03 +true \ud800\udc03 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]&&[\ud800\udc03]&&\ud800\udc03] +\ud800\udc03 +true \ud800\udc03 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]&&[\ud800\udc03]&&\ud800\udc03&&\ud800\udc03] +\ud800\udc03 +true \ud800\udc03 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]&&[\ud800\udc03]&&\ud800\udc03&&[\ud800\udc03\ud800\udc04\ud800\udc05]] +\ud800\udc03 +true \ud800\udc03 0 + +[z[\ud800\udc61b\ud800\udc03&&b\ud800\udc03\ud800\udc04]] +\ud800\udc03 +true \ud800\udc03 0 + +[z[\ud800\udc61b\ud800\udc03&&b\ud800\udc03\ud800\udc04]&&[u-z]] +z +true z 0 + +[x[\ud800\udc61b\ud800\udc03&&b\ud800\udc03\ud800\udc04[z]]&&[u-z]] +z +false 0 + +[x[[wz]\ud800\udc61b\ud800\udc03&&b\ud800\udc03\ud800\udc04[z]]&&[u-z]] +z +true z 0 + +[[\ud800\udc61b\ud800\udc03]&&[\ud800\udc04\ud800\udc05f]\ud800\udc61b\ud800\udc03] +\ud800\udc61 +true \ud800\udc61 0 + +[[\ud800\udc61b\ud800\udc03]&&[\ud800\udc04\ud800\udc05f]xyz[\ud800\udc61b\ud800\udc03]] +\ud800\udc61 +true \ud800\udc61 0 + +\pL +\ud800\udc00 +true \ud800\udc00 0 + +\p{IsASCII} +\ud800\udc00 +false 0 + +\pLbc +\ud800\udc00bc +true \ud800\udc00bc 0 + +\ud800\udc61[r\p{InGreek}]c +\ud800\udc61\u0370c +true \ud800\udc61\u0370c 0 + +\ud800\udc61\p{InGreek} +\ud800\udc61\u0370 +true \ud800\udc61\u0370 0 + +\ud800\udc61\P{InGreek} +\ud800\udc61\u0370 +false 0 + +\ud800\udc61\P{InGreek} +\ud800\udc61b +true \ud800\udc61b 0 + +\ud800\udc61{^InGreek} +- +error + +\ud800\udc61\p{^InGreek} +- +error + +\ud800\udc61\P{^InGreek} +- +error + +\ud800\udc61\p{InGreek} +\ud800\udc61\u0370 +true \ud800\udc61\u0370 0 + +\ud800\udc61[\p{InGreek}]c +\ud800\udc61\u0370c +true \ud800\udc61\u0370c 0 + +\ud800\udc61[\P{InGreek}]c +\ud800\udc61\u0370c +false 0 + +\ud800\udc61[\P{InGreek}]c +\ud800\udc61bc +true \ud800\udc61bc 0 + +\ud800\udc61[{^InGreek}]c +\ud800\udc61nc +true \ud800\udc61nc 0 + +\ud800\udc61[{^InGreek}]c +\ud800\udc61zc +false 0 + +\ud800\udc61[\p{^InGreek}]c +- +error + +\ud800\udc61[\P{^InGreek}]c +- +error + +\ud800\udc61[\p{InGreek}] +\ud800\udc61\u0370 +true \ud800\udc61\u0370 0 + +\ud800\udc61[r\p{InGreek}]c +\ud800\udc61rc +true \ud800\udc61rc 0 + +\ud800\udc61[\p{InGreek}r]c +\ud800\udc61rc +true \ud800\udc61rc 0 + +\ud800\udc61[r\p{InGreek}]c +\ud800\udc61rc +true \ud800\udc61rc 0 + +\ud800\udc61[^\p{InGreek}]c +\ud800\udc61\u0370c +false 0 + +\ud800\udc61[^\P{InGreek}]c +\ud800\udc61\u0370c +true \ud800\udc61\u0370c 0 + +\ud800\udc61[\p{InGreek}&&[^\u0370]]c +\ud800\udc61\u0370c +false 0 + +// Test the dot metacharacter +\ud800\udc61.c.+ +\ud800\udc61#c%& +true \ud800\udc61#c%& 0 + +\ud800\udc61b. +\ud800\udc61b\n +false 0 + +(?s)\ud800\udc61b. +\ud800\udc61b\n +true \ud800\udc61b\n 0 + +\ud800\udc61[\p{L}&&[\P{InGreek}]]c +\ud800\udc61\u6000c +true \ud800\udc61\u6000c 0 + +\ud800\udc61[\p{L}&&[\P{InGreek}]]c +\ud800\udc61rc +true \ud800\udc61rc 0 + +\ud800\udc61[\p{L}&&[\P{InGreek}]]c +\ud800\udc61\u0370c +false 0 + +\ud800\udc61\p{InGreek}c +\ud800\udc61\u0370c +true \ud800\udc61\u0370c 0 + +\ud800\udc61\p{Sc} +\ud800\udc61$ +true \ud800\udc61$ 0 + +// Test \p{L} +\p{L} +\ud800\udf1e +true \ud800\udf1e 0 + +^a\p{L}z$ +a\ud800\udf1ez +true a\ud800\udf1ez 0 + +// Test \P{InDeseret} + +\ud800\udf00\p{L}{2,3}\P{L}*supp->\ud900\udc00<-\P{InDeseret} +\ud800\udf00\ud800\udf1e\ud800\udf1esupp->\ud900\udc00<-\ud901\udf00 +true \ud800\udf00\ud800\udf1e\ud800\udf1esupp->\ud900\udc00<-\ud901\udf00 0 + +\ud800\udf00\p{L}{2,3}\P{L}*supp->\ud900\udc00<-\P{InDeseret} +\ud800\udf00\ud800\udf1e\ud800\udf1e\ud901\udf00supp->\ud900\udc00<-\ud901\udf00 +true \ud800\udf00\ud800\udf1e\ud800\udf1e\ud901\udf00supp->\ud900\udc00<-\ud901\udf00 0 + +// Test \p{InDeseret} +\ud800\udf00\p{L}{2,3}\P{L}*supp->\ud900\udc00<-\p{InDeseret} +\ud800\udf00\ud800\udf1e\ud800\udf1e\ud901\udf00supp->\ud900\udc00<-\ud801\udc00 +true \ud800\udf00\ud800\udf1e\ud800\udf1e\ud901\udf00supp->\ud900\udc00<-\ud801\udc00 0 + +// Test the word char escape sequence +\ud800\udc61b\wc +\ud800\udc61bcc +true \ud800\udc61bcc 0 + +\ud800\udc61bc[\w] +\ud800\udc61bcd +true \ud800\udc61bcd 0 + +\ud800\udc61bc[\sdef]* +\ud800\udc61bc def +true \ud800\udc61bc def 0 + +\ud800\udc61bc[\sy-z]* +\ud800\udc61bc y z +true \ud800\udc61bc y z 0 + +\ud800\udc01bc[\ud800\udc01-\ud800\udc04\sm-p]* +\ud800\udc01bc\ud800\udc01\ud800\udc01 mn p +true \ud800\udc01bc\ud800\udc01\ud800\udc01 mn p 0 + +// Test the whitespace escape sequence +\ud800\udc61b\s\ud800\udc03 +\ud800\udc61b \ud800\udc03 +true \ud800\udc61b \ud800\udc03 0 + +\s\s\s +bl\ud800\udc61h err +false 0 + +\S\S\s +bl\ud800\udc61h err +true \ud800\udc61h 0 + +// Test the digit escape sequence +\ud800\udc61b\d\ud800\udc03 +\ud800\udc61b9\ud800\udc03 +true \ud800\udc61b9\ud800\udc03 0 + +\d\d\d +bl\ud800\udc61h45 +false 0 + +// Test the caret metacharacter +^\ud800\udc61bc +\ud800\udc61bcdef +true \ud800\udc61bc 0 + +^\ud800\udc61bc +bcd\ud800\udc61bc +false 0 + +// Greedy ? metacharacter +\ud800\udc61?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +\udc61?\ud800\udc02 +\ud800\udc61\udc61\udc61\ud800\udc02 +true \udc61\ud800\udc02 0 + +\ud800\udc61?\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800?\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800\udc61?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc03\ud800\udc03\ud800\udc03 +false 0 + +.?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +// Reluctant ? metacharacter +\ud800\udc61??\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +\ud800??\ud800\udc02 +\ud800\ud800\ud8001\ud800\ud800\udc02 +true \ud800\ud800\udc02 0 + +\ud800\udc61??\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800??\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800\udc61??\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.??\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +// Possessive ? metacharacter +\ud800\udc61?+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +\ud800\udc61?+\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800\udc61?+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.?+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +// Greedy + metacharacter +\ud800\udc61+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +\udc61+\ud800\udc02 +\ud800\udc61\udc61\udc61\udc61\ud800\udc02 +true \udc61\udc61\udc61\ud800\udc02 0 + +\ud800\udc61+\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800+\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800\udc61+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +.+\ud800\udc02 +\ud800\udc61\udc61\udc61\udc61\ud800\udc02 +true \ud800\udc61\udc61\udc61\udc61\ud800\udc02 0 + +// Reluctant + metacharacter +\ud800\udc61+?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +\udc61+?\ud800\udc02 +\udc61\udc61\udc61\udc61\ud800\udc02 +true \udc61\udc61\udc61\udc61\ud800\udc02 0 + +\ud800\udc61+?\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800+?\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800\udc61+?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.+?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +// Possessive + metacharacter +\ud800\udc61++\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +\ud800\udc61++\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800\udc61++\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.++\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +false 0 + +// Greedy Repetition +\ud800\udc61{2,3} +\ud800\udc61 +false 0 + +\ud800\udc61{2,3} +\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61 0 + +\ud800\udc61{2,3} +\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\udc61 0 + +\ud800\udc61{2,3} +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\udc61 0 + +\ud800\udc61{3,} +zzz\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61zzz +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61 0 + +\ud800\udc61{3,} +zzz\ud800\udc61\ud800\udc61zzz +false 0 + +// Reluctant Repetition +\ud800\udc61{2,3}? +\ud800\udc61 +false 0 + +\ud800\udc61{2,3}? +\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61 0 + +\ud800\udc61{2,3}? +\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61 0 + +\ud800\udc61{2,3}? +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61 0 + +// Zero width Positive lookahead +\ud800\udc61\ud802\udc02\ud803\udc03(?=\ud804\udc04) +zzz\ud800\udc61\ud802\udc02\ud803\udc03\ud804\udc04 +true \ud800\udc61\ud802\udc02\ud803\udc03 0 + +\ud800\udc61\ud802\udc02\ud803\udc03(?=\ud804\udc04) +zzz\ud800\udc61\ud802\udc02\ud803\udc03e\ud804\udc04 +false 0 + +\ud800\udc61\ud802\udc02\ud803\udc03(?=\udcff\ud804\udc04) +zzz\ud800\udc61\ud802\udc02\ud803\udc03\udcff\ud804\udc04 +true \ud800\udc61\ud802\udc02\ud803\udc03 0 + +\ud800\udc61\ud802\udc02\ud803\udc03(?=\udcff\ud804\udc04) +zzz\ud800\udc61\ud802\udc02\ud803\udc03\ud8ff\udcff\ud804\udc04 +false 0 + +// Zero width Negative lookahead +\ud800\udc61\ud802\udc02\ud803\udc03(?!\ud804\udc04) +zz\ud800\udc61\ud802\udc02\ud803\udc03\ud804\udc04 +false 0 + +a\ud802\udc02\ud803\udc03(?!\ud804\udc04) +zza\ud802\udc02\ud803\udc03\udc04\ud804\udc04 +true a\ud802\udc02\ud803\udc03 0 + +\ud800\udc61\ud802\udc02\ud803\udc03(?!\ud804\udc04\ud8ff) +zz\ud800\udc61\ud802\udc02\ud803\udc03\ud804\udc04\ud8ffX +false 0 + +a\ud802\udc02\ud803\udc03(?!\ud804\udc04\ud8ff) +zza\ud802\udc02\ud803\udc03e\ud804\udc04\ud8ff\udcff +true a\ud802\udc02\ud803\udc03 0 + +// Zero width Positive lookbehind +(?<=\ud801\udc01\ud802\udc02)\ud803\udc03 +\ud801\udc01\ud802\udc02\ud803\udc03 +true \ud803\udc03 0 + +// Zero width Negative lookbehind +(?<!\ud801\udc01)\ud802\udc02\ud803\udc03 +###\ud800\udc00\ud802\udc02\ud803\udc03 +true \ud802\udc02\ud803\udc03 0 + +(?<![\ud801\udc01\ud802\udc02])\ud803\udc03. +\ud801\udc01\ud803\udc03x\ud800\udc00\ud803\udc03y +true \ud803\udc03y 0 + +(?<!\ud801\udc01)\ud803\udc03 +\ud801\udc01\ud803\udc03 +false 0 + +// Nondeterministic group +(\ud800\udc61+\ud802)+ +\ud800\udc61\ud802\ud800\udc61\ud802\ud800\udc61\ud802 +true \ud800\udc61\ud802\ud800\udc61\ud802\ud800\udc61\ud802 1 \ud800\udc61\ud802 + +(\ud800\udc61|\ud802)+ +\ud800\ud802\udc61\ud803\ud802\udc61 +false 1 + +// Deterministic group +(\ud800\udc61\ud802)+ +\ud800\udc61\ud802\ud800\udc61\ud802\ud800\udc61\ud802 +true \ud800\udc61\ud802\ud800\udc61\ud802\ud800\udc61\ud802 1 \ud800\udc61\ud802 + +(\ud800\udc61\ud802)+ +\ud800\udc61ccccd +false 1 + +(\ud800\udc61\ud802)* +\ud800\udc61\ud802\ud800\udc61\ud802\ud800\udc61\ud802 +true \ud800\udc61\ud802\ud800\udc61\ud802\ud800\udc61\ud802 1 \ud800\udc61\ud802 + +(\ud800\udc61b)(cd*) +zzz\ud800\udc61bczzz +true \ud800\udc61bc 2 \ud800\udc61b c + +\ud800\udc61bc(\ud804\udc04)*\ud800\udc61bc +\ud800\udc61bc\ud804\udc04\ud804\udc04\ud804\udc04\ud804\udc04\ud804\udc04\ud800\udc61bc +true \ud800\udc61bc\ud804\udc04\ud804\udc04\ud804\udc04\ud804\udc04\ud804\udc04\ud800\udc61bc 1 \ud804\udc04 + +// Back references +(\ud800\udc61*)\ud802\udc02c\1 +zzz\ud800\udc61\ud800\udc61\ud802\udc02c\ud800\udc61\ud800\udc61zzz +true \ud800\udc61\ud800\udc61\ud802\udc02c\ud800\udc61\ud800\udc61 1 \ud800\udc61\ud800\udc61 + +(\ud800\udc61*)\ud802\udc02c\1 +zzz\ud800\udc61\ud800\udc61\ud802\udc02c\ud800\udc61zzz +true \ud800\udc61\ud802\udc02c\ud800\udc61 1 \ud800\udc61 + +(\ud800\udc07\ud800\udc14*)(\ud804\udc04\ud804\udc04e)*(yu)\1\3(vv) +zzz\ud800\udc07\ud800\udc14\ud800\udc14\ud804\udc04\ud804\udc04e\ud804\udc04\ud804\udc04eyu\ud800\udc07\ud800\udc14\ud800\udc14yuvvzzz +true \ud800\udc07\ud800\udc14\ud800\udc14\ud804\udc04\ud804\udc04e\ud804\udc04\ud804\udc04eyu\ud800\udc07\ud800\udc14\ud800\udc14yuvv 4 \ud800\udc07\ud800\udc14\ud800\udc14 \ud804\udc04\ud804\udc04e yu vv + +// Greedy * metacharacter +\ud800\udc61*\ud802\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 0 + +\ud800\udc61*\ud802\udc02 +\ud802\udc02 +true \ud802\udc02 0 + +\ud800\udc61*\ud802\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.*\ud802\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 0 + +// Reluctant * metacharacter +\ud800\udc61*?\ud802\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 0 + +\ud800\udc61*?\ud802\udc02 +\ud802\udc02 +true \ud802\udc02 0 + +\ud800\udc61*?\ud802\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.*?\ud802\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 0 + +// Possessive * metacharacter +\ud800\udc61*+\ud802\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 0 + +\ud800\udc61*+\ud802\udc02 +\ud802\udc02 +true \ud802\udc02 0 + +\ud800\udc61*+\ud802\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.*+\ud802\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02 +false 0 + +// Case insensitivity +(?iu)\ud801\udc00\ud801\udc01\ud801\udc02x +\ud801\udc28\ud801\udc29\ud801\udc2aX +true \ud801\udc28\ud801\udc29\ud801\udc2aX 0 + +\ud801\udc00(?iu)\ud801\udc01\ud801\udc02 +\ud801\udc00\ud801\udc29\ud801\udc2a +true \ud801\udc00\ud801\udc29\ud801\udc2a 0 + +\ud801\udc00(?iu)\ud801\udc01\ud801\udc02 +\ud801\udc28\ud801\udc29\ud801\udc2a +false 0 + +(?iu)\ud801\udc00[\ud801\udc01\ud801\udc02]+ +\ud801\udc28\ud801\udc29\ud801\udc2a +true \ud801\udc28\ud801\udc29\ud801\udc2a 0 + +(?iu)[\ud801\udc00-\ud801\udc02]+ +\ud801\udc28\ud801\udc29\ud801\udc2a +true \ud801\udc28\ud801\udc29\ud801\udc2a 0 + +// Disable metacharacters- test both length <=3 and >3 +// So that the BM optimization is part of test +\Q***\E\ud801\udc01\ud802\udc02\ud800\udc03 +***\ud801\udc01\ud802\udc02\ud800\udc03 +true ***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\ud802\udc02l\Q***\E\ud801\udc01\ud802\udc02\ud800\udc03 +\ud802\udc02l***\ud801\udc01\ud802\udc02\ud800\udc03 +true \ud802\udc02l***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\Q***\ud801\udc01\ud802\udc02\ud800\udc03 +***\ud801\udc01\ud802\udc02\ud800\udc03 +true ***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\ud802\udc02l\ud801\udc01h\Q***\E\ud801\udc01\ud802\udc02\ud800\udc03 +\ud802\udc02l\ud801\udc01h***\ud801\udc01\ud802\udc02\ud800\udc03 +true \ud802\udc02l\ud801\udc01h***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\Q***\ud801\udc01\ud802\udc02\ud800\udc03 +***\ud801\udc01\ud802\udc02\ud800\udc03 +true ***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\Q*\ud801\udc01\ud802\udc02 +*\ud801\udc01\ud802\udc02 +true *\ud801\udc01\ud802\udc02 0 + +\ud802\udc02l\ud801\udc01h\Q***\ud801\udc01\ud802\udc02\ud800\udc03 +\ud802\udc02l\ud801\udc01h***\ud801\udc01\ud802\udc02\ud800\udc03 +true \ud802\udc02l\ud801\udc01h***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\ud802\udc02l\ud801\udc01\Q***\ud801\udc01\ud802\udc02\ud800\udc03 +\ud802\udc02l\ud801\udc01***\ud801\udc01\ud802\udc02\ud800\udc03 +true \ud802\udc02l\ud801\udc01***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +//Test cases below copied from i18n QE's RegexSupplementaryTests.txt +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +true \uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 0 + +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +\u1000\uD801\uDFF1\uDB00\uDC00 +false 0 + +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +\uD800\uDFFF\uFFFF\uDB00\uDC00 +false 0 + +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +\uD800\uDFFF\uD801\uDFF1\uFFFF +false 0 + +\u1000.\uFFFF +\u1000\uD800\uDFFF\uFFFF +true \u1000\uD800\uDFFF\uFFFF 0 + +//======= +// Ranges +//======= +[a-\uD800\uDFFF] +\uDFFF +true \uDFFF 0 + +[a-\uD800\uDFFF] +\uD800 +true \uD800 0 + +[a-\uD800\uDFFF] +\uD800\uDFFF +true \uD800\uDFFF 0 + +[\uD800\uDC00-\uDBFF\uDFFF] +\uDBFF +false 0 + +[\uD800\uDC00-\uDBFF\uDFFF] +\uDC00 +false 0 + +[\uD800-\uDFFF] +\uD800\uDFFF +false 0 + +[\uD800-\uDFFF] +\uDFFF\uD800 +true \uDFFF 0 + +foo[^\uD800-\uDFFF] +foo\uD800\uDFFF +true foo\uD800\uDFFF 0 + +foo[^\uD800-\uDFFF] +foo\uDFFF\uD800 +false 0 + +//fo\uD800[\uDC00-\uDFFF] + +//================== +// Character Classes +//================== +// Simple class +[ab\uD800\uDFFFcd]at +\uD800at +false 0 + +[ab\uD800\uDFFFcd]at +\uD800\uDFFFat +true \uD800\uDFFFat 0 + +// Negation +[^\uD800\uDFFFcd]at +\uD800at +true \uD800at 0 + +[^\uD800\uDFFFcd]at +\uDFFFat +true \uDFFFat 0 + +// Inclusive range +[\u0000-\uD800\uDFFF-\uFFFF] +\uD800\uDFFF +true \uD800\uDFFF 0 + +// Unions +[\u0000-\uD800[\uDFFF-\uFFFF]] +\uD800\uDFFF +false 0 + + +// Intersection +[\u0000-\uFFFF&&[\uD800\uDFFF]] +\uD800\uDFFF +false 0 + +[\u0000-\uFFFF&&[\uD800\uDFFF]] +\uD800 +false 0 + +[\u0000-\uFFFF&&[\uDFFF\uD800]] +\uD800 +true \uD800 0 + +[\u0000-\uFFFF&&[\uDFFF\uD800\uDC00]] +\uDC00 +false 0 + +[\u0000-\uDFFF&&[\uD800-\uFFFF]] +\uD800\uDFFF +false 0 + +[\u0000-\uDFFF&&[\uD800-\uFFFF]] +\uDFFF\uD800 +true \uDFFF 0 + +// Subtraction +[\u0000-\uD800\uDFFF&&[^\uD800\uDC00]] +\uD800 +true \uD800 0 + +[\u0000-\uD800\uDFFF&&[^\uD800\uDC00]] +\uDC00 +true \uDC00 0 + +[\u0000-\uD800\uDFFF&&[^\uD800\uDC00]] +\uD800\uDFFF +true \uD800\uDFFF 0 + +[\u0000-\uD800\uDFFF&&[^\uD800\uDBFF\uDC00]] +\uD800 +false 0 + +[\u0000-\uD800\uDFFF&&[^\uDC00\uD800\uDBFF]] +\uD800\uDC00 +true \uD800\uDC00 0 + +// Quantifiers +a\uD800\uDFFF? +a\uD800 +true a 0 + +a\uD800\uDFFF? +a\uDFFF +true a 0 + +a\uD800\uDFFF? +a\uD800\uDFFF +true a\uD800\uDFFF 0 + +a\uDFFF\uD800? +a\uDFFF +true a\uDFFF 0 + +a\uDFFF\uD800? +a\uD800 +false 0 + +\uD800\uDFFF\uDC00? +\uD800 +false 0 + +\uD800\uDFFF\uDC00? +\uD800\uDFFF +true \uD800\uDFFF 0 + +a\uD800\uDFFF?? +a\uDFFF +true a 0 + +a\uD800\uDFFF* +a +true a 0 + +a\uD800\uDFFF* +a\uD800 +true a 0 + +\uD800\uDFFF* +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uD800\uDFFF* +\uD800\uDFFF\uDFFF\uDFFF\uDFFF +true \uD800\uDFFF 0 + +\uD800*\uDFFF +\uD800\uDFFF +false 0 + +a\uD800\uDFFF* +a\uD800 +true a 0 + +\uDFFF\uD800* +\uDFFF +true \uDFFF 0 + +\uDFFF\uD800* +\uDFFF\uD800\uD800\uD800 +true \uDFFF\uD800\uD800\uD800 0 + +\uD800\uDFFF+ +\uD800\uDFFF\uDFFF\uDFFF +true \uD800\uDFFF 0 + +\uD800\uDFFF+ +\uD800 +false 0 + +\uD800\uDFFF+ +\uD800\uDFFF +true \uD800\uDFFF 0 + +\uD800\uDFFF+ +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uDFFF\uD800+ +\uDFFF\uD800\uDFFF\uD800 +false 0 + +\uD800+\uDFFF +\uD800\uDFFF +false 0 + +\uD800+\uDFFF +\uD800 +false 0 + +\uDFFF+\uD800 +\uD800 +false 0 + +\uDFFF+\uD800 +\uDFFF\uD800 +true \uDFFF\uD800 0 + +\uD800\uDFFF{3} +\uD800\uDFFF\uDFFF\uDFFF +false 0 + +\uD800\uDFFF{3} +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uDFFF\uD800{3} +\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800 +false 0 + +\uDFFF\uD800{3} +\uDFFF\uD800\uD800\uD800 +true \uDFFF\uD800\uD800\uD800 0 + +\uD800\uDFFF{2,} +\uD800\uDFFF +false 0 + +\uD800\uDFFF{2,} +\uD800\uDFFF\uDFFF +false 0 + +\uD800\uDFFF{2,} +\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF 0 + +\uDFFF\uD800{2,} +\uDFFF\uD800\uDFFF\uD800 +false 0 + +\uDFFF\uD800{2,} +\uDFFF\uD800\uD800\uD800 +true \uDFFF\uD800\uD800\uD800 0 + +\uD800\uDFFF{3,4} +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uD800\uDFFF{3,4} +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800 +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uD800\uDFFF{3,4} +\uD800\uDFFF\uD800\uD800\uDFFF\uD800\uDFFF +false 0 + +\uDFFF\uD800{3,5} +\uDFFF\uD800\uD800\uD800\uD800\uD800\uD800\uD800 +true \uDFFF\uD800\uD800\uD800\uD800\uD800 0 + +\uD800\uDFFF{3,5} +\uD800\uDFFF\uDFFF\uDFFF +false 0 + +\uD800\uDFFF{3,5} +\uD800\uDFFF\uD800\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +// Groupings +(\uD800(\uDFFF)) +\uD800\uDFFF +false 2 + +(\uD800(\uDC00)(\uDFFF)) +\uD800\uDC00\uDFFF +false 3 + +((\uD800)(\uDFFF)) +\uD800\uDFFF +false 3 + +(\uD800(\uDFFF)\uDFFF) +\uD800\uDFFF +false 2 + +(\uDFFF(\uD800)(\uDBFF)) +\uDFFF\uD800\uDBFF +true \uDFFF\uD800\uDBFF 3 \uDFFF\uD800\uDBFF \uD800 \uDBFF + +(\uDFFF(\uD800)(\uDC00)) +\uDFFF\uD800\uDC00 +false 3 + +(\uDFFF\uD800(\uDC00\uDBFF)) +\uDFFF\uD800\uDC00\uDBFF +false 2 + +(\uD800\uDFFF(\uDBFF)(\uDC00)) +\uD800\uDFFF\uDBFF\uDC00 +false 3 + +(\uD800\uDFFF(\uDBFF\uDC00)) +\uD800\uDFFF\uDBFF\uDC00 +true \uD800\uDFFF\uDBFF\uDC00 2 \uD800\uDFFF\uDBFF\uDC00 \uDBFF\uDC00 diff --git a/jdk/test/java/util/regex/TestCases.txt b/jdk/test/java/util/regex/TestCases.txt new file mode 100644 index 00000000000..fd41df33f76 --- /dev/null +++ b/jdk/test/java/util/regex/TestCases.txt @@ -0,0 +1,1092 @@ +// +// Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +// CA 95054 USA or visit www.sun.com if you need additional information or +// have any questions. +// +// +// This file contains test cases for regular expressions. +// A test case consists of three lines: +// The first line is a pattern used in the test +// The second line is the input to search for the pattern in +// The third line is a concatentation of the match, the number of groups, +// and the contents of the first four subexpressions. +// Empty lines and lines beginning with comment slashes are ignored. +// +// Test unsetting of backed off groups +^(a)?a +a +true a 1 + +^(aa(bb)?)+$ +aabbaa +true aabbaa 2 aa bb + +((a|b)?b)+ +b +true b 2 b + +(aaa)?aaa +aaa +true aaa 1 + +^(a(b)?)+$ +aba +true aba 2 a b + +^(a(b(c)?)?)?abc +abc +true abc 3 + +^(a(b(c))).* +abc +true abc 3 abc bc c + +// use of x modifier +abc(?x)blah +abcblah +true abcblah 0 + +abc(?x) blah +abcblah +true abcblah 0 + +abc(?x) blah blech +abcblahblech +true abcblahblech 0 + +abc(?x) blah # ignore comment +abcblah +true abcblah 0 + +// Simple alternation +a|b +a +true a 0 + +a|b +z +false 0 + +a|b +b +true b 0 + +a|b|cd +cd +true cd 0 + +a|ad +ad +true a 0 + +z(a|ac)b +zacb +true zacb 1 ac + +// Simple char class +[abc]+ +ababab +true ababab 0 + +[abc]+ +defg +false 0 + +[abc]+[def]+[ghi]+ +zzzaaddggzzz +true aaddgg 0 + +// Range char class +[a-g]+ +zzzggg +true ggg 0 + +[a-g]+ +mmm +false 0 + +[a-]+ +za-9z +true a- 0 + +[a-\\u4444]+ +za-9z +true za 0 + +// Negated char class +[^abc]+ +ababab +false 0 + +[^abc]+ +aaabbbcccdefg +true defg 0 + +// Making sure a ^ not in first position matches literal ^ +[abc^b] +b +true b 0 + +[abc^b] +^ +true ^ 0 + +// Class union and intersection +[abc[def]] +b +true b 0 + +[abc[def]] +e +true e 0 + +[a-d[0-9][m-p]] +a +true a 0 + +[a-d[0-9][m-p]] +o +true o 0 + +[a-d[0-9][m-p]] +4 +true 4 0 + +[a-d[0-9][m-p]] +e +false 0 + +[a-d[0-9][m-p]] +u +false 0 + +[[a-d][0-9][m-p]] +b +true b 0 + +[[a-d][0-9][m-p]] +z +false 0 + +[a-c[d-f[g-i]]] +a +true a 0 + +[a-c[d-f[g-i]]] +e +true e 0 + +[a-c[d-f[g-i]]] +h +true h 0 + +[a-c[d-f[g-i]]] +m +false 0 + +[a-c[d-f[g-i]]m] +m +true m 0 + +[abc[def]ghi] +a +true a 0 + +[abc[def]ghi] +d +true d 0 + +[abc[def]ghi] +h +true h 0 + +[abc[def]ghi] +w +false 0 + +[a-c&&[d-f]] +a +false 0 + +[a-c&&[d-f]] +e +false 0 + +[a-c&&[d-f]] +z +false 0 + +[[a-c]&&[d-f]] +a +false 0 + +[[a-c]&&[d-f]] +e +false 0 + +[[a-c]&&[d-f]] +z +false 0 + +[a-c&&d-f] +a +false 0 + +[a-m&&m-z] +m +true m 0 + +[a-m&&m-z&&a-c] +m +false 0 + +[a-m&&m-z&&a-z] +m +true m 0 + +[[a-m]&&[m-z]] +a +false 0 + +[[a-m]&&[m-z]] +m +true m 0 + +[[a-m]&&[m-z]] +z +false 0 + +[[a-m]&&[^a-c]] +a +false 0 + +[[a-m]&&[^a-c]] +d +true d 0 + +[a-m&&[^a-c]] +a +false 0 + +[a-m&&[^a-c]] +d +true d 0 + +[a-cd-f&&[d-f]] +a +false 0 + +[a-cd-f&&[d-f]] +e +true e 0 + +[[a-c]&&d-fa-c] +a +true a 0 + +[[a-c]&&[d-f][a-c]] +a +true a 0 + +[[a-c][d-f]&&abc] +a +true a 0 + +[[a-c][d-f]&&abc[def]] +e +true e 0 + +[[a-c]&&[b-d]&&[c-e]] +a +false 0 + +[[a-c]&&[b-d]&&[c-e]] +c +true c 0 + +[[a-c]&&[b-d][c-e]&&[u-z]] +c +false 0 + +[abc[^bcd]] +a +true a 0 + +[abc[^bcd]] +d +false 0 + +[a-c&&a-d&&a-eghi] +b +true b 0 + +[a-c&&a-d&&a-eghi] +g +false 0 + +[[a[b]]&&[b[a]]] +a +true a 0 + +[[a]&&[b][c][a]&&[^d]] +a +true a 0 + +[[a]&&[b][c][a]&&[^d]] +d +false 0 + +[[[a-d]&&[c-f]]] +a +false 0 + +[[[a-d]&&[c-f]]] +c +true c 0 + +[[[a-d]&&[c-f]]&&[c]] +c +true c 0 + +[[[a-d]&&[c-f]]&&[c]&&c] +c +true c 0 + +[[[a-d]&&[c-f]]&&[c]&&c&&c] +c +true c 0 + +[[[a-d]&&[c-f]]&&[c]&&c&&[cde]] +c +true c 0 + +[z[abc&&bcd]] +c +true c 0 + +[z[abc&&bcd]&&[u-z]] +z +true z 0 + +[x[abc&&bcd[z]]&&[u-z]] +z +false 0 + +[x[[wz]abc&&bcd[z]]&&[u-z]] +z +true z 0 + +[[abc]&&[def]abc] +a +true a 0 + +[[abc]&&[def]xyz[abc]] +a +true a 0 + +\pL +a +true a 0 + +\pL +7 +false 0 + +\p{L} +a +true a 0 + +\p{LC} +a +true a 0 + +\p{LC} +A +true A 0 + +\p{IsL} +a +true a 0 + +\p{IsLC} +a +true a 0 + +\p{IsLC} +A +true A 0 + +\p{IsLC} +9 +false 0 + +\P{IsLC} +9 +true 9 0 + +// Guillemet left is initial quote punctuation +\p{Pi} +\u00ab +true \u00ab 0 + +\P{Pi} +\u00ac +true \u00ac 0 + +// Guillemet right is final quote punctuation +\p{IsPf} +\u00bb +true \u00bb 0 + +\p{P} +\u00bb +true \u00bb 0 + +\p{P}+ +\u00bb +true \u00bb 0 + +\P{IsPf} +\u00bc +true \u00bc 0 + +\P{IsP} +\u00bc +true \u00bc 0 + +\p{L1} +\u00bc +true \u00bc 0 + +\p{L1}+ +\u00bc +true \u00bc 0 + +\p{L1} +\u02bc +false 0 + +\p{ASCII} +a +true a 0 + +\p{IsASCII} +a +true a 0 + +\p{IsASCII} +\u0370 +false 0 + +\pLbc +abc +true abc 0 + +a[r\p{InGreek}]c +a\u0370c +true a\u0370c 0 + +a\p{InGreek} +a\u0370 +true a\u0370 0 + +a\P{InGreek} +a\u0370 +false 0 + +a\P{InGreek} +ab +true ab 0 + +a{^InGreek} +- +error + +a\p{^InGreek} +- +error + +a\P{^InGreek} +- +error + +a\p{InGreek} +a\u0370 +true a\u0370 0 + +a[\p{InGreek}]c +a\u0370c +true a\u0370c 0 + +a[\P{InGreek}]c +a\u0370c +false 0 + +a[\P{InGreek}]c +abc +true abc 0 + +a[{^InGreek}]c +anc +true anc 0 + +a[{^InGreek}]c +azc +false 0 + +a[\p{^InGreek}]c +- +error + +a[\P{^InGreek}]c +- +error + +a[\p{InGreek}] +a\u0370 +true a\u0370 0 + +a[r\p{InGreek}]c +arc +true arc 0 + +a[\p{InGreek}r]c +arc +true arc 0 + +a[r\p{InGreek}]c +arc +true arc 0 + +a[^\p{InGreek}]c +a\u0370c +false 0 + +a[^\P{InGreek}]c +a\u0370c +true a\u0370c 0 + +a[\p{InGreek}&&[^\u0370]]c +a\u0370c +false 0 + +// Test the dot metacharacter +a.c.+ +a#c%& +true a#c%& 0 + +ab. +ab\n +false 0 + +(?s)ab. +ab\n +true ab\n 0 + +a[\p{L}&&[\P{InGreek}]]c +a\u6000c +true a\u6000c 0 + +a[\p{L}&&[\P{InGreek}]]c +arc +true arc 0 + +a[\p{L}&&[\P{InGreek}]]c +a\u0370c +false 0 + +a\p{InGreek}c +a\u0370c +true a\u0370c 0 + +a\p{Sc} +a$ +true a$ 0 + +// Test the word char escape sequence +ab\wc +abcc +true abcc 0 + +\W\w\W +#r# +true #r# 0 + +\W\w\W +rrrr#ggg +false 0 + +abc[\w] +abcd +true abcd 0 + +abc[\sdef]* +abc def +true abc def 0 + +abc[\sy-z]* +abc y z +true abc y z 0 + +abc[a-d\sm-p]* +abcaa mn p +true abcaa mn p 0 + +// Test the whitespace escape sequence +ab\sc +ab c +true ab c 0 + +\s\s\s +blah err +false 0 + +\S\S\s +blah err +true ah 0 + +// Test the digit escape sequence +ab\dc +ab9c +true ab9c 0 + +\d\d\d +blah45 +false 0 + +// Test the caret metacharacter +^abc +abcdef +true abc 0 + +^abc +bcdabc +false 0 + +// Greedy ? metacharacter +a?b +aaaab +true ab 0 + +a?b +b +true b 0 + +a?b +aaaccc +false 0 + +.?b +aaaab +true ab 0 + +// Reluctant ? metacharacter +a??b +aaaab +true ab 0 + +a??b +b +true b 0 + +a??b +aaaccc +false 0 + +.??b +aaaab +true ab 0 + +// Possessive ? metacharacter +a?+b +aaaab +true ab 0 + +a?+b +b +true b 0 + +a?+b +aaaccc +false 0 + +.?+b +aaaab +true ab 0 + +// Greedy + metacharacter +a+b +aaaab +true aaaab 0 + +a+b +b +false 0 + +a+b +aaaccc +false 0 + +.+b +aaaab +true aaaab 0 + +// Reluctant + metacharacter +a+?b +aaaab +true aaaab 0 + +a+?b +b +false 0 + +a+?b +aaaccc +false 0 + +.+?b +aaaab +true aaaab 0 + +// Possessive + metacharacter +a++b +aaaab +true aaaab 0 + +a++b +b +false 0 + +a++b +aaaccc +false 0 + +.++b +aaaab +false 0 + +// Greedy Repetition +a{2,3} +a +false 0 + +a{2,3} +aa +true aa 0 + +a{2,3} +aaa +true aaa 0 + +a{2,3} +aaaa +true aaa 0 + +a{3,} +zzzaaaazzz +true aaaa 0 + +a{3,} +zzzaazzz +false 0 + +// Reluctant Repetition +a{2,3}? +a +false 0 + +a{2,3}? +aa +true aa 0 + +a{2,3}? +aaa +true aa 0 + +a{2,3}? +aaaa +true aa 0 + +// Zero width Positive lookahead +abc(?=d) +zzzabcd +true abc 0 + +abc(?=d) +zzzabced +false 0 + +// Zero width Negative lookahead +abc(?!d) +zzabcd +false 0 + +abc(?!d) +zzabced +true abc 0 + +// Zero width Positive lookbehind +\w(?<=a) +###abc### +true a 0 + +\w(?<=a) +###ert### +false 0 + +// Zero width Negative lookbehind +(?<!a)\w +###abc### +true a 0 + +(?<!a)c +bc +true c 0 + +(?<!a)c +ac +false 0 + +// Nondeterministic group +(a+b)+ +ababab +true ababab 1 ab + +(a|b)+ +ccccd +false 1 + +// Deterministic group +(ab)+ +ababab +true ababab 1 ab + +(ab)+ +accccd +false 1 + +(ab)* +ababab +true ababab 1 ab + +(ab)(cd*) +zzzabczzz +true abc 2 ab c + +abc(d)*abc +abcdddddabc +true abcdddddabc 1 d + +// Escaped metacharacter +\* +* +true * 0 + +\\ +\ +true \ 0 + +\\ +\\\\ +true \ 0 + +// Back references +(a*)bc\1 +zzzaabcaazzz +true aabcaa 1 aa + +(a*)bc\1 +zzzaabcazzz +true abca 1 a + +(gt*)(dde)*(yu)\1\3(vv) +zzzgttddeddeyugttyuvvzzz +true gttddeddeyugttyuvv 4 gtt dde yu vv + +// Greedy * metacharacter +a*b +aaaab +true aaaab 0 + +a*b +b +true b 0 + +a*b +aaaccc +false 0 + +.*b +aaaab +true aaaab 0 + +// Reluctant * metacharacter +a*?b +aaaab +true aaaab 0 + +a*?b +b +true b 0 + +a*?b +aaaccc +false 0 + +.*?b +aaaab +true aaaab 0 + +// Possessive * metacharacter +a*+b +aaaab +true aaaab 0 + +a*+b +b +true b 0 + +a*+b +aaaccc +false 0 + +.*+b +aaaab +false 0 + +// Case insensitivity +(?i)foobar +fOobAr +true fOobAr 0 + +f(?i)oobar +fOobAr +true fOobAr 0 + +foo(?i)bar +fOobAr +false 0 + +(?i)foo[bar]+ +foObAr +true foObAr 0 + +(?i)foo[a-r]+ +foObAr +true foObAr 0 + +// Disable metacharacters- test both length <=3 and >3 +// So that the BM optimization is part of test +\Q***\Eabc +***abc +true ***abc 0 + +bl\Q***\Eabc +bl***abc +true bl***abc 0 + +\Q***abc +***abc +true ***abc 0 + +blah\Q***\Eabc +blah***abc +true blah***abc 0 + +\Q***abc +***abc +true ***abc 0 + +\Q*ab +*ab +true *ab 0 + +blah\Q***abc +blah***abc +true blah***abc 0 + +bla\Q***abc +bla***abc +true bla***abc 0 + +// Escapes in char classes +[ab\Qdef\E] +d +true d 0 + +[ab\Q[\E] +[ +true [ 0 + +[\Q]\E] +] +true ] 0 + +[\Q\\E] +\ +true \ 0 + +[\Q(\E] +( +true ( 0 + +[\n-#] +! +true ! 0 + +[\n-#] +- +false 0 + +[\w-#] +! +false 0 + +[\w-#] +a +true a 0 + +[\w-#] +- +true - 0 + +[\w-#] +# +true # 0 + +[\043]+ +blahblah#blech +true # 0 + +[\042-\044]+ +blahblah#blech +true # 0 + +[\u1234-\u1236] +blahblah\u1235blech +true \u1235 0 + +[^\043]* +blahblah#blech +true blahblah 0 + +(|f)?+ +foo +true 1 diff --git a/jdk/test/java/util/zip/LargeZip.java b/jdk/test/java/util/zip/LargeZip.java new file mode 100644 index 00000000000..e49950261b6 --- /dev/null +++ b/jdk/test/java/util/zip/LargeZip.java @@ -0,0 +1,193 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.*; +import java.nio.*; +import java.util.*; +import java.util.zip.*; + +public class LargeZip { + // If true, don't delete large ZIP file created for test. + static final boolean debug = System.getProperty("debug") != null; + + //static final int DATA_LEN = 1024 * 1024; + static final int DATA_LEN = 80 * 1024; + static final int DATA_SIZE = 8; + + static long fileSize = 6L * 1024L * 1024L * 1024L; // 6GB + + static boolean userFile = false; + + static byte[] data; + static File largeFile; + static String lastEntryName; + + /* args can be empty, in which case check a 3 GB file which is created for + * this test (and then deleted). Or it can be a number, in which case + * that designates the size of the file that's created for this test (and + * then deleted). Or it can be the name of a file to use for the test, in + * which case it is *not* deleted. Note that in this last case, the data + * comparison might fail. + */ + static void realMain (String[] args) throws Throwable { + if (args.length > 0) { + try { + fileSize = Long.parseLong(args[0]); + System.out.println("Testing with file of size " + fileSize); + } catch (NumberFormatException ex) { + largeFile = new File(args[0]); + if (!largeFile.exists()) { + throw new Exception("Specified file " + args[0] + " does not exist"); + } + userFile = true; + System.out.println("Testing with user-provided file " + largeFile); + } + } + File testDir = null; + if (largeFile == null) { + testDir = new File(System.getProperty("test.scratch", "."), + "LargeZip"); + if (testDir.exists()) { + if (!testDir.delete()) { + throw new Exception("Cannot delete already-existing test directory"); + } + } + check(!testDir.exists() && testDir.mkdirs()); + largeFile = new File(testDir, "largezip.zip"); + createLargeZip(); + } + + readLargeZip1(); + readLargeZip2(); + + if (!userFile && !debug) { + check(largeFile.delete()); + check(testDir.delete()); + } + } + + static void createLargeZip() throws Throwable { + int iterations = DATA_LEN / DATA_SIZE; + ByteBuffer bb = ByteBuffer.allocate(DATA_SIZE); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < iterations; i++) { + bb.putDouble(0, Math.random()); + baos.write(bb.array(), 0, DATA_SIZE); + } + data = baos.toByteArray(); + + ZipOutputStream zos = new ZipOutputStream( + new BufferedOutputStream(new FileOutputStream(largeFile))); + long length = 0; + while (length < fileSize) { + ZipEntry ze = new ZipEntry("entry-" + length); + lastEntryName = ze.getName(); + zos.putNextEntry(ze); + zos.write(data, 0, data.length); + zos.closeEntry(); + length = largeFile.length(); + } + System.out.println("Last entry written is " + lastEntryName); + zos.close(); + } + + static void readLargeZip1() throws Throwable { + ZipFile zipFile = new ZipFile(largeFile); + ZipEntry entry = null; + String entryName = null; + int count = 0; + Enumeration<? extends ZipEntry> entries = zipFile.entries(); + while (entries.hasMoreElements()) { + entry = entries.nextElement(); + entryName = entry.getName(); + count++; + } + System.out.println("Number of entries read: " + count); + System.out.println("Last entry read is " + entryName); + check(!entry.isDirectory()); + if (check(entryName.equals(lastEntryName))) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream is = zipFile.getInputStream(entry); + byte buf[] = new byte[4096]; + int len; + while ((len = is.read(buf)) >= 0) { + baos.write(buf, 0, len); + } + baos.close(); + is.close(); + check(Arrays.equals(data, baos.toByteArray())); + } + } + + + static void readLargeZip2() throws Throwable { + ZipInputStream zis = new ZipInputStream( + new BufferedInputStream(new FileInputStream(largeFile))); + ZipEntry entry = null; + String entryName = null; + int count = 0; + while ((entry = zis.getNextEntry()) != null) { + entryName = entry.getName(); + if (entryName.equals(lastEntryName)) { + break; + } + count++; + } + System.out.println("Number of entries read: " + count); + System.out.println("Last entry read is " + entryName); + check(!entry.isDirectory()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + byte buf[] = new byte[4096]; + int len; + while ((len = zis.read(buf)) >= 0) { + baos.write(buf, 0, len); + } + baos.close(); + check(Arrays.equals(data, baos.toByteArray())); + check(zis.getNextEntry() == null); + zis.close(); + } + + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void pass(String msg) {System.out.println(msg); passed++;} + static void fail() {failed++; Thread.dumpStack();} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void unexpected(Throwable t, String msg) { + System.out.println(msg); failed++; t.printStackTrace();} + static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.println("\nPassed = " + passed + " failed = " + failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/jdk/test/java/util/zip/ZipFile/LargeZipFile.java b/jdk/test/java/util/zip/ZipFile/LargeZipFile.java new file mode 100644 index 00000000000..d228a5f93e3 --- /dev/null +++ b/jdk/test/java/util/zip/ZipFile/LargeZipFile.java @@ -0,0 +1,160 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.*; +import java.nio.*; +import java.util.*; +import java.util.zip.*; + +public class LargeZipFile { + // If true, don't delete large ZIP file created for test. + static final boolean debug = System.getProperty("debug") != null; + + static final int DATA_LEN = 1024 * 1024; + static final int DATA_SIZE = 8; + + static long fileSize = 3L * 1024L * 1024L * 1024L; // 3GB + + static boolean userFile = false; + + static byte[] data; + static File largeFile; + static String lastEntryName; + + /* args can be empty, in which case check a 3 GB file which is created for + * this test (and then deleted). Or it can be a number, in which case + * that designates the size of the file that's created for this test (and + * then deleted). Or it can be the name of a file to use for the test, in + * which case it is *not* deleted. Note that in this last case, the data + * comparison might fail. + */ + static void realMain (String[] args) throws Throwable { + if (args.length > 0) { + try { + fileSize = Long.parseLong(args[0]); + System.out.println("Testing with file of size " + fileSize); + } catch (NumberFormatException ex) { + largeFile = new File(args[0]); + if (!largeFile.exists()) { + throw new Exception("Specified file " + args[0] + " does not exist"); + } + userFile = true; + System.out.println("Testing with user-provided file " + largeFile); + } + } + File testDir = null; + if (largeFile == null) { + testDir = new File(System.getProperty("test.scratch", "."), + "LargeZip"); + if (testDir.exists()) { + if (!testDir.delete()) { + throw new Exception("Cannot delete already-existing test directory"); + } + } + check(!testDir.exists() && testDir.mkdirs()); + largeFile = new File(testDir, "largezip.zip"); + createLargeZip(); + } + + readLargeZip(); + + if (!userFile && !debug) { + check(largeFile.delete()); + check(testDir.delete()); + } + } + + static void createLargeZip() throws Throwable { + int iterations = DATA_LEN / DATA_SIZE; + ByteBuffer bb = ByteBuffer.allocate(DATA_SIZE); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < iterations; i++) { + bb.putDouble(0, Math.random()); + baos.write(bb.array(), 0, DATA_SIZE); + } + data = baos.toByteArray(); + + ZipOutputStream zos = new ZipOutputStream( + new BufferedOutputStream(new FileOutputStream(largeFile))); + long length = 0; + while (length < fileSize) { + ZipEntry ze = new ZipEntry("entry-" + length); + lastEntryName = ze.getName(); + zos.putNextEntry(ze); + zos.write(data, 0, data.length); + zos.closeEntry(); + length = largeFile.length(); + } + System.out.println("Last entry written is " + lastEntryName); + zos.close(); + } + + static void readLargeZip() throws Throwable { + ZipFile zipFile = new ZipFile(largeFile); + ZipEntry entry = null; + String entryName = null; + int count = 0; + Enumeration<? extends ZipEntry> entries = zipFile.entries(); + while (entries.hasMoreElements()) { + entry = entries.nextElement(); + entryName = entry.getName(); + count++; + } + System.out.println("Number of entries read: " + count); + System.out.println("Last entry read is " + entryName); + check(!entry.isDirectory()); + if (check(entryName.equals(lastEntryName))) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream is = zipFile.getInputStream(entry); + byte buf[] = new byte[4096]; + int len; + while ((len = is.read(buf)) >= 0) { + baos.write(buf, 0, len); + } + baos.close(); + is.close(); + check(Arrays.equals(data, baos.toByteArray())); + } + try { + zipFile.close(); + } catch (IOException ioe) {/* what can you do */ } + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void pass(String msg) {System.out.println(msg); passed++;} + static void fail() {failed++; Thread.dumpStack();} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void unexpected(Throwable t, String msg) { + System.out.println(msg); failed++; t.printStackTrace();} + static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.println("\nPassed = " + passed + " failed = " + failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/jdk/test/javax/imageio/metadata/BooleanAttributes.java b/jdk/test/javax/imageio/metadata/BooleanAttributes.java new file mode 100644 index 00000000000..104b12432c8 --- /dev/null +++ b/jdk/test/javax/imageio/metadata/BooleanAttributes.java @@ -0,0 +1,202 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 5082756 + * @summary ensure that boolean attributes follow ( "TRUE" | "FALSE" ) + * including correct (i.e. upper) case + * + * @run main BooleanAttributes + */ + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.StringReader; +import java.util.Arrays; +import java.util.List; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.MemoryCacheImageInputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class BooleanAttributes { + + private static TransformerFactory transformerFactory = + TransformerFactory.newInstance(); + + private static XPath xpathEngine = XPathFactory.newInstance().newXPath(); + + public static void main(String[] args) throws Exception { + test("image/png", false, "<javax_imageio_1.0 />", + "Chroma/BlackIsZero/@value", + "Compression/Lossless/@value"); + + test("image/png", false, + "<javax_imageio_png_1.0>" + + "<iTXt><iTXtEntry keyword='Comment' compressionFlag='TRUE' " + + "compressionMethod='0' languageTag='en' " + + "translatedKeyword='comment' text='foo'/></iTXt>" + + "</javax_imageio_png_1.0>", + "iTXt/iTXtEntry/@compressionFlag"); + + test("image/png", false, + "<javax_imageio_png_1.0>" + + "<iTXt><iTXtEntry keyword='Comment' compressionFlag='FALSE' " + + "compressionMethod='0' languageTag='en' " + + "translatedKeyword='comment' text='foo'/></iTXt>" + + "</javax_imageio_png_1.0>", + "iTXt/iTXtEntry/@compressionFlag"); + + test("image/gif", false, "<javax_imageio_1.0 />", + "Chroma/BlackIsZero/@value", + "Compression/Lossless/@value"); + + test("image/gif", false, + "<javax_imageio_gif_image_1.0>" + + "<ImageDescriptor imageLeftPosition='0' imageTopPosition='0' " + + "imageWidth='16' imageHeight='16' interlaceFlag='TRUE' />" + + "<LocalColorTable sizeOfLocalColorTable='2' " + + "backgroundColorIndex='1' sortFlag='TRUE'>" + + "<ColorTableEntry index='0' red='0' green='0' blue='0' />" + + "<ColorTableEntry index='1' red='255' green='255' blue='255' />" + + "</LocalColorTable>" + + "<GraphicControlExtension disposalMethod='doNotDispose' " + + "userInputFlag='FALSE' transparentColorFlag='TRUE' " + + "delayTime='100' transparentColorIndex='1' />" + + "</javax_imageio_gif_image_1.0>", + "ImageDescriptor/@interlaceFlag", + "LocalColorTable/@sortFlag", + "GraphicControlExtension/@userInputFlag", + "GraphicControlExtension/@transparentColorFlag"); + + test("image/gif", true, + "<javax_imageio_gif_stream_1.0>" + + "<GlobalColorTable sizeOfGlobalColorTable='2' " + + "backgroundColorIndex='1' sortFlag='TRUE'>" + + "<ColorTableEntry index='0' red='0' green='0' blue='0' />" + + "<ColorTableEntry index='1' red='255' green='255' blue='255' />" + + "</GlobalColorTable>" + + "</javax_imageio_gif_stream_1.0>", + "GlobalColorTable/@sortFlag"); + + test("image/jpeg", false, "<javax_imageio_1.0 />", + "Compression/Lossless/@value"); + } + + private static void transform(Source src, Result dst) + throws Exception + { + transformerFactory.newTransformer().transform(src, dst); + } + + private static void verify(Node meta, String[] xpaths, boolean required) + throws Exception + { + for (String xpath: xpaths) { + NodeList list = (NodeList) + xpathEngine.evaluate(xpath, meta, XPathConstants.NODESET); + if (list.getLength() == 0 && required) + throw new AssertionError("Missing value: " + xpath); + for (int i = 0; i < list.getLength(); ++i) { + String value = list.item(i).getNodeValue(); + if (!(value.equals("TRUE") || value.equals("FALSE"))) + throw new AssertionError(xpath + " has value " + value); + } + } + } + + public static void test(String mimeType, boolean useStreamMeta, + String metaXml, String... boolXpaths) + throws Exception + { + BufferedImage img = + new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB); + ImageWriter iw = ImageIO.getImageWritersByMIMEType(mimeType).next(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageOutputStream ios = new MemoryCacheImageOutputStream(os); + iw.setOutput(ios); + ImageWriteParam param = null; + IIOMetadata streamMeta = iw.getDefaultStreamMetadata(param); + IIOMetadata imageMeta = + iw.getDefaultImageMetadata(new ImageTypeSpecifier(img), param); + IIOMetadata meta = useStreamMeta ? streamMeta : imageMeta; + Source src = new StreamSource(new StringReader(metaXml)); + DOMResult dst = new DOMResult(); + transform(src, dst); + Document doc = (Document)dst.getNode(); + Element node = doc.getDocumentElement(); + String metaFormat = node.getNodeName(); + + // Verify that the default metadata gets formatted correctly. + verify(meta.getAsTree(metaFormat), boolXpaths, false); + + meta.mergeTree(metaFormat, node); + + // Verify that the merged metadata gets formatte correctly. + verify(meta.getAsTree(metaFormat), boolXpaths, true); + + iw.write(streamMeta, new IIOImage(img, null, imageMeta), param); + iw.dispose(); + ios.close(); + ImageReader ir = ImageIO.getImageReader(iw); + byte[] bytes = os.toByteArray(); + if (bytes.length == 0) + throw new AssertionError("Zero length image file"); + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + ImageInputStream iis = new MemoryCacheImageInputStream(is); + ir.setInput(iis); + if (useStreamMeta) meta = ir.getStreamMetadata(); + else meta = ir.getImageMetadata(0); + + // Verify again after writing and re-reading the image + verify(meta.getAsTree(metaFormat), boolXpaths, true); + } + + public static void xtest(Object... eatAnyArguments) { + System.err.println("Disabled test! Change xtest back into test!"); + } + +} diff --git a/jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java b/jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java new file mode 100644 index 00000000000..407242161c2 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java @@ -0,0 +1,161 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6795544 + * + * @summary Test verifes that Image I/O gif writer correctly handles + * buffered images based on translated reasters (typically + * produced by getSubImage() method). + * + * @run main EncodeSubImageTest gif + */ + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.io.File; +import java.io.IOException; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeSubImageTest { + private static String format = "gif"; + private static ImageWriter writer; + private static String file_suffix; + private static final int subSampleX = 2; + private static final int subSampleY = 2; + + public static void main(String[] args) throws IOException { + if (args.length > 0) { + format = args[0]; + } + + writer = ImageIO.getImageWritersByFormatName(format).next(); + + file_suffix =writer.getOriginatingProvider().getFileSuffixes()[0]; + + BufferedImage src = createTestImage(); + EncodeSubImageTest m1 = new EncodeSubImageTest(src); + m1.doTest("test_src"); + + BufferedImage sub = src.getSubimage(subImageOffset, subImageOffset, + src.getWidth() - 2 * subImageOffset, + src.getHeight() - 2 * subImageOffset); + EncodeSubImageTest m2 = new EncodeSubImageTest(sub); + m2.doTest("test_sub"); + } + + BufferedImage img; + + public EncodeSubImageTest(BufferedImage img) { + this.img = img; + } + + public void doTest(String prefix) throws IOException { + System.out.println(prefix); + File f = new File(prefix + file_suffix); + write(f, false); + verify(f, false); + + System.out.println(prefix + "_subsampled"); + f = new File(prefix + "_subsampled"); + write(f, true); + verify(f, true); + + System.out.println(prefix + ": Test PASSED."); + } + + private static final int subImageOffset = 10; + + private void verify(File f, boolean isSubsampled) { + BufferedImage dst = null; + try { + dst = ImageIO.read(f); + } catch (IOException e) { + throw new RuntimeException("Test FAILED: can't readin test image " + + f.getAbsolutePath(), e); + } + if (dst == null) { + throw new RuntimeException("Test FAILED: no dst image available."); + } + + checkPixel(dst, 0, 0, isSubsampled); + + checkPixel(dst, img.getWidth() / 2, img.getHeight() / 2, isSubsampled); + } + + private void checkPixel(BufferedImage dst, int x, int y, + boolean isSubsampled) + { + int dx = isSubsampled ? x / subSampleX : x; + int dy = isSubsampled ? y / subSampleY : y; + int src_rgb = img.getRGB(x, y); + System.out.printf("src_rgb: %x\n", src_rgb); + + int dst_rgb = dst.getRGB(dx, dy); + System.out.printf("dst_rgb: %x\n", dst_rgb); + + if (src_rgb != dst_rgb) { + throw new RuntimeException("Test FAILED: invalid color in dst"); + } + } + + private static BufferedImage createTestImage() { + int w = 100; + int h = 100; + + BufferedImage src = new BufferedImage(w, h, + BufferedImage.TYPE_BYTE_INDEXED); + Graphics g = src.createGraphics(); + g.setColor(Color.red); + g.fillRect(0, 0, w, h); + g.setColor(Color.green); + g.fillRect(subImageOffset, subImageOffset, + w - 2 * subImageOffset, h - 2* subImageOffset); + g.setColor(Color.blue); + g.fillRect(2 * subImageOffset, 2 * subImageOffset, + w - 4 * subImageOffset, h - 4 * subImageOffset); + g.dispose(); + + return src; + } + + private void write(File f, boolean subsample) throws IOException { + ImageOutputStream ios = ImageIO.createImageOutputStream(f); + + writer.setOutput(ios); + ImageWriteParam p = writer.getDefaultWriteParam(); + if (subsample) { + p.setSourceSubsampling(subSampleX, subSampleY, 0, 0); + } + writer.write(null, new IIOImage(img, null, null), p); + ios.close(); + writer.reset(); + } +} diff --git a/jdk/test/javax/imageio/plugins/png/ITXtTest.java b/jdk/test/javax/imageio/plugins/png/ITXtTest.java index 9bace746227..ec81bd874ac 100644 --- a/jdk/test/javax/imageio/plugins/png/ITXtTest.java +++ b/jdk/test/javax/imageio/plugins/png/ITXtTest.java @@ -123,7 +123,7 @@ public class ITXtTest { } t.keyword = e.getAttribute("keyword"); t.isCompressed = - (Integer.valueOf(e.getAttribute("compressionFlag")).intValue() == 1); + Boolean.valueOf(e.getAttribute("compressionFlag")).booleanValue(); t.compression = Integer.valueOf(e.getAttribute("compressionMethod")).intValue(); t.language = e.getAttribute("languageTag"); diff --git a/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java b/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java new file mode 100644 index 00000000000..e35495bdee1 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java @@ -0,0 +1,241 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6541476 6782079 + * @summary Write and read a PNG file including an non-latin1 iTXt chunk + * Test also verifies that trunkated png images does not cause + * an OoutOfMemory error. + * + * @run main ItxtUtf8Test + * + * @run main/othervm/timeout=10 -Xmx2m ItxtUtf8Test truncate + */ + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.List; +import javax.imageio.IIOException; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.MemoryCacheImageInputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; + +public class ItxtUtf8Test { + + public static final String + TEXT = "\u24c9\u24d4\u24e7\u24e3" + + "\ud835\udc13\ud835\udc1e\ud835\udc31\ud835\udc2d" + + "\u24c9\u24d4\u24e7\u24e3", // a repetition for compression + VERBATIM = "\u24e5\u24d4\u24e1\u24d1\u24d0\u24e3\u24d8\u24dc", + COMPRESSED = "\u24d2\u24de\u24dc\u24df\u24e1\u24d4\u24e2\u24e2\u24d4\u24d3"; + + public static final byte[] + VBYTES = { + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x56, // chunk length + (byte)0x69, (byte)0x54, (byte)0x58, (byte)0x74, // chunk type "iTXt" + (byte)0x76, (byte)0x65, (byte)0x72, (byte)0x62, + (byte)0x61, (byte)0x74, (byte)0x69, (byte)0x6d, // keyword "verbatim" + (byte)0x00, // separator terminating keyword + (byte)0x00, // compression flag + (byte)0x00, // compression method, must be zero + (byte)0x78, (byte)0x2d, (byte)0x63, (byte)0x69, + (byte)0x72, (byte)0x63, (byte)0x6c, (byte)0x65, + (byte)0x64, // language tag "x-circled" + (byte)0x00, // separator terminating language tag + (byte)0xe2, (byte)0x93, (byte)0xa5, // '\u24e5' + (byte)0xe2, (byte)0x93, (byte)0x94, // '\u24d4' + (byte)0xe2, (byte)0x93, (byte)0xa1, // '\u24e1' + (byte)0xe2, (byte)0x93, (byte)0x91, // '\u24d1' + (byte)0xe2, (byte)0x93, (byte)0x90, // '\u24d0' + (byte)0xe2, (byte)0x93, (byte)0xa3, // '\u24e3' + (byte)0xe2, (byte)0x93, (byte)0x98, // '\u24d8' + (byte)0xe2, (byte)0x93, (byte)0x9c, // '\u24dc' + (byte)0x00, // separator terminating the translated keyword + (byte)0xe2, (byte)0x93, (byte)0x89, // '\u24c9' + (byte)0xe2, (byte)0x93, (byte)0x94, // '\u24d4' + (byte)0xe2, (byte)0x93, (byte)0xa7, // '\u24e7' + (byte)0xe2, (byte)0x93, (byte)0xa3, // '\u24e3' + (byte)0xf0, (byte)0x9d, (byte)0x90, (byte)0x93, // '\ud835\udc13' + (byte)0xf0, (byte)0x9d, (byte)0x90, (byte)0x9e, // '\ud835\udc1e' + (byte)0xf0, (byte)0x9d, (byte)0x90, (byte)0xb1, // '\ud835\udc31' + (byte)0xf0, (byte)0x9d, (byte)0x90, (byte)0xad, // '\ud835\udc2d' + (byte)0xe2, (byte)0x93, (byte)0x89, // '\u24c9' + (byte)0xe2, (byte)0x93, (byte)0x94, // '\u24d4' + (byte)0xe2, (byte)0x93, (byte)0xa7, // '\u24e7' + (byte)0xe2, (byte)0x93, (byte)0xa3, // '\u24e3' + (byte)0xb5, (byte)0xcc, (byte)0x97, (byte)0x56 // CRC + }, + CBYTES = { + // we don't want to check the chunk length, + // as this might depend on implementation. + (byte)0x69, (byte)0x54, (byte)0x58, (byte)0x74, // chunk type "iTXt" + (byte)0x63, (byte)0x6f, (byte)0x6d, (byte)0x70, + (byte)0x72, (byte)0x65, (byte)0x73, (byte)0x73, + (byte)0x65, (byte)0x64, // keyword "compressed" + (byte)0x00, // separator terminating keyword + (byte)0x01, // compression flag + (byte)0x00, // compression method, 0=deflate + (byte)0x78, (byte)0x2d, (byte)0x63, (byte)0x69, + (byte)0x72, (byte)0x63, (byte)0x6c, (byte)0x65, + (byte)0x64, // language tag "x-circled" + (byte)0x00, // separator terminating language tag + // we don't want to check the actual compressed data, + // as this might depend on implementation. + }; +/* +*/ + + public static void main(String[] args) throws Exception { + List argList = Arrays.asList(args); + if (argList.contains("truncate")) { + try { + runTest(false, true); + throw new AssertionError("Expect an error for truncated file"); + } + catch (IIOException e) { + // expected an error for a truncated image file. + } + } + else { + runTest(argList.contains("dump"), false); + } + } + + public static void runTest(boolean dump, boolean truncate) + throws Exception + { + String format = "javax_imageio_png_1.0"; + BufferedImage img = + new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB); + ImageWriter iw = ImageIO.getImageWritersByMIMEType("image/png").next(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageOutputStream ios = new MemoryCacheImageOutputStream(os); + iw.setOutput(ios); + IIOMetadata meta = + iw.getDefaultImageMetadata(new ImageTypeSpecifier(img), null); + DOMImplementationRegistry registry; + registry = DOMImplementationRegistry.newInstance(); + DOMImplementation impl = registry.getDOMImplementation("XML 3.0"); + Document doc = impl.createDocument(null, format, null); + Element root, itxt, entry; + root = doc.getDocumentElement(); + root.appendChild(itxt = doc.createElement("iTXt")); + itxt.appendChild(entry = doc.createElement("iTXtEntry")); + entry.setAttribute("keyword", "verbatim"); + entry.setAttribute("compressionFlag", "false"); + entry.setAttribute("compressionMethod", "0"); + entry.setAttribute("languageTag", "x-circled"); + entry.setAttribute("translatedKeyword", VERBATIM); + entry.setAttribute("text", TEXT); + itxt.appendChild(entry = doc.createElement("iTXtEntry")); + entry.setAttribute("keyword", "compressed"); + entry.setAttribute("compressionFlag", "true"); + entry.setAttribute("compressionMethod", "0"); + entry.setAttribute("languageTag", "x-circled"); + entry.setAttribute("translatedKeyword", COMPRESSED); + entry.setAttribute("text", TEXT); + meta.mergeTree(format, root); + iw.write(new IIOImage(img, null, meta)); + iw.dispose(); + + byte[] bytes = os.toByteArray(); + if (dump) + System.out.write(bytes); + if (findBytes(VBYTES, bytes) < 0) + throw new AssertionError("verbatim block not found"); + if (findBytes(CBYTES, bytes) < 0) + throw new AssertionError("compressed block not found"); + int length = bytes.length; + if (truncate) + length = findBytes(VBYTES, bytes) + 32; + + ImageReader ir = ImageIO.getImageReader(iw); + ByteArrayInputStream is = new ByteArrayInputStream(bytes, 0, length); + ImageInputStream iis = new MemoryCacheImageInputStream(is); + ir.setInput(iis); + meta = ir.getImageMetadata(0); + Node node = meta.getAsTree(format); + for (node = node.getFirstChild(); + !"iTXt".equals(node.getNodeName()); + node = node.getNextSibling()); + boolean verbatimSeen = false, compressedSeen = false; + for (node = node.getFirstChild(); + node != null; + node = node.getNextSibling()) { + entry = (Element)node; + String keyword = entry.getAttribute("keyword"); + String translatedKeyword = entry.getAttribute("translatedKeyword"); + String text = entry.getAttribute("text"); + if ("verbatim".equals(keyword)) { + if (verbatimSeen) throw new AssertionError("Duplicate"); + verbatimSeen = true; + if (!VERBATIM.equals(translatedKeyword)) + throw new AssertionError("Wrong translated keyword"); + if (!TEXT.equals(text)) + throw new AssertionError("Wrong text"); + } + else if ("compressed".equals(keyword)) { + if (compressedSeen) throw new AssertionError("Duplicate"); + compressedSeen = true; + if (!COMPRESSED.equals(translatedKeyword)) + throw new AssertionError("Wrong translated keyword"); + if (!TEXT.equals(text)) + throw new AssertionError("Wrong text"); + } + else { + throw new AssertionError("Unexpected keyword"); + } + } + if (!(verbatimSeen && compressedSeen)) + throw new AssertionError("Missing chunk"); + } + + private static final int findBytes(byte[] needle, byte[] haystack) { + HAYSTACK: for (int h = 0; h <= haystack.length - needle.length; ++h) { + for (int n = 0; n < needle.length; ++n) { + if (needle[n] != haystack[h + n]) { + continue HAYSTACK; + } + } + return h; + } + return -1; + } + +} diff --git a/jdk/test/javax/imageio/plugins/png/MergeStdCommentTest.java b/jdk/test/javax/imageio/plugins/png/MergeStdCommentTest.java new file mode 100644 index 00000000000..21a7c5f10d0 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/png/MergeStdCommentTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 5106550 + * @summary Merge a comment using the standard metdata format + * and only a minimal set of attributes + */ + +import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; + +public class MergeStdCommentTest { + + public static void main(String[] args) throws Exception { + String format = "javax_imageio_1.0"; + BufferedImage img = + new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB); + ImageWriter iw = ImageIO.getImageWritersByMIMEType("image/png").next(); + IIOMetadata meta = + iw.getDefaultImageMetadata(new ImageTypeSpecifier(img), null); + DOMImplementationRegistry registry; + registry = DOMImplementationRegistry.newInstance(); + DOMImplementation impl = registry.getDOMImplementation("XML 3.0"); + Document doc = impl.createDocument(null, format, null); + Element root, text, entry; + root = doc.getDocumentElement(); + root.appendChild(text = doc.createElement("Text")); + text.appendChild(entry = doc.createElement("TextEntry")); + // keyword isn't #REQUIRED by the standard metadata format. + // However, it is required by the PNG format, so we include it here. + entry.setAttribute("keyword", "Comment"); + entry.setAttribute("value", "Some demo comment"); + meta.mergeTree(format, root); + } +} diff --git a/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh b/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh new file mode 100644 index 00000000000..af3e428cb30 --- /dev/null +++ b/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh @@ -0,0 +1,205 @@ +#!/bin/ksh -p +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# @test +# @bug 6788096 +# @summary Test simulates the case of multiple applets executed in +# the same VM and verifies that ImageIO shutdown hook +# StreamCloser does not cause a leak of classloaders. +# +# @build test.Main +# @build testapp.Main +# @run shell run_test.sh + +# There are several resources which need to be present before many +# shell scripts can run. Following are examples of how to check for +# many common ones. +# +# Note that the shell used is the Korn Shell, KSH +# +# Also note, it is recommended that make files NOT be used. Rather, +# put the individual commands directly into this file. That way, +# it is possible to use command line arguments and other shell tech- +# niques to find the compiler, etc on different systems. For example, +# a different path could be used depending on whether this were a +# Solaris or Win32 machine, which is more difficult (if even possible) +# in a make file. + + +# Beginning of subroutines: +status=1 + +#Call this from anywhere to fail the test with an error message +# usage: fail "reason why the test failed" +fail() + { echo "The test failed :-(" + echo "$*" 1>&2 + echo "exit status was $status" + exit $status + } #end of fail() + +#Call this from anywhere to pass the test with a message +# usage: pass "reason why the test passed if applicable" +pass() + { echo "The test passed!!!" + echo "$*" 1>&2 + exit 0 + } #end of pass() + +# end of subroutines + + +# The beginning of the script proper + +# Checking for proper OS +OS=`uname -s` +case "$OS" in + SunOS ) + VAR="One value for Sun" + DEFAULT_JDK=/usr/local/java/jdk1.2/solaris + FILESEP="/" + PATHSEP=":" + TMP="/tmp" + ;; + + Linux ) + VAR="A different value for Linux" + DEFAULT_JDK=/usr/local/java/jdk1.4/linux-i386 + FILESEP="/" + PATHSEP=":" + TMP="/tmp" + ;; + + Windows_95 | Windows_98 | Windows_NT | Windows_ME ) + VAR="A different value for Win32" + DEFAULT_JDK=/usr/local/java/jdk1.2/win32 + FILESEP="\\" + PATHSEP=";" + TMP=`cd "${SystemRoot}/Temp"; echo ${PWD}` + ;; + + # catch all other OSs + * ) + echo "Unrecognized system! $OS" + fail "Unrecognized system! $OS" + ;; +esac + +# Want this test to run standalone as well as in the harness, so do the +# following to copy the test's directory into the harness's scratch directory +# and set all appropriate variables: + +if [ -z "${TESTJAVA}" ] ; then + # TESTJAVA is not set, so the test is running stand-alone. + # TESTJAVA holds the path to the root directory of the build of the JDK + # to be tested. That is, any java files run explicitly in this shell + # should use TESTJAVA in the path to the java interpreter. + # So, we'll set this to the JDK spec'd on the command line. If none + # is given on the command line, tell the user that and use a cheesy + # default. + # THIS IS THE JDK BEING TESTED. + if [ -n "$1" ] ; + then TESTJAVA=$1 + else echo "no JDK specified on command line so using default!" + TESTJAVA=$DEFAULT_JDK + fi + TESTSRC=. + TESTCLASSES=. + STANDALONE=1; +fi +echo "JDK under test is: $TESTJAVA" + + +############### YOUR TEST CODE HERE!!!!!!! ############# + +#All files required for the test should be in the same directory with +# this file. If converting a standalone test to run with the harness, +# as long as all files are in the same directory and it returns 0 for +# pass, you should be able to cut and paste it into here and it will +# run with the test harness. + +# This is an example of running something -- test +# The stuff below catches the exit status of test then passes or fails +# this shell test as appropriate ( 0 status is considered a pass here ) + +echo "Create TestApp.jar..." + +if [ -f TestApp.jar ] ; then + rm -f TestApp.jar +fi + +${TESTJAVA}/bin/jar -cvf TestApp.jar -C ${TESTCLASSES} testapp + +if [ $? -ne "0" ] ; then + fail "Failed to create TestApp.jar" +fi + +echo "Create Test.jar..." +if [ -f Test.jar ] ; then + rm -f Test.jar +fi + +${TESTJAVA}/bin/jar -cvf Test.jar -C ${TESTCLASSES} test + +if [ $? -ne 0 ] ; then + fail "Failed to create Test.jar" +fi + +# Prepare temp dir for cahce files +mkdir ./tmp +if [ $? -ne 0 ] ; then + fail "Unable to create temp directory." +fi + +# Verify that all classoladers are destroyed +${TESTJAVA}/bin/java -cp Test.jar test.Main +if [ $? -ne 0 ] ; then + fail "Test FAILED: some classloaders weren't destroyed." +fi + + +# Verify that ImageIO shutdown hook works correcly +${TESTJAVA}/bin/java -cp Test.jar -DforgetSomeStreams=true test.Main +if [ $? -ne 0 ] ; then + fail "Test FAILED: some classloaders weren't destroyed of shutdown hook failed." +fi + +# sanity check: verify that all cache files were deleted +cache_files=`ls tmp` + +if [ "x${cache_files}" != "x" ] ; then + echo "WARNING: some cache files was not deleted: ${cache_files}" +fi + +echo "Test done." + +status=$? + +if [ $status -eq "0" ] ; then + pass "" +else + fail "Test failed due to test plugin was not found." +fi + diff --git a/jdk/test/javax/imageio/stream/StreamCloserLeak/test/Main.java b/jdk/test/javax/imageio/stream/StreamCloserLeak/test/Main.java new file mode 100644 index 00000000000..b87299967c6 --- /dev/null +++ b/jdk/test/javax/imageio/stream/StreamCloserLeak/test/Main.java @@ -0,0 +1,284 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package test; + +import java.io.File; +import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map.Entry; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import javax.imageio.stream.ImageInputStream; +import sun.awt.AppContext; +import sun.awt.SunToolkit; + +public class Main { + + private static ThreadGroup appsThreadGroup; + + private static WeakHashMap<MyClassLoader, String> refs = + new WeakHashMap<MyClassLoader, String>(); + + /** Collection to simulate forgrotten streams **/ + private static HashMap<String, ImageInputStream> strongRefs = + new HashMap<String, ImageInputStream>(); + + private static ConcurrentLinkedQueue<Throwable> problems = + new ConcurrentLinkedQueue<Throwable>(); + + private static AppContext mainAppContext = null; + + private static CountDownLatch doneSignal; + + private static final int gcTimeout = + Integer.getInteger("gcTimeout", 10).intValue(); + + private static boolean forgetSomeStreams = + Boolean.getBoolean("forgetSomeStreams"); + + public static void main(String[] args) throws IOException { + mainAppContext = SunToolkit.createNewAppContext(); + System.out.println("Current context class loader: " + + Thread.currentThread().getContextClassLoader()); + + appsThreadGroup = new ThreadGroup("MyAppsThreadGroup"); + + File jar = new File("TestApp.jar"); + if (!jar.exists()) { + System.out.println(jar.getAbsolutePath() + " was not found!\n" + + "Please install the jar with test application correctly!"); + throw new RuntimeException("Test failed: no TestApp.jar"); + } + + URL[] urls = new URL[]{jar.toURL()}; + + int numApps = Integer.getInteger("numApps", 20).intValue(); + + doneSignal = new CountDownLatch(numApps); + int cnt = 0; + while (cnt++ < numApps) { + launch(urls, "testapp.Main", "launch"); + + checkErrors(); + } + + System.out.println("Wait for apps completion...."); + + try { + doneSignal.await(); + } catch (InterruptedException e) { + } + + System.out.println("All apps finished."); + + System.gc(); + + System.out.flush(); + + System.out.println("Enumerate strong refs:"); + for (String is : strongRefs.keySet()) { + System.out.println("-> " + is); + } + + System.out.println("======================="); + + // wait few seconds + waitAndGC(gcTimeout); + + doneSignal = new CountDownLatch(1); + + Runnable workaround = new Runnable() { + + public void run() { + AppContext ctx = null; + try { + ctx = SunToolkit.createNewAppContext(); + } catch (Throwable e) { + // ignore... + } finally { + doneSignal.countDown(); + } + } + }; + + Thread wt = new Thread(appsThreadGroup, workaround, "Workaround"); + wt.setContextClassLoader(new MyClassLoader(urls, "workaround")); + wt.start(); + wt = null; + workaround = null; + + System.out.println("Wait for workaround completion..."); + + try { + doneSignal.await(); + } catch (InterruptedException e) { + } + + // give a chance to GC + waitAndGC(gcTimeout); + + if (!refs.isEmpty()) { + System.out.println("Classloaders still alive:"); + + for (MyClassLoader l : refs.keySet()) { + String val = refs.get(l); + + if (val == null) { + throw new RuntimeException("Test FAILED: Invalid classloader name"); + } + System.out.println("->" + val + (strongRefs.get(val) != null ? + " (has strong ref)" : "")); + if (strongRefs.get(val) == null) { + throw new RuntimeException("Test FAILED: exta class loader is detected! "); + } + } + } else { + System.out.println("No alive class loaders!!"); + } + System.out.println("Test PASSED."); + } + + private static void waitAndGC(int sec) { + int cnt = sec; + System.out.print("Wait "); + while (cnt-- > 0) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + // do GC every 3 seconds + if (cnt % 3 == 2) { + System.gc(); + System.out.print("+"); + } else { + System.out.print("."); + } + checkErrors(); + } + System.out.println(""); + } + + private static void checkErrors() { + while (!problems.isEmpty()) { + Throwable theProblem = problems.poll(); + System.out.println("Test FAILED!"); + do { + theProblem.printStackTrace(System.out); + theProblem = theProblem.getCause(); + } while (theProblem != null); + throw new RuntimeException("Test FAILED"); + } + } + static int counter = 0; + + private static void launch(URL[] urls, final String className, + final String methodName) + { + final String uniqClassName = "testapp/Uniq" + counter; + final boolean saveStrongRef = forgetSomeStreams ? (counter % 5 == 4) : false; + + System.out.printf("%s: launch the app\n", uniqClassName); + Runnable launchIt = new Runnable() { + public void run() { + AppContext ctx = SunToolkit.createNewAppContext(); + + try { + Class appMain = + ctx.getContextClassLoader().loadClass(className); + Method launch = appMain.getDeclaredMethod(methodName, + strongRefs.getClass()); + + Constructor c = appMain.getConstructor(String.class, + problems.getClass()); + + Object o = c.newInstance(uniqClassName, problems); + + if (saveStrongRef) { + System.out.printf("%s: force strong ref\n", + uniqClassName); + launch.invoke(o, strongRefs); + } else { + HashMap<String, ImageInputStream> empty = null; + launch.invoke(o, empty); + } + + ctx = null; + } catch (Throwable e) { + problems.add(e); + } finally { + doneSignal.countDown(); + } + } + }; + + MyClassLoader appClassLoader = new MyClassLoader(urls, uniqClassName); + + refs.put(appClassLoader, uniqClassName); + + Thread appThread = new Thread(appsThreadGroup, launchIt, + "AppThread" + counter++); + appThread.setContextClassLoader(appClassLoader); + + appThread.start(); + launchIt = null; + appThread = null; + appClassLoader = null; + } + + private static class MyClassLoader extends URLClassLoader { + + private static boolean verbose = + Boolean.getBoolean("verboseClassLoading"); + private String uniqClassName; + + public MyClassLoader(URL[] urls, String uniq) { + super(urls); + + uniqClassName = uniq; + } + + public Class loadClass(String name) throws ClassNotFoundException { + if (verbose) { + System.out.printf("%s: load class %s\n", uniqClassName, name); + } + if (uniqClassName.equals(name)) { + return Object.class; + } + return super.loadClass(name); + } + + public String toString() { + return "MyClassLoader(" + uniqClassName + ")"; + } + } +} diff --git a/jdk/test/javax/imageio/stream/StreamCloserLeak/testapp/Main.java b/jdk/test/javax/imageio/stream/StreamCloserLeak/testapp/Main.java new file mode 100644 index 00000000000..3c4bb5ec3ff --- /dev/null +++ b/jdk/test/javax/imageio/stream/StreamCloserLeak/testapp/Main.java @@ -0,0 +1,109 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package testapp; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import javax.imageio.stream.FileCacheImageInputStream; +import javax.imageio.stream.ImageInputStream; + +public class Main { + + public static void main(String[] args) { + Main o = new Main("testapp.some.class", null); + o.launch(null); + } + + private final String uniqClassName; + private final ConcurrentLinkedQueue<Throwable> problems; + + public Main(String uniq, ConcurrentLinkedQueue<Throwable> p) { + uniqClassName = uniq; + problems = p; + } + + public void launch(HashMap<String, ImageInputStream> refs) { + System.out.printf("%s: current context class loader: %s\n", + uniqClassName, + Thread.currentThread().getContextClassLoader()); + try { + byte[] data = new byte[1024]; + ByteArrayInputStream bais = new ByteArrayInputStream(data); + MyImageInputStream iis = new MyImageInputStream(bais, + uniqClassName, + problems); + if (refs != null) { + System.out.printf("%s: added to strong store\n", + uniqClassName); + refs.put(uniqClassName, iis); + } + iis.read(); + //leave stream open : let's shutdown hook work! + } catch (IOException e) { + problems.add(e); + } + } + + private static class MyImageInputStream extends FileCacheImageInputStream { + private final String uniqClassName; + private ConcurrentLinkedQueue<Throwable> problems; + public MyImageInputStream(InputStream is, String uniq, + ConcurrentLinkedQueue<Throwable> p) throws IOException + { + super(is, new File("tmp")); + uniqClassName = uniq; + problems = p; + } + + @Override + public void close() throws IOException { + Test t = new Test(); + try { + t.doTest(uniqClassName); + } catch (Throwable e) { + problems.add(e); + } + + super.close(); + + problems = null; + } + } +} + +class Test { + public void doTest(String uniqClassName) throws ClassNotFoundException { + System.out.printf("%s: Current thread: %s\n", uniqClassName, + Thread.currentThread()); + + ClassLoader thisCL = this.getClass().getClassLoader(); + Class uniq = thisCL.loadClass(uniqClassName); + + System.out.printf("%s: test is done!\n",uniqClassName); + } +} diff --git a/jdk/test/javax/script/Test3.java b/jdk/test/javax/script/Test3.java index 8aa876ba24a..66fa23af07a 100644 --- a/jdk/test/javax/script/Test3.java +++ b/jdk/test/javax/script/Test3.java @@ -4,7 +4,6 @@ * * 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 diff --git a/jdk/test/javax/swing/JFileChooser/6570445/bug6570445.java b/jdk/test/javax/swing/JFileChooser/6570445/bug6570445.java new file mode 100644 index 00000000000..f746edaee54 --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6570445/bug6570445.java @@ -0,0 +1,20 @@ +/* + * @test + * @bug 6570445 + * @summary Checks if Win32ShellFolder2's COM-using methods work under a security manager + * @author Leonid Popov + */ + +import javax.swing.filechooser.FileSystemView; + +public class bug6570445 { + public static void main(String[] args) { + System.setSecurityManager(new SecurityManager()); + + // The next line of code forces FileSystemView to request data from Win32ShellFolder2, + // what causes an exception if a security manager installed (see the bug 6570445 description) + FileSystemView.getFileSystemView().getRoots(); + + System.out.println("Passed."); + } +} diff --git a/jdk/test/javax/swing/JFileChooser/6738668/bug6738668.java b/jdk/test/javax/swing/JFileChooser/6738668/bug6738668.java new file mode 100644 index 00000000000..f54515e7e4e --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6738668/bug6738668.java @@ -0,0 +1,44 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6738668 + @summary JFileChooser cannot be created under SecurityManager + @author Pavel Porvatov + @run main/othervm/policy=security.policy bug6738668 +*/ + +import javax.swing.*; +import java.io.File; + +public class bug6738668 { + public static void main(String[] args) throws Exception { + for (UIManager.LookAndFeelInfo lookAndFeelInfo : UIManager.getInstalledLookAndFeels()) { + UIManager.setLookAndFeel(lookAndFeelInfo.getClassName()); + + new JFileChooser(new File("c:/temp")); + + System.out.println("Test passed for LookAndFeel " + lookAndFeelInfo.getClassName()); + } + } +} diff --git a/jdk/test/javax/swing/JFileChooser/6738668/security.policy b/jdk/test/javax/swing/JFileChooser/6738668/security.policy new file mode 100644 index 00000000000..fd3aa757c56 --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6738668/security.policy @@ -0,0 +1,5 @@ +grant { + permission java.io.FilePermission "C:\\temp\\*", "read"; + permission java.io.FilePermission "C:\\temp", "read"; + permission java.util.PropertyPermission "*", "read"; +}; diff --git a/jdk/test/javax/swing/JFileChooser/6798062/bug6798062.html b/jdk/test/javax/swing/JFileChooser/6798062/bug6798062.html new file mode 100644 index 00000000000..12955f6eee7 --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6798062/bug6798062.html @@ -0,0 +1,11 @@ +<html> +<body> +<applet code="bug6798062.class" width=400 height=300></applet> +1. Create a link +2. Copy path to the link into TextField +3. Run the Windows Task Manager. Select the Processes tab and find the java process +4. Press the Start button in the test window +5. Wait several minutes and observe in the Windows Task Manager +that Memory Usage of java process is not increasing +</body> +</html> diff --git a/jdk/test/javax/swing/JFileChooser/6798062/bug6798062.java b/jdk/test/javax/swing/JFileChooser/6798062/bug6798062.java new file mode 100644 index 00000000000..ee4d333fc85 --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6798062/bug6798062.java @@ -0,0 +1,189 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test %W% %E% + @bug 6798062 + @summary Memory Leak on using getFiles of FileSystemView + @author Pavel Porvatov + @run applet/manual=done bug6798062.html +*/ + +import sun.awt.shell.ShellFolder; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.*; +import java.io.File; +import java.io.FileNotFoundException; + +public class bug6798062 extends JApplet { + + private final JSlider slider = new JSlider(0, 100); + + private final JTextField tfLink = new JTextField(); + + private final JButton btnStart = new JButton("Start"); + + private final JButton btnStop = new JButton("Stop"); + + private final JButton btnGC = new JButton("Run System.gc()"); + + private ShellFolder folder; + + private Thread thread; + + public static void main(String[] args) { + JFrame frame = new JFrame("bug6798062"); + + frame.setSize(400, 300); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.add(new bug6798062().initialize()); + + frame.setVisible(true); + } + + public void init() { + add(initialize()); + } + + private JPanel initialize() { + File file = new File("c:/"); + + try { + folder = ShellFolder.getShellFolder(file); + } catch (FileNotFoundException e) { + fail("Directory " + file.getPath() + " not found"); + } + + slider.setMajorTickSpacing(10); + slider.setPaintTicks(true); + slider.setPaintLabels(true); + slider.setSnapToTicks(true); + slider.setValue(10); + + btnStart.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + setEnabledState(false); + + thread = new MyThread(slider.getValue(), tfLink.getText()); + thread.start(); + } + }); + + btnStop.setEnabled(false); + + btnStop.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + thread.interrupt(); + thread = null; + + setEnabledState(true); + } + }); + + btnGC.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.gc(); + } + }); + + setEnabledState(true); + + JPanel pnButtons = new JPanel(); + + pnButtons.setLayout(new BoxLayout(pnButtons, BoxLayout.X_AXIS)); + + pnButtons.add(btnStart); + pnButtons.add(btnStop); + pnButtons.add(btnGC); + + tfLink.setMaximumSize(new Dimension(300, 20)); + + JPanel pnContent = new JPanel(); + + pnContent.setLayout(new BoxLayout(pnContent, BoxLayout.Y_AXIS)); + pnContent.add(new JLabel("Delay between listFiles() invocation (ms):")); + pnContent.add(slider); + pnContent.add(new JLabel("Provide link here:")); + pnContent.add(tfLink); + pnContent.add(pnButtons); + + return pnContent; + } + + private void setEnabledState(boolean enabled) { + slider.setEnabled(enabled); + btnStart.setEnabled(enabled); + btnStop.setEnabled(!enabled); + } + + private static void fail(String msg) { + throw new RuntimeException(msg); + } + + private class MyThread extends Thread { + private final int delay; + + private final ShellFolder link; + + private MyThread(int delay, String link) { + this.delay = delay; + + ShellFolder linkFolder; + + try { + linkFolder = ShellFolder.getShellFolder(new File(link)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + + linkFolder = null; + } + + this.link = linkFolder; + } + + public void run() { + while (!isInterrupted()) { + folder.listFiles(); + if (link != null) { + try { + link.getLinkLocation(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + if (delay > 0) { + try { + Thread.sleep(delay); + } catch (InterruptedException e1) { + // The thread was interrupted + return; + } + } + } + } + } +} diff --git a/jdk/test/javax/swing/JSlider/6794831/bug6794831.java b/jdk/test/javax/swing/JSlider/6794831/bug6794831.java new file mode 100644 index 00000000000..a147987d417 --- /dev/null +++ b/jdk/test/javax/swing/JSlider/6794831/bug6794831.java @@ -0,0 +1,105 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6794831 + * @summary Infinite loop while painting ticks on Slider with maximum=MAX_INT + * @author Pavel Porvatov + @run main bug6794831 + */ + +import javax.swing.*; +import javax.swing.plaf.basic.BasicSliderUI; +import java.awt.image.BufferedImage; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class bug6794831 { + private final CountDownLatch countDownLatch = new CountDownLatch(1); + + public static void main(String args[]) throws InterruptedException { + new bug6794831().run(); + } + + private void run() throws InterruptedException { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + for (UIManager.LookAndFeelInfo lookAndFeelInfo : UIManager.getInstalledLookAndFeels()) { + try { + UIManager.setLookAndFeel(lookAndFeelInfo.getClassName()); + } catch (Exception e) { + fail(e.getMessage()); + } + + BufferedImage image = new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB); + + // Test 1 + JSlider slider = new JSlider(0, Integer.MAX_VALUE - 1, 0); + + slider.setMajorTickSpacing((Integer.MAX_VALUE - 1) / 4); + slider.setPaintTicks(true); + + ((BasicSliderUI) slider.getUI()).paintTicks(image.getGraphics()); + + // Test 2 + slider = new JSlider(0, Integer.MAX_VALUE - 1, 0); + + slider.setMinorTickSpacing((Integer.MAX_VALUE - 1) / 4); + slider.setPaintTicks(true); + + ((BasicSliderUI) slider.getUI()).paintTicks(image.getGraphics()); + + // Test 3 + slider = new JSlider(0, Integer.MAX_VALUE - 1, 0); + + slider.setOrientation(JSlider.VERTICAL); + slider.setMajorTickSpacing((Integer.MAX_VALUE - 1) / 4); + slider.setPaintTicks(true); + + ((BasicSliderUI) slider.getUI()).paintTicks(image.getGraphics()); + + // Test 4 + slider = new JSlider(0, Integer.MAX_VALUE - 1, 0); + + slider.setOrientation(JSlider.VERTICAL); + slider.setMinorTickSpacing((Integer.MAX_VALUE - 1) / 4); + slider.setPaintTicks(true); + + ((BasicSliderUI) slider.getUI()).paintTicks(image.getGraphics()); + + countDownLatch.countDown(); + } + } + }); + + if (countDownLatch.await(3000, TimeUnit.MILLISECONDS)) { + System.out.println("bug6794831 passed"); + } else { + fail("bug6794831 failed"); + } + } + + private static void fail(String msg) { + throw new RuntimeException(msg); + } +} diff --git a/jdk/test/javax/swing/system/6799345/TestShutdown.java b/jdk/test/javax/swing/system/6799345/TestShutdown.java new file mode 100644 index 00000000000..694df3eac01 --- /dev/null +++ b/jdk/test/javax/swing/system/6799345/TestShutdown.java @@ -0,0 +1,203 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6799345 + @summary Tests that no exceptions are thrown from TimerQueue and +SwingWorker on AppContext shutdown + @author art + @run main TestShutdown +*/ + +import java.awt.*; +import java.awt.event.*; + +import java.util.*; + +import javax.swing.*; + +import sun.awt.*; + +public class TestShutdown +{ + private static AppContext targetAppContext; + + private static JFrame f; + private static JTextField tf; + + private static volatile boolean exceptionsOccurred = false; + private static volatile boolean appcontextInitDone = false; + + private static int timerValue = 0; + + public static void main(String[] args) + throws Exception + { + ThreadGroup tg = new TestThreadGroup("TTG"); + Thread t = new Thread(tg, new TestRunnable(), "InitThread"); + t.start(); + + while (!appcontextInitDone) + { + Thread.sleep(500); + } + + targetAppContext.dispose(); + + if (exceptionsOccurred) + { + throw new RuntimeException("Test FAILED: some exceptions occurred"); + } + } + + static void initGUI() + { + f = new JFrame("F"); + f.setBounds(100, 100, 200, 100); + tf = new JTextField("Test"); + f.add(tf); + f.setVisible(true); + } + + static void startGUI() + { + // caret blink Timer + tf.requestFocusInWindow(); + + // misc Timer + ActionListener al = new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + System.out.println("Timer tick: " + timerValue++); + } + }; + new javax.swing.Timer(30, al).start(); + } + + static class TestThreadGroup extends ThreadGroup + { + public TestThreadGroup(String name) + { + super(name); + } + + @Override + public synchronized void uncaughtException(Thread thread, Throwable t) + { + if (t instanceof ThreadDeath) + { + // this one is expected, rethrow + throw (ThreadDeath)t; + } + System.err.println("Test FAILED: an exception is caught in the " + + "target thread group on thread " + thread.getName()); + t.printStackTrace(System.err); + exceptionsOccurred = true; + } + } + + static class TestRunnable implements Runnable + { + @Override + public void run() + { + SunToolkit stk = (SunToolkit)Toolkit.getDefaultToolkit(); + targetAppContext = stk.createNewAppContext(); + + // create and show frame and text field + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + initGUI(); + } + }); + stk.realSync(); + + // start some Timers + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + startGUI(); + } + }); + stk.realSync(); + + // start multiple SwingWorkers + while (!Thread.interrupted()) + { + try + { + new TestSwingWorker().execute(); + Thread.sleep(40); + } + catch (Exception e) + { + // exception here is expected, skip + break; + } + } + } + } + + static class TestSwingWorker extends SwingWorker<String, Integer> + { + @Override + public String doInBackground() + { + Random r = new Random(); + for (int i = 0; i < 10; i++) + { + try + { + int delay = r.nextInt() % 50; + Thread.sleep(delay); + publish(delay); + } + catch (Exception z) + { + break; + } + } + if (!appcontextInitDone) + { + appcontextInitDone = true; + } + return "Done"; + } + + @Override + public void process(java.util.List<Integer> chunks) + { + for (Integer i : chunks) + { + System.err.println("Processed: " + i); + } + } + } +} diff --git a/jdk/test/javax/swing/text/LayoutQueue/Test6588003.java b/jdk/test/javax/swing/text/LayoutQueue/Test6588003.java new file mode 100644 index 00000000000..d14d6a56a95 --- /dev/null +++ b/jdk/test/javax/swing/text/LayoutQueue/Test6588003.java @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6588003 + @summary LayoutQueue should not share its DefaultQueue across AppContexts + @author Peter Zhelezniakov + @run main Test6588003 +*/ + +import javax.swing.text.LayoutQueue; +import sun.awt.SunToolkit; + +public class Test6588003 implements Runnable { + private static final LayoutQueue DEFAULT = new LayoutQueue(); + + public static void main(String[] args) throws InterruptedException { + LayoutQueue.setDefaultQueue(DEFAULT); + + ThreadGroup group = new ThreadGroup("Test6588003"); + Thread thread = new Thread(group, new Test6588003()); + thread.start(); + thread.join(); + + if (LayoutQueue.getDefaultQueue() != DEFAULT) { + throw new RuntimeException("Sharing detected"); + } + } + + public void run() { + SunToolkit.createNewAppContext(); + + if (LayoutQueue.getDefaultQueue() == DEFAULT) { + throw new RuntimeException("Sharing detected"); + } + + LayoutQueue.setDefaultQueue(new LayoutQueue()); + } +} diff --git a/jdk/test/javax/swing/text/html/Test4783068.java b/jdk/test/javax/swing/text/html/Test4783068.java new file mode 100644 index 00000000000..08859788e05 --- /dev/null +++ b/jdk/test/javax/swing/text/html/Test4783068.java @@ -0,0 +1,93 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 4783068 + @summary Disabled components should render grayed-out HTML + @author Peter Zhelezniakov + @run main Test4783068 +*/ + +import java.awt.*; +import java.awt.image.BufferedImage; +import javax.swing.*; +import javax.swing.plaf.metal.MetalLookAndFeel; + +public class Test4783068 { + final static Color TEST_COLOR = Color.WHITE; + + final static String html = "<html>" + + "This is a <font color='red'>colored</font> <b>text</b>" + + "<p>with a <a href='http://ru.sun.com'>link</a>" + + "<ul><li>an unordered<li>list</ul>" + + "<ol><li>and an ordered<li>list</ol>" + + "</html>"; + + + void test() { + try { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + } catch (UnsupportedLookAndFeelException e) { + throw new Error("Cannot set Metal LAF"); + } + // Render text using background color + UIManager.put("textInactiveText", TEST_COLOR); + + test(new JLabel(html)); + test(new JButton(html)); + + JEditorPane pane = new JEditorPane("text/html", html); + pane.setDisabledTextColor(TEST_COLOR); + test(pane); + } + + void test(JComponent c) { + c.setEnabled(false); + c.setOpaque(true); + c.setBackground(TEST_COLOR); + c.setBorder(null); + Dimension size = c.getPreferredSize(); + c.setBounds(0, 0, size.width, size.height); + + BufferedImage image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB); + c.paint(image.getGraphics()); + + int rgb = TEST_COLOR.getRGB(); + for (int i = 0; i < size.height; i++) { + for (int j = 0; j < size.width; j++) { + if (image.getRGB(j, i) != rgb) { + throw new RuntimeException( + String.format("Color mismatch at [%d, %d]", j, i)); + } + } + } + } + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override public void run() { + new Test4783068().test(); + } + }); + } +} diff --git a/jdk/test/sun/awt/image/DrawByteBinary.java b/jdk/test/sun/awt/image/DrawByteBinary.java new file mode 100644 index 00000000000..e9db5c63f23 --- /dev/null +++ b/jdk/test/sun/awt/image/DrawByteBinary.java @@ -0,0 +1,75 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6800846 + * + * @summary Test verifes that images with short palette are rendered + * withourt artifacts. + * + * @run main DrawByteBinary + */ + + +import java.awt.*; +import java.awt.color.*; +import java.awt.image.*; +import static java.awt.image.BufferedImage.*; + + +public class DrawByteBinary { + + public static void main(String args[]) { + int w = 100, h = 30; + int x = 10; + byte[] arr = {(byte)0xff, (byte)0x0, (byte)0x00}; + + IndexColorModel newCM = new IndexColorModel(1, 2, arr, arr, arr); + BufferedImage orig = new BufferedImage(w, h, TYPE_BYTE_BINARY, newCM); + Graphics2D g2d = orig.createGraphics(); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, w, h); + g2d.setColor(Color.black); + g2d.drawLine(x, 0, x, h); + g2d.dispose(); + + IndexColorModel origCM = (IndexColorModel)orig.getColorModel(); + BufferedImage test = new BufferedImage(w, h, TYPE_BYTE_BINARY,origCM); + g2d = test.createGraphics(); + g2d.drawImage(orig, 0, 0, null); + g2d.dispose(); + + int y = h / 2; + + // we expect white color outside the line + if (test.getRGB(x - 1, y) != 0xffffffff) { + throw new RuntimeException("Invalid color outside the line."); + } + + // we expect black color on the line + if (test.getRGB(x, y) != 0xff000000) { + throw new RuntimeException("Invalid color on the line."); + } + } +} diff --git a/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java b/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java new file mode 100644 index 00000000000..dc54d94ab45 --- /dev/null +++ b/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java @@ -0,0 +1,120 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6476665 6523403 6733501 + * @summary Verifies reading and writing profiles and tags of the standard color + * spaces + * @run main ReadWriteProfileTest + */ +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.util.*; +import java.nio.*; +import java.util.Hashtable; + +public class ReadWriteProfileTest implements Runnable { + /* Location of the tag sig counter in 4-byte words */ + final static int TAG_COUNT_OFFSET = 32; + + /* Location of the tag sig table in 4-byte words */ + final static int TAG_ELEM_OFFSET = 33; + + static byte[][] profiles; + static int [][] tagSigs; + static Hashtable<Integer,byte[]> [] tags; + + static int [] cspaces = {ColorSpace.CS_sRGB, ColorSpace.CS_PYCC, + ColorSpace.CS_LINEAR_RGB, ColorSpace.CS_CIEXYZ, + ColorSpace.CS_GRAY}; + + static String [] csNames = {"sRGB", "PYCC", "LINEAR_RGB", "CIEXYZ", "GRAY"}; + + static void getProfileTags(byte [] data, Hashtable tags) { + ByteBuffer byteBuf = ByteBuffer.wrap(data); + IntBuffer intBuf = byteBuf.asIntBuffer(); + int tagCount = intBuf.get(TAG_COUNT_OFFSET); + intBuf.position(TAG_ELEM_OFFSET); + for (int i = 0; i < tagCount; i++) { + int tagSig = intBuf.get(); + int tagDataOff = intBuf.get(); + int tagSize = intBuf.get(); + + byte [] tagData = new byte[tagSize]; + byteBuf.position(tagDataOff); + byteBuf.get(tagData); + tags.put(tagSig, tagData); + } + } + + static { + profiles = new byte[cspaces.length][]; + tags = new Hashtable[cspaces.length]; + + for (int i = 0; i < cspaces.length; i++) { + ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]); + profiles[i] = pf.getData(); + tags[i] = new Hashtable(); + getProfileTags(profiles[i], tags[i]); + } + } + + public void run() { + for (int i = 0; i < cspaces.length; i++) { + ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]); + byte [] data = pf.getData(); + pf = ICC_Profile.getInstance(data); + if (!Arrays.equals(data, profiles[i])) { + System.err.println("Incorrect result of getData() " + "with " + + csNames[i] + " profile"); + throw new RuntimeException("Incorrect result of getData()"); + } + + for (int tagSig : tags[i].keySet()) { + byte [] tagData = pf.getData(tagSig); + byte [] empty = new byte[tagData.length]; + pf.setData(tagSig, empty); + pf.setData(tagSig, tagData); + + byte [] tagData1 = pf.getData(tagSig); + + if (!Arrays.equals(tagData1, tags[i].get(tagSig))) + { + System.err.println("Incorrect result of getData(int) with" + + " tag " + + Integer.toHexString(tagSig) + + " of " + csNames[i] + " profile"); + + throw new RuntimeException("Incorrect result of " + + "getData(int)"); + } + } + } + } + + public static void main(String [] args) { + ReadWriteProfileTest test = new ReadWriteProfileTest(); + test.run(); + } +} diff --git a/jdk/test/sun/net/sdp/ProbeIB.java b/jdk/test/sun/net/sdp/ProbeIB.java new file mode 100644 index 00000000000..ac2a4b72d74 --- /dev/null +++ b/jdk/test/sun/net/sdp/ProbeIB.java @@ -0,0 +1,59 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.File; +import java.io.IOException; +import java.net.NetworkInterface; +import java.net.InetAddress; +import java.util.Scanner; +import java.util.Enumeration; + +/** + * Probes for InfiniBand devices plumbed with IP addresses. + */ + +public class ProbeIB { + public static void main(String[] args) throws IOException { + Scanner s = new Scanner(new File("/etc/path_to_inst")); + try { + while (s.hasNextLine()) { + String line = s.nextLine(); + if (line.startsWith("#")) + continue; + String[] fields = line.split("\\s+"); + if (!fields[2].equals("\"ibd\"")) + continue; + String name = fields[2].substring(1, fields[2].length()-1) + fields[1]; + NetworkInterface ni = NetworkInterface.getByName(name); + if (ni != null) { + Enumeration<InetAddress> addrs = ni.getInetAddresses(); + while (addrs.hasMoreElements()) { + System.out.println(addrs.nextElement().getHostAddress()); + } + } + } + } finally { + s.close(); + } + } +} diff --git a/jdk/test/sun/net/sdp/Sanity.java b/jdk/test/sun/net/sdp/Sanity.java new file mode 100644 index 00000000000..2c8d55e00af --- /dev/null +++ b/jdk/test/sun/net/sdp/Sanity.java @@ -0,0 +1,168 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Enumeration; + +/** + * Sanity check Socket/ServerSocket and each of the stream-oriented channels + * on each IP address plumbed to the network adapters. + */ + +public class Sanity { + public static void main(String[] args) throws Exception { + Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces(); + while (nifs.hasMoreElements()) { + NetworkInterface ni = nifs.nextElement(); + Enumeration<InetAddress> addrs = ni.getInetAddresses(); + while (addrs.hasMoreElements()) { + InetAddress addr = addrs.nextElement(); + test(addr); + } + } + } + + static void test(InetAddress addr) throws Exception { + System.out.println(addr.getHostAddress()); + + // ServerSocketChannel.bind + ServerSocketChannel ssc = ServerSocketChannel.open(); + try { + ssc.bind(new InetSocketAddress(addr, 0)); + int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort(); + + // SocketChannel.connect (implicit bind) + SocketChannel client = SocketChannel.open(); + try { + client.connect(new InetSocketAddress(addr, port)); + SocketChannel peer = ssc.accept(); + try { + testConnection(Channels.newOutputStream(client), + Channels.newInputStream(peer)); + } finally { + peer.close(); + } + } finally { + client.close(); + } + + // SocketChannel.connect (explicit bind) + client = SocketChannel.open(); + try { + client.bind(new InetSocketAddress(addr, 0)) + .connect(new InetSocketAddress(addr, port)); + ssc.accept().close(); + } finally { + client.close(); + } + } finally { + ssc.close(); + } + + // AsynchronousServerSocketChannel.bind + AsynchronousServerSocketChannel server = + AsynchronousServerSocketChannel.open(); + try { + server.bind(new InetSocketAddress(addr, 0)); + int port = ((InetSocketAddress)(server.getLocalAddress())).getPort(); + + // AsynchronousSocketChannel.connect (implicit bind) + AsynchronousSocketChannel client = AsynchronousSocketChannel.open(); + try { + client.connect(new InetSocketAddress(addr, port)).get(); + AsynchronousSocketChannel peer = server.accept().get(); + try { + testConnection(Channels.newOutputStream(client), + Channels.newInputStream(peer)); + } finally { + peer.close(); + } + } finally { + client.close(); + } + + // AsynchronousSocketChannel.connect (explicit bind) + client = AsynchronousSocketChannel.open(); + try { + client.bind(new InetSocketAddress(addr, 0)) + .connect(new InetSocketAddress(addr, port)).get(); + server.accept().get().close(); + } finally { + client.close(); + } + } finally { + server.close(); + } + + // ServerSocket.bind + ServerSocket ss = new ServerSocket(); + try { + ss.bind(new InetSocketAddress(addr, 0)); + int port = ss.getLocalPort(); + + // Socket.connect (implicit bind) + Socket s = new Socket(); + try { + s.connect(new InetSocketAddress(addr, port)); + Socket peer = ss.accept(); + try { + testConnection(s.getOutputStream(), peer.getInputStream()); + } finally { + peer.close(); + } + } finally { + s.close(); + } + + // Socket.connect (explicit bind) + s = new Socket(); + try { + s.bind(new InetSocketAddress(addr, 0)); + s.connect(new InetSocketAddress(addr, port)); + ss.accept().close(); + } finally { + s.close(); + } + } finally { + ss.close(); + } + } + + static void testConnection(OutputStream out, InputStream in) + throws IOException + { + byte[] msg = "hello".getBytes(); + out.write(msg); + + byte[] ba = new byte[100]; + int nread = 0; + while (nread < msg.length) { + int n = in.read(ba); + if (n < 0) + throw new IOException("EOF not expected!"); + nread += n; + } + } +} diff --git a/jdk/test/sun/net/sdp/sanity.sh b/jdk/test/sun/net/sdp/sanity.sh new file mode 100644 index 00000000000..baca9feccef --- /dev/null +++ b/jdk/test/sun/net/sdp/sanity.sh @@ -0,0 +1,72 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 4890703 +# @summary Unit test for Solaris SDP support +# @build ProbeIB Sanity +# @run shell sanity.sh + +# Check we are on Solaris and that SDP is enabled +OS=`uname -s` +if [ "$OS" != "SunOS" ]; then + echo "This is a Solaris-only test" + exit 0 +fi +SDPADM=/usr/sbin/sdpadm +if [ ! -f ${SDPADM} ]; then + echo "SDP not available" + exit 0 +fi +${SDPADM} status|grep Enabled +if [ $? != 0 ]; then + echo "SDP not enabled" + exit 0 +fi + +if [ -z "$TESTJAVA" ]; then + JAVA=java + TESTCLASSES=. + TESTSRC=. +else + JAVA="${TESTJAVA}/bin/java" +fi + +CLASSPATH=${TESTCLASSES}:${TESTSRC} +export CLASSPATH + +# Probe for IP addresses plumbed to IB interfaces +$JAVA -Djava.net.preferIPv4Stack=true ProbeIB > ib_addrs + +# Create sdp.conf +SDPCONF=sdp.conf +rm ${SDPCONF} +touch ${SDPCONF} +cat ib_addrs | while read ADDR +do + echo "bind ${ADDR} *" > ${SDPCONF} + echo "connect ${ADDR} *" >> ${SDPCONF} +done + +# Sanity check +$JAVA -Djava.net.preferIPv4Stack=true -Dcom.sun.sdp.conf=${SDPCONF} -Dcom.sun.sdp.debug Sanity diff --git a/jdk/test/sun/nio/cs/FindEncoderBugs.java b/jdk/test/sun/nio/cs/FindEncoderBugs.java index 0f4c406d453..54bc5b268a0 100644 --- a/jdk/test/sun/nio/cs/FindEncoderBugs.java +++ b/jdk/test/sun/nio/cs/FindEncoderBugs.java @@ -526,4 +526,3 @@ public class FindEncoderBugs { System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} } - diff --git a/jdk/test/sun/nio/cs/StrCodingBenchmark.java b/jdk/test/sun/nio/cs/StrCodingBenchmark.java new file mode 100644 index 00000000000..73256eb2b43 --- /dev/null +++ b/jdk/test/sun/nio/cs/StrCodingBenchmark.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.util.*; +import java.nio.*; +import java.nio.charset.*; +import java.util.concurrent.*; +import java.util.regex.Pattern; + +/** + * Usage: java StringCodingBenchmark + * [-Diterations=N] [-Dsize=N] [-Dsubsize=N] [-Dmaxchar=N] + * [-Dfilter=REGEXP] [-DSecurityManager=true] + */ +public class StrCodingBenchmark { + abstract static class Job { + private final String name; + public Job(String name) { this.name = name; } + public String name() { return name; } + public abstract void work() throws Throwable; + } + + private static void collectAllGarbage() { + final java.util.concurrent.CountDownLatch drained + = new java.util.concurrent.CountDownLatch(1); + try { + System.gc(); // enqueue finalizable objects + new Object() { protected void finalize() { + drained.countDown(); }}; + System.gc(); // enqueue detector + drained.await(); // wait for finalizer queue to drain + System.gc(); // cleanup finalized objects + } catch (InterruptedException e) { throw new Error(e); } + } + + /** + * Runs each job for long enough that all the runtime compilers + * have had plenty of time to warm up, i.e. get around to + * compiling everything worth compiling. + * Returns array of average times per job per run. + */ + public static long[] time0(Job ... jobs) throws Throwable { + //final long warmupNanos = 10L * 1000L * 1000L * 1000L; + final long warmupNanos = 100L * 100L; + long[] nanoss = new long[jobs.length]; + for (int i = 0; i < jobs.length; i++) { + collectAllGarbage(); + long t0 = System.nanoTime(); + long t; + int j = 0; + do { jobs[i].work(); j++; } + while ((t = System.nanoTime() - t0) < warmupNanos); + nanoss[i] = t/j; + } + return nanoss; + } + + public static void time(Job ... jobs) throws Throwable { + + long[] warmup = time0(jobs); // Warm up run + long[] nanoss = time0(jobs); // Real timing run + long[] milliss = new long[jobs.length]; + double[] ratios = new double[jobs.length]; + + final String nameHeader = "Method"; + final String millisHeader = "Millis"; + final String ratioHeader = "Ratio"; + + int nameWidth = nameHeader.length(); + int millisWidth = millisHeader.length(); + int ratioWidth = ratioHeader.length(); + + for (int i = 0; i < jobs.length; i++) { + nameWidth = Math.max(nameWidth, jobs[i].name().length()); + + milliss[i] = nanoss[i]/(1000L * 1000L); + millisWidth = Math.max(millisWidth, + String.format("%d", milliss[i]).length()); + + ratios[i] = (double) nanoss[i] / (double) nanoss[0]; + ratioWidth = Math.max(ratioWidth, + String.format("%.3f", ratios[i]).length()); + } + String format = String.format("%%-%ds %%%dd %n", + nameWidth, millisWidth); + String headerFormat = String.format("%%-%ds %%%ds%n", + nameWidth, millisWidth); + System.out.printf(headerFormat, "Method", "Millis"); + + // Print out absolute and relative times, calibrated against first job + for (int i = 0; i < jobs.length; i++) + System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]); + } + + public static Job[] filter(Pattern filter, Job[] jobs) { + if (filter == null) return jobs; + Job[] newJobs = new Job[jobs.length]; + int n = 0; + for (Job job : jobs) + if (filter.matcher(job.name()).find()) + newJobs[n++] = job; + // Arrays.copyOf not available in JDK 5 + Job[] ret = new Job[n]; + System.arraycopy(newJobs, 0, ret, 0, n); + return ret; + } + + static class PermissiveSecurityManger extends SecurityManager { + @Override public void checkPermission(java.security.Permission p) { + } + } + + public static void main(String[] args) throws Throwable { + final int itrs = Integer.getInteger("iterations", 100000); + final int size = Integer.getInteger("size", 2048); + final int subsize = Integer.getInteger("subsize", 128); + final int maxchar = Integer.getInteger("maxchar", 128); + final String regex = System.getProperty("filter"); + final Pattern filter = (regex == null) ? null : Pattern.compile(regex); + final boolean useSecurityManager = Boolean.getBoolean("SecurityManager"); + if (useSecurityManager) + System.setSecurityManager(new PermissiveSecurityManger()); + final Random rnd = new Random(); + + for (Charset charset: Charset.availableCharsets().values()) { + if (!("ISO-8859-1".equals(charset.name()) || + "US-ASCII".equals(charset.name()) || + charset.newDecoder() instanceof sun.nio.cs.SingleByte.Decoder)) + continue; + final String csn = charset.name(); + final Charset cs = charset; + final StringBuilder sb = new StringBuilder(); + { + final CharsetEncoder enc = cs.newEncoder(); + for (int i = 0; i < size; ) { + char c = (char) rnd.nextInt(maxchar); + if (enc.canEncode(c)) { + sb.append(c); + i++; + } + } + } + final String string = sb.toString(); + final byte[] bytes = string.getBytes(cs); + + System.out.printf("%n--------%s---------%n", csn); + for (int sz = 4; sz <= 2048; sz *= 2) { + System.out.printf(" [len=%d]%n", sz); + final byte[] bs = Arrays.copyOf(bytes, sz); + final String str = new String(bs, csn); + Job[] jobs = { + new Job("String decode: csn") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + new String(bs, csn); + }}, + + new Job("String decode: cs") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + new String(bs, cs); + }}, + + new Job("String encode: csn") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + str.getBytes(csn); + }}, + + new Job("String encode: cs") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + str.getBytes(cs); + }}, + }; + time(filter(filter, jobs)); + } + } + } +} diff --git a/jdk/test/sun/nio/cs/TestStringCoding.java b/jdk/test/sun/nio/cs/TestStringCoding.java new file mode 100644 index 00000000000..8d0c8f94f24 --- /dev/null +++ b/jdk/test/sun/nio/cs/TestStringCoding.java @@ -0,0 +1,151 @@ +/* + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6636323 6636319 + @summary Test if StringCoding and NIO result have the same de/encoding result + * @run main/timeout=2000 TestStringCoding + */ + +import java.util.*; +import java.nio.*; +import java.nio.charset.*; + +public class TestStringCoding { + public static void main(String[] args) throws Throwable { + + for (Boolean hasSM: new boolean[] { false, true }) { + if (hasSM) + System.setSecurityManager(new PermissiveSecurityManger()); + for (Charset cs: Charset.availableCharsets().values()) { + if ("ISO-2022-CN".equals(cs.name()) || + "x-COMPOUND_TEXT".equals(cs.name()) || + "x-JISAutoDetect".equals(cs.name())) + continue; + System.out.printf("Testing(sm=%b) " + cs.name() + "....", hasSM); + // full bmp first + char[] bmpCA = new char[0x10000]; + for (int i = 0; i < 0x10000; i++) { + bmpCA[i] = (char)i; + } + byte[] sbBA = new byte[0x100]; + for (int i = 0; i < 0x100; i++) { + sbBA[i] = (byte)i; + } + test(cs, bmpCA, sbBA); + // "randomed" sizes + Random rnd = new Random(); + for (int i = 0; i < 10; i++) { + int clen = rnd.nextInt(0x10000); + int blen = rnd.nextInt(0x100); + //System.out.printf(" blen=%d, clen=%d%n", blen, clen); + test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen)); + //add a pair of surrogates + int pos = clen / 2; + if ((pos + 1) < blen) { + bmpCA[pos] = '\uD800'; + bmpCA[pos+1] = '\uDC00'; + } + test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen)); + } + System.out.println("done!"); + } + } + } + + static void test(Charset cs, char[] bmpCA, byte[] sbBA) throws Throwable { + String bmpStr = new String(bmpCA); + CharsetDecoder dec = cs.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + CharsetEncoder enc = cs.newEncoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + + //getBytes(csn); + byte[] baSC = bmpStr.getBytes(cs.name()); + ByteBuffer bf = enc.reset().encode(CharBuffer.wrap(bmpCA)); + byte[] baNIO = new byte[bf.limit()]; + bf.get(baNIO, 0, baNIO.length); + if (!Arrays.equals(baSC, baNIO)) + throw new RuntimeException("getBytes(csn) failed -> " + cs.name()); + + //getBytes(cs); + baSC = bmpStr.getBytes(cs); + if (!Arrays.equals(baSC, baNIO)) + throw new RuntimeException("getBytes(cs) failed -> " + cs.name()); + + //new String(csn); + String strSC = new String(sbBA, cs.name()); + String strNIO = dec.reset().decode(ByteBuffer.wrap(sbBA)).toString(); + if(!strNIO.equals(strSC)) + throw new RuntimeException("new String(csn) failed -> " + cs.name()); + + //new String(cs); + strSC = new String(sbBA, cs); + if (!strNIO.equals(strSC)) + throw new RuntimeException("new String(cs) failed -> " + cs.name()); + + //encode unmappable surrogates + if (enc instanceof sun.nio.cs.ArrayEncoder && + cs.contains(Charset.forName("ASCII"))) { + enc.replaceWith(new byte[] { (byte)'A'}); + sun.nio.cs.ArrayEncoder cae = (sun.nio.cs.ArrayEncoder)enc; + + String str = "ab\uD800\uDC00\uD800\uDC00cd"; + byte[] ba = new byte[str.length() - 2]; + int n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 6 || !"abAAcd".equals(new String(ba, cs.name()))) + throw new RuntimeException("encode1(surrogates) failed -> " + + cs.name()); + + ba = new byte[str.length()]; + n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 6 || !"abAAcd".equals(new String(ba, 0, n, + cs.name()))) + throw new RuntimeException("encode2(surrogates) failed -> " + + cs.name()); + str = "ab\uD800B\uDC00Bcd"; + ba = new byte[str.length()]; + n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 8 || !"abABABcd".equals(new String(ba, 0, n, + cs.name()))) + throw new RuntimeException("encode3(surrogates) failed -> " + + cs.name()); + + ba = new byte[str.length() - 1]; + n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 7 || !"abABABc".equals(new String(ba, 0, n, + cs.name()))) + throw new RuntimeException("encode4(surrogates) failed -> " + + cs.name()); + } + + } + + static class PermissiveSecurityManger extends SecurityManager { + @Override public void checkPermission(java.security.Permission p) {} + } +} diff --git a/jdk/test/sun/pisces/DashStrokeTest.java b/jdk/test/sun/pisces/DashStrokeTest.java new file mode 100644 index 00000000000..f77acbeacfe --- /dev/null +++ b/jdk/test/sun/pisces/DashStrokeTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @summary verify that first element is a dash + * @bug 6793344 + */ + +import java.awt.*; +import java.awt.image.*; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +public class DashStrokeTest extends Component { + + static BufferedImage bi; + static boolean printed = false; + + public Dimension getPreferredSize() { + return new Dimension(200,200); + } + + public static void drawGui() { + bi = new BufferedImage(200, 20, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bi.createGraphics(); + BasicStroke dashStroke = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, + BasicStroke.JOIN_ROUND, 1.0f, new float[] { 0.0f, 200 }, + 1.0f); + + g2d.setStroke(dashStroke); + g2d.setColor(Color.RED); + g2d.drawLine(5,10, 100,10); + printed =true; + } + + public static void main(String[] args) { + try { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + drawGui(); + } + + }); + } catch (Exception e) { + } + + if (printed) { + checkBI(bi, Color.RED); + } + } + + static void checkBI(BufferedImage bi, Color badColor) { + int badrgb = badColor.getRGB(); + + int col = bi.getRGB(6, 9); + if (col == badrgb) { + throw new RuntimeException("A pixel was turned on. "); + } + } +} + diff --git a/jdk/test/sun/pisces/JoinMiterTest.java b/jdk/test/sun/pisces/JoinMiterTest.java new file mode 100644 index 00000000000..567526b66e9 --- /dev/null +++ b/jdk/test/sun/pisces/JoinMiterTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @summary Pass if no RuntimeException. + * @bug 6812600 + */ +import java.awt.*; +import java.awt.image.BufferedImage; + +public class JoinMiterTest { + + public static void main(String[] args) throws Exception { + BufferedImage image = new BufferedImage(200, 200, +BufferedImage.TYPE_INT_RGB); + Graphics2D g = image.createGraphics(); + g.setPaint(Color.WHITE); + g.fill(new Rectangle(image.getWidth(), image.getHeight())); + g.translate(25, 100); + g.setPaint(Color.BLACK); + g.setStroke(new BasicStroke(20, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER)); + g.draw(new Polygon(new int[] {0, 150, 0}, new int[] {75, 0, -75}, 3)); + if (image.getRGB(16, 10) == Color.WHITE.getRGB()) { + throw new RuntimeException("Miter is not rendered."); + } + } +} diff --git a/jdk/test/sun/security/krb5/ParseCAPaths.java b/jdk/test/sun/security/krb5/ParseCAPaths.java new file mode 100644 index 00000000000..9f6772d4fca --- /dev/null +++ b/jdk/test/sun/security/krb5/ParseCAPaths.java @@ -0,0 +1,98 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test + * @bug 6789935 + * @summary cross-realm capath search error + */ + +import java.util.Arrays; +import sun.security.krb5.Realm; + +public class ParseCAPaths { + static boolean failed = false; + public static void main(String[] args) throws Exception { + System.setProperty("java.security.krb5.conf", System.getProperty("test.src", ".") +"/krb5-capaths.conf"); + //System.setProperty("sun.security.krb5.debug", "true"); + + // Standard example + check("ANL.GOV", "TEST.ANL.GOV", "ANL.GOV"); + check("ANL.GOV", "ES.NET", "ANL.GOV"); + check("ANL.GOV", "PNL.GOV", "ANL.GOV", "ES.NET"); + check("ANL.GOV", "NERSC.GOV", "ANL.GOV", "ES.NET"); + // Hierachical + check("N1.N.COM", "N2.N.COM", "N1.N.COM", "N.COM"); // 2 common + check("N1.N.COM", "N2.N3.COM", "N1.N.COM", "N.COM", // 1 common + "COM", "N3.COM"); + check("N1.COM", "N2.COM", "N1.COM", "COM"); // 1 common + check("N1", "N2", "N1"); // 0 common + // Extra garbages + check("A1.COM", "A4.COM", "A1.COM", "A2.COM"); + check("B1.COM", "B3.COM", "B1.COM", "B2.COM"); + // Missing is "." + check("C1.COM", "C3.COM", "C1.COM", "C2.COM"); + // Multiple path + check("D1.COM", "D4.COM", "D1.COM", "D2.COM"); + check("E1.COM", "E4.COM", "E1.COM", "E2.COM"); + check("F1.COM", "F4.COM", "F1.COM", "F9.COM"); + // Infinite loop + check("G1.COM", "G3.COM", "G1.COM", "COM"); + check("H1.COM", "H3.COM", "H1.COM"); + check("I1.COM", "I4.COM", "I1.COM", "I5.COM"); + + if (failed) { + throw new Exception("Failed somewhere."); + } + } + + static void check(String from, String to, String... paths) { + try { + check2(from, to, paths); + } catch (Exception e) { + failed = true; + e.printStackTrace(); + } + } + static void check2(String from, String to, String... paths) + throws Exception { + System.out.println(from + " -> " + to); + System.out.println(" expected: " + Arrays.toString(paths)); + String[] result = Realm.getRealmsList(from, to); + System.out.println(" result: " + Arrays.toString(result)); + if (result == null) { + if (paths.length == 0) { + // OK + } else { + throw new Exception("Shouldn't have a valid path."); + } + } else if(result.length != paths.length) { + throw new Exception("Length of path not correct"); + } else { + for (int i=0; i<result.length; i++) { + if (!result[i].equals(paths[i])) { + throw new Exception("Path not same"); + } + } + } + } +} diff --git a/jdk/test/sun/security/krb5/auto/SpnegoReqFlags.java b/jdk/test/sun/security/krb5/auto/SpnegoReqFlags.java new file mode 100644 index 00000000000..a94a2b5d1ac --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/SpnegoReqFlags.java @@ -0,0 +1,92 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6815182 + * @summary GSSAPI/SPNEGO does not work with server using MIT Kerberos library + */ + +import sun.security.jgss.GSSUtil; +import sun.security.util.BitArray; +import sun.security.util.DerInputStream; +import sun.security.util.DerValue; + +public class SpnegoReqFlags { + + public static void main(String[] args) + throws Exception { + + // Create and start the KDC + new OneKDC(null).writeJAASConf(); + new SpnegoReqFlags().go(); + } + + void go() throws Exception { + Context c = Context.fromJAAS("client"); + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_SPNEGO_MECH_OID); + + byte[] token = c.doAs(new Action() { + @Override + public byte[] run(Context me, byte[] input) throws Exception { + me.x().requestCredDeleg(true); + me.x().requestReplayDet(false); + me.x().requestSequenceDet(false); + return me.x().initSecContext(new byte[0], 0, 0); + } + }, null); + + DerValue d = new DerValue(token); // GSSToken + DerInputStream ins = d.data; // OID + mech token + d.data.getDerValue(); // skip OID + d = d.data.getDerValue(); // NegTokenInit + d = d.data.getDerValue(); // The SEQUENCE inside + + boolean found = false; + + // Go through all fields inside NegTokenInit. The reqFlags field + // is optional. It's even not recommended in RFC 4178. + while (d.data.available() > 0) { + DerValue d2 = d.data.getDerValue(); + if (d2.isContextSpecific((byte)1)) { + found = true; + System.out.println("regFlags field located."); + BitArray ba = d2.data.getUnalignedBitString(); + if (ba.length() != 7) { + throw new Exception("reqFlags should contain 7 bits"); + } + if (!ba.get(0)) { + throw new Exception("delegFlag should be true"); + } + if (ba.get(2) || ba.get(3)) { + throw new Exception("replay/sequenceFlag should be false"); + } + } + } + + if (!found) { + System.out.println("Warning: regFlags field not found, too new?"); + } + c.dispose(); + } +} diff --git a/jdk/test/sun/security/krb5/krb5-capaths.conf b/jdk/test/sun/security/krb5/krb5-capaths.conf new file mode 100644 index 00000000000..db672820b7d --- /dev/null +++ b/jdk/test/sun/security/krb5/krb5-capaths.conf @@ -0,0 +1,87 @@ +[capaths] + +# Standard + +ANL.GOV = { + TEST.ANL.GOV = . + PNL.GOV = ES.NET + NERSC.GOV = ES.NET + ES.NET = . +} +TEST.ANL.GOV = { + ANL.GOV = . +} +PNL.GOV = { + ANL.GOV = ES.NET +} +NERSC.GOV = { + ANL.GOV = ES.NET +} +ES.NET = { + ANL.GOV = . +} + +# Extra garbages + +A1.COM = { + A2.COM = . + A4.COM = A2.COM + A3.COM = A4.COM + A3.COM = A2.COM +} + +B1.COM = { + B2.COM = . + B3.COM = B2.COM + B3.COM = B4.COM +} + +# Missing is "." + +C1.COM = { + C3.COM = C2.COM +} + +# Multiple paths + +D1.COM = { + D2.COM = . + D3.COM = . + D4.COM = D2.COM + D4.COM = D3.COM +} + +E1.COM = { + E2.COM = . + E3.COM = . + E4.COM = E2.COM E3.COM E2.COM +} + +# Shortest or First? + +F1.COM = { + F2.COM = . + F3.COM = F2.COM + F4.COM = F9.COM + F4.COM = F3.COM + F4.COM = F2.COM +} + +# Infinite loop + +G1.COM = { + G2.COM = G3.COM + G3.COM = G2.COM +} + +H1.COM = { + H2.COM = H3.COM + H3.COM = H2.COM + H3.COM = . +} + +I1.COM = { + I2.COM = I3.COM + I3.COM = I2.COM + I4.COM = I2.COM I5.COM +} diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/AppInputStream/ReadZeroBytes.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/AppInputStream/ReadZeroBytes.java new file mode 100644 index 00000000000..56134e0e773 --- /dev/null +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/AppInputStream/ReadZeroBytes.java @@ -0,0 +1,254 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6697270 + * @summary Inputstream dosent behave correct + */ + +import java.io.*; +import java.net.*; +import javax.net.ssl.*; + +public class ReadZeroBytes { + + /* + * ============================================================= + * Set the various variables needed for the tests, then + * specify what tests to run on each side. + */ + + /* + * Should we run the client or server in a separate thread? + * Both sides can throw exceptions, but do you have a preference + * as to which side should be the main thread. + */ + static boolean separateServerThread = false; + + /* + * Where do we find the keystores? + */ + static String pathToStores = "../../../../../../../etc"; + static String keyStoreFile = "keystore"; + static String trustStoreFile = "truststore"; + static String passwd = "passphrase"; + + /* + * Is the server ready to serve? + */ + volatile static boolean serverReady = false; + + /* + * Turn on SSL debugging? + */ + static boolean debug = false; + + /* + * Define the server side of the test. + */ + void doServerSide() throws Exception { + SSLServerSocketFactory sslssf = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + SSLServerSocket sslServerSocket = + (SSLServerSocket) sslssf.createServerSocket(serverPort); + + serverPort = sslServerSocket.getLocalPort(); + + /* + * Signal Client, we're ready for his connect. + */ + serverReady = true; + + SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + // no read, no write. + SSLSession sess = sslSocket.getSession(); + if (!sess.isValid()) { + throw new Exception("Error occurs during the initial handshake"); + } + + sslIS.close(); + sslOS.close(); + sslSocket.close(); + } + + /* + * Define the client side of the test. + */ + void doClientSide() throws Exception { + + /* + * Wait for server to get started. + */ + while (!serverReady) { + Thread.sleep(50); + } + + SSLSocketFactory sslsf = + (SSLSocketFactory) SSLSocketFactory.getDefault(); + SSLSocket sslSocket = (SSLSocket) + sslsf.createSocket("localhost", serverPort); + + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + // read zero byte, write zero byte. + sslIS.read(new byte[0], 0, 0); + sslOS.write(new byte[0], 0, 0); + + // if byte array length matters. + sslIS.read(new byte[1], 0, 0); + sslOS.write(new byte[1], 0, 0); + + // note that the above read/write should not kickoff handshaking. + SSLSession sess = sslSocket.getSession(); + if (!sess.isValid()) { + throw new Exception("Error occurs during the initial handshake"); + } + + sslIS.close(); + sslOS.close(); + sslSocket.close(); + } + + /* + * ============================================================= + * The remainder is just support stuff + */ + + // use any free port by default + volatile int serverPort = 0; + + volatile Exception serverException = null; + volatile Exception clientException = null; + + public static void main(String[] args) throws Exception { + String keyFilename = + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + keyStoreFile; + String trustFilename = + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + trustStoreFile; + + System.setProperty("javax.net.ssl.keyStore", keyFilename); + System.setProperty("javax.net.ssl.keyStorePassword", passwd); + System.setProperty("javax.net.ssl.trustStore", trustFilename); + System.setProperty("javax.net.ssl.trustStorePassword", passwd); + + if (debug) + System.setProperty("javax.net.debug", "all"); + + /* + * Start the tests. + */ + new ReadZeroBytes(); + } + + Thread clientThread = null; + Thread serverThread = null; + + /* + * Primary constructor, used to drive remainder of the test. + * + * Fork off the other side, then do your work. + */ + ReadZeroBytes () throws Exception { + if (separateServerThread) { + startServer(true); + startClient(false); + } else { + startClient(true); + startServer(false); + } + + /* + * Wait for other side to close down. + */ + if (separateServerThread) { + serverThread.join(); + } else { + clientThread.join(); + } + + /* + * When we get here, the test is pretty much over. + * + * If the main thread excepted, that propagates back + * immediately. If the other thread threw an exception, we + * should report back. + */ + if (serverException != null) + throw serverException; + if (clientException != null) + throw clientException; + } + + void startServer(boolean newThread) throws Exception { + if (newThread) { + serverThread = new Thread() { + public void run() { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not already active... + */ + System.out.println("Server died..."); + serverReady = true; + serverException = e; + } + } + }; + serverThread.start(); + } else { + doServerSide(); + } + } + + void startClient(boolean newThread) throws Exception { + if (newThread) { + clientThread = new Thread() { + public void run() { + try { + doClientSide(); + } catch (Exception e) { + /* + * Our client thread just died. + */ + System.out.println("Client died..."); + clientException = e; + } + } + }; + clientThread.start(); + } else { + doClientSide(); + } + } +} + diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/LoopbackSSLSocket.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/LoopbackSSLSocket.java new file mode 100644 index 00000000000..d97f20da7aa --- /dev/null +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/LoopbackSSLSocket.java @@ -0,0 +1,50 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 5067458 + * @summary Loopback SSLSocketImpl createSocket is throwing an exception. + * @author Xuelei Fan + */ + +import java.io.*; +import java.net.*; + +import javax.net.ssl.*; + +public class LoopbackSSLSocket { + + public static void main(String[] args) throws Exception { + SSLSocketFactory sf = (SSLSocketFactory)SSLSocketFactory.getDefault(); + // we won't expect a IllegalArgumentException: hostname can't be null. + try { + SSLSocket s = (SSLSocket)sf.createSocket((String)null, 0); + s.close(); + } catch (IOException ioe) { + // would catch a IOException because there is no listener on + // that socket. + } + } + +} diff --git a/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh b/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh new file mode 100644 index 00000000000..1c9eaabe396 --- /dev/null +++ b/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh @@ -0,0 +1,200 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 6802846 +# @summary jarsigner needs enhanced cert validation(options) +# +# @run shell concise_jarsigner.sh +# + +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore js.jks" +JAR=$TESTJAVA${FS}bin${FS}jar +JARSIGNER=$TESTJAVA${FS}bin${FS}jarsigner +JAVAC=$TESTJAVA${FS}bin${FS}javac + +rm js.jks + +echo class A1 {} > A1.java +echo class A2 {} > A2.java +echo class A3 {} > A3.java +echo class A4 {} > A4.java +echo class A5 {} > A5.java +echo class A6 {} > A6.java + +$JAVAC A1.java A2.java A3.java A4.java A5.java A6.java +YEAR=`date +%Y` + +# ========================================================== +# First part: output format +# ========================================================== + +$KT -genkeypair -alias a1 -dname CN=a1 -validity 365 +$KT -genkeypair -alias a2 -dname CN=a2 -validity 365 + +# a.jar includes 8 unsigned, 2 signed by a1 and a2, 2 signed by a3 +$JAR cvf a.jar A1.class A2.class +$JARSIGNER -keystore js.jks -storepass changeit a.jar a1 +$JAR uvf a.jar A3.class A4.class +$JARSIGNER -keystore js.jks -storepass changeit a.jar a2 +$JAR uvf a.jar A5.class A6.class + +# Verify OK +$JARSIGNER -verify a.jar +[ $? = 0 ] || exit $LINENO + +# 4(chainNotValidated)+16(hasUnsignedEntry)+32(aliasNotInStore) +$JARSIGNER -verify a.jar -strict +[ $? = 52 ] || exit $LINENO + +# 16(hasUnsignedEntry) +$JARSIGNER -verify a.jar -strict -keystore js.jks +[ $? = 16 ] || exit $LINENO + +# 16(hasUnsignedEntry)+32(notSignedByAlias) +$JARSIGNER -verify a.jar a1 -strict -keystore js.jks +[ $? = 48 ] || exit $LINENO + +# 16(hasUnsignedEntry) +$JARSIGNER -verify a.jar a1 a2 -strict -keystore js.jks +[ $? = 16 ] || exit $LINENO + +# 12 entries all together +LINES=`$JARSIGNER -verify a.jar -verbose | grep $YEAR | wc -l` +[ $LINES = 12 ] || exit $LINENO + +# 12 entries all listed +LINES=`$JARSIGNER -verify a.jar -verbose:grouped | grep $YEAR | wc -l` +[ $LINES = 12 ] || exit $LINENO + +# 3 groups: unrelated, signed, unsigned +LINES=`$JARSIGNER -verify a.jar -verbose:summary | grep $YEAR | wc -l` +[ $LINES = 3 ] || exit $LINENO + +# 4 groups: unrelated, signed by a1/a2, signed by a2, unsigned +LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep $YEAR | wc -l` +[ $LINES = 4 ] || exit $LINENO + +# 2*2 for A1/A2, 2 for A3/A4 +LINES=`$JARSIGNER -verify a.jar -verbose -certs | grep "\[certificate" | wc -l` +[ $LINES = 6 ] || exit $LINENO + +# a1,a2 for A1/A2, a2 for A3/A4 +LINES=`$JARSIGNER -verify a.jar -verbose:grouped -certs | grep "\[certificate" | wc -l` +[ $LINES = 3 ] || exit $LINENO + +# a1,a2 for A1/A2, a2 for A3/A4 +LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "\[certificate" | wc -l` +[ $LINES = 3 ] || exit $LINENO + +# 4 groups +LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "more)" | wc -l` +[ $LINES = 4 ] || exit $LINENO + +# ========================================================== +# Second part: exit code 2, 4, 8 +# 16 and 32 already covered in the first part +# ========================================================== + +$KT -genkeypair -alias expiring -dname CN=expiring -startdate -1m +$KT -genkeypair -alias expired -dname CN=expired -startdate -10m +$KT -genkeypair -alias notyetvalid -dname CN=notyetvalid -startdate +1m +$KT -genkeypair -alias badku -dname CN=badku -ext KU=cRLSign -validity 365 +$KT -genkeypair -alias badeku -dname CN=badeku -ext EKU=sa -validity 365 +$KT -genkeypair -alias goodku -dname CN=goodku -ext KU=dig -validity 365 +$KT -genkeypair -alias goodeku -dname CN=goodeku -ext EKU=codesign -validity 365 + +# badchain signed by ca, but ca is removed later +$KT -genkeypair -alias badchain -dname CN=badchain -validity 365 +$KT -genkeypair -alias ca -dname CN=ca -ext bc -validity 365 +$KT -certreq -alias badchain | $KT -gencert -alias ca -validity 365 | \ + $KT -importcert -alias badchain +$KT -delete -alias ca + +$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar expiring +[ $? = 2 ] || exit $LINENO + +$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar expired +[ $? = 4 ] || exit $LINENO + +$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar notyetvalid +[ $? = 4 ] || exit $LINENO + +$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar badku +[ $? = 8 ] || exit $LINENO + +$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar badeku +[ $? = 8 ] || exit $LINENO + +$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar goodku +[ $? = 0 ] || exit $LINENO + +$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar goodeku +[ $? = 0 ] || exit $LINENO + +$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar badchain +[ $? = 4 ] || exit $LINENO + +$JARSIGNER -verify a.jar +[ $? = 0 ] || exit $LINENO + +# ========================================================== +# Third part: -certchain test +# ========================================================== + +# altchain signed by ca2, but ca2 is removed later +$KT -genkeypair -alias altchain -dname CN=altchain -validity 365 +$KT -genkeypair -alias ca2 -dname CN=ca2 -ext bc -validity 365 +$KT -certreq -alias altchain | $KT -gencert -alias ca2 -validity 365 -rfc > certchain +$KT -exportcert -alias ca2 -rfc >> certchain +$KT -delete -alias ca2 + +# Now altchain is still self-signed +$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar altchain +[ $? = 0 ] || exit $LINENO + +# If -certchain is used, then it's bad +$JARSIGNER -strict -keystore js.jks -storepass changeit -certchain certchain a.jar altchain +[ $? = 4 ] || exit $LINENO + +$JARSIGNER -verify a.jar +[ $? = 0 ] || exit $LINENO + +echo OK +exit 0 diff --git a/jdk/test/sun/security/tools/keytool/KeyToolTest.java b/jdk/test/sun/security/tools/keytool/KeyToolTest.java index e25c3766b50..e1edebedfa5 100644 --- a/jdk/test/sun/security/tools/keytool/KeyToolTest.java +++ b/jdk/test/sun/security/tools/keytool/KeyToolTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,11 +56,14 @@ */ import java.security.KeyStore; -import java.util.Locale; -import java.util.MissingResourceException; import sun.security.tools.KeyTool; import sun.security.x509.*; import java.io.*; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.security.cert.X509Certificate; +import sun.security.util.ObjectIdentifier; public class KeyToolTest { @@ -118,7 +121,7 @@ public class KeyToolTest { lastInput = input; lastCommand = cmd; - // "X" is appened so that we can precisely test how input is consumed + // "X" is appended so that we can precisely test how input is consumed HumanInputStream in = new HumanInputStream(input+"X"); test(in, cmd); // make sure the input string is no more no less @@ -264,12 +267,21 @@ public class KeyToolTest { } void assertTrue(boolean bool, String msg) { + if (debug) { + System.err.println("If not " + bool + ", " + msg); + } else { + System.err.print("v"); + } if(!bool) { afterFail(lastInput, lastCommand, "TRUE"); + System.err.println(msg); throw new RuntimeException(msg); } } + void assertTrue(boolean bool) { + assertTrue(bool, "well..."); + } /** * Helper method, load a keystore * @param file file for keystore, null or "NONE" for PKCS11 @@ -827,32 +839,363 @@ public class KeyToolTest { remove("mykey.cert"); } + void v3extTest(String keyAlg) throws Exception { + KeyStore ks; + remove("x.jks"); + String simple = "-keystore x.jks -storepass changeit -keypass changeit -noprompt -keyalg " + keyAlg + " "; + String pre = simple + "-genkeypair -dname CN=Olala -alias "; + + // Version and SKID + testOK("", pre + "o1"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(((X509Certificate)ks.getCertificate("o1")).getVersion() == 3); + assertTrue(((X509CertImpl)ks.getCertificate("o1")).getSubjectKeyIdentifierExtension() != null); + + // BC + testOK("", pre + "b1 -ext BC:critical"); + testOK("", pre + "b2 -ext BC"); + testOK("", pre + "b3 -ext bc"); + testOK("", pre + "b4 -ext BasicConstraints"); + testOK("", pre + "b5 -ext basicconstraints"); + testOK("", pre + "b6 -ext BC=ca:true,pathlen:12"); + testOK("", pre + "b7 -ext BC=ca:false"); + testOK("", pre + "b8 -ext BC:critical=ca:false"); + testOK("", pre + "b9 -ext BC=12"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(((X509CertImpl)ks.getCertificate("b1")).getBasicConstraintsExtension().isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("b2")).getBasicConstraintsExtension().isCritical()); + assertTrue(((X509CertImpl)ks.getCertificate("b8")).getBasicConstraintsExtension().isCritical()); + assertTrue(((X509Certificate)ks.getCertificate("b1")).getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b2")).getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b3")).getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b4")).getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b5")).getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b6")).getBasicConstraints() == 12); + assertTrue(((X509Certificate)ks.getCertificate("b7")).getBasicConstraints() == -1); + assertTrue(((X509Certificate)ks.getCertificate("b9")).getBasicConstraints() == 12); + + // KU + testOK("", pre + "ku1 -ext KeyUsage:critical=digitalsignature"); + testOK("", pre + "ku2 -ext KU=digitalSignature"); + testOK("", pre + "ku3 -ext KU=ds"); + testOK("", pre + "ku4 -ext KU=dig"); + testFail("", pre + "ku5 -ext KU=d"); // ambigous value + testFail("", pre + "ku6 -ext KU=cs"); // cRLSign cannot be cs + testOK("", pre + "ku11 -ext KU=nr"); + testFail("", pre + "ku12 -ext KU=ke"); // ke also means keyAgreement + testOK("", pre + "ku12 -ext KU=keyE"); + testFail("", pre + "ku13 -ext KU=de"); // de also means decipherOnly + testOK("", pre + "ku13 -ext KU=dataE"); + testOK("", pre + "ku14 -ext KU=ka"); + testOK("", pre + "ku15 -ext KU=kcs"); + testOK("", pre + "ku16 -ext KU=crls"); + testOK("", pre + "ku17 -ext KU=eo"); + testOK("", pre + "ku18 -ext KU=do"); + testOK("", pre + "ku19 -ext KU=cc"); + + testOK("", pre + "ku017 -ext KU=ds,cc,eo"); + testOK("", pre + "ku135 -ext KU=nr,dataEncipherment,keyCertSign"); + testOK("", pre + "ku246 -ext KU=keyEnc,cRL,keyA"); + testOK("", pre + "ku1234 -ext KU=ka,da,keyE,nonR"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckKU { + void check(KeyStore ks, String alias, int... pos) throws Exception { + System.err.print("x"); + boolean[] bs = ((X509Certificate)ks.getCertificate(alias)).getKeyUsage(); + bs = Arrays.copyOf(bs, 9); + for (int i=0; i<bs.length; i++) { + boolean found = false; + for (int p: pos) { + if (p == i) found = true; + } + if (!found ^ bs[i]) { + // OK + } else { + throw new RuntimeException("KU not match at " + i + + ": " + found + " vs " + bs[i]); + } + } + } + } + CheckKU c = new CheckKU(); + assertTrue(((X509CertImpl)ks.getCertificate("ku1")).getExtension(PKIXExtensions.KeyUsage_Id).isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("ku2")).getExtension(PKIXExtensions.KeyUsage_Id).isCritical()); + c.check(ks, "ku1", 0); + c.check(ks, "ku2", 0); + c.check(ks, "ku3", 0); + c.check(ks, "ku4", 0); + c.check(ks, "ku11", 1); + c.check(ks, "ku12", 2); + c.check(ks, "ku13", 3); + c.check(ks, "ku14", 4); + c.check(ks, "ku15", 5); + c.check(ks, "ku16", 6); + c.check(ks, "ku17", 7); + c.check(ks, "ku18", 8); + c.check(ks, "ku19", 1); + c.check(ks, "ku11", 1); + c.check(ks, "ku11", 1); + c.check(ks, "ku11", 1); + c.check(ks, "ku017", 0, 1, 7); + c.check(ks, "ku135", 1, 3, 5); + c.check(ks, "ku246", 6, 2, 4); + c.check(ks, "ku1234", 1, 2, 3, 4); + + // EKU + testOK("", pre + "eku1 -ext EKU:critical=sa"); + testOK("", pre + "eku2 -ext ExtendedKeyUsage=ca"); + testOK("", pre + "eku3 -ext EKU=cs"); + testOK("", pre + "eku4 -ext EKU=ep"); + testOK("", pre + "eku8 -ext EKU=ts"); + testFail("", pre + "eku9 -ext EKU=os"); + testOK("", pre + "eku9 -ext EKU=ocsps"); + testOK("", pre + "eku10 -ext EKU=any"); + testOK("", pre + "eku11 -ext EKU=1.2.3.4,1.3.5.7,ep"); + testFail("", pre + "eku12 -ext EKU=c"); + testFail("", pre + "eku12 -ext EKU=nothing"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckEKU { + void check(KeyStore ks, String alias, String... pos) throws Exception { + System.err.print("x"); + List<String> bs = ((X509Certificate)ks.getCertificate(alias)).getExtendedKeyUsage(); + int found = 0; + for (String p: pos) { + if (bs.contains(p)) { + found++; + } else { + throw new RuntimeException("EKU: not included " + p); + } + } + if (found != bs.size()) { + throw new RuntimeException("EKU: more items than expected"); + } + } + } + CheckEKU cx = new CheckEKU(); + assertTrue(((X509CertImpl)ks.getCertificate("eku1")).getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("eku2")).getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical()); + cx.check(ks, "eku1", "1.3.6.1.5.5.7.3.1"); + cx.check(ks, "eku2", "1.3.6.1.5.5.7.3.2"); + cx.check(ks, "eku3", "1.3.6.1.5.5.7.3.3"); + cx.check(ks, "eku4", "1.3.6.1.5.5.7.3.4"); + cx.check(ks, "eku8", "1.3.6.1.5.5.7.3.8"); + cx.check(ks, "eku9", "1.3.6.1.5.5.7.3.9"); + cx.check(ks, "eku10", "2.5.29.37.0"); + cx.check(ks, "eku11", "1.3.6.1.5.5.7.3.4", "1.2.3.4", "1.3.5.7"); + + // SAN + testOK("", pre+"san1 -ext san:critical=email:me@me.org"); + testOK("", pre+"san2 -ext san=uri:http://me.org"); + testOK("", pre+"san3 -ext san=dns:me.org"); + testOK("", pre+"san4 -ext san=ip:192.168.0.1"); + testOK("", pre+"san5 -ext san=oid:1.2.3.4"); + testOK("", pre+"san235 -ext san=uri:http://me.org,dns:me.org,oid:1.2.3.4"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckSAN { + // Please sort items with name type + void check(KeyStore ks, String alias, int type, Object... items) throws Exception { + int pos = 0; + System.err.print("x"); + Object[] names = null; + if (type == 0) names = ((X509Certificate)ks.getCertificate(alias)).getSubjectAlternativeNames().toArray(); + else names = ((X509Certificate)ks.getCertificate(alias)).getIssuerAlternativeNames().toArray(); + Arrays.sort(names, new Comparator() { + public int compare(Object o1, Object o2) { + int i1 = (Integer)((List)o1).get(0); + int i2 = (Integer)((List)o2).get(0); + return i1 - i2; + } + }); + for (Object o: names) { + List l = (List)o; + for (Object o2: l) { + if (!items[pos++].equals(o2)) { + throw new RuntimeException("Not equals at " + pos + + ": " + items[pos-1] + " vs " + o2); + } + } + } + if (pos != items.length) { + throw new RuntimeException("Extra items, pos is " + pos); + } + } + } + CheckSAN csan = new CheckSAN(); + assertTrue(((X509CertImpl)ks.getCertificate("san1")).getSubjectAlternativeNameExtension().isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("san2")).getSubjectAlternativeNameExtension().isCritical()); + csan.check(ks, "san1", 0, 1, "me@me.org"); + csan.check(ks, "san2", 0, 6, "http://me.org"); + csan.check(ks, "san3", 0, 2, "me.org"); + csan.check(ks, "san4", 0, 7, "192.168.0.1"); + csan.check(ks, "san5", 0, 8, "1.2.3.4"); + csan.check(ks, "san235", 0, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4"); + + // IAN + testOK("", pre+"ian1 -ext ian:critical=email:me@me.org"); + testOK("", pre+"ian2 -ext ian=uri:http://me.org"); + testOK("", pre+"ian3 -ext ian=dns:me.org"); + testOK("", pre+"ian4 -ext ian=ip:192.168.0.1"); + testOK("", pre+"ian5 -ext ian=oid:1.2.3.4"); + testOK("", pre+"ian235 -ext ian=uri:http://me.org,dns:me.org,oid:1.2.3.4"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(((X509CertImpl)ks.getCertificate("ian1")).getIssuerAlternativeNameExtension().isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("ian2")).getIssuerAlternativeNameExtension().isCritical()); + csan.check(ks, "ian1", 1, 1, "me@me.org"); + csan.check(ks, "ian2", 1, 6, "http://me.org"); + csan.check(ks, "ian3", 1, 2, "me.org"); + csan.check(ks, "ian4", 1, 7, "192.168.0.1"); + csan.check(ks, "ian5", 1, 8, "1.2.3.4"); + csan.check(ks, "ian235", 1, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4"); + + // SIA + testOK("", pre+"sia1 -ext sia=care:uri:ldap://ca.com/cn=CA"); + testOK("", pre+"sia2 -ext sia=ts:email:ts@ca.com"); + testFail("SIA never critical", pre+"sia3 -ext sia:critical=ts:email:ts@ca.com"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckSia { + void check(KeyStore ks, String alias, int type, Object... items) throws Exception { + int pos = 0; + System.err.print("x"); + AccessDescription[] ads = null; + if (type == 0) { + SubjectInfoAccessExtension siae = (SubjectInfoAccessExtension)((X509CertImpl)ks.getCertificate(alias)).getExtension(PKIXExtensions.SubjectInfoAccess_Id); + ads = siae.getAccessDescriptions().toArray(new AccessDescription[0]); + } else { + AuthorityInfoAccessExtension aiae = (AuthorityInfoAccessExtension)((X509CertImpl)ks.getCertificate(alias)).getExtension(PKIXExtensions.AuthInfoAccess_Id); + ads = aiae.getAccessDescriptions().toArray(new AccessDescription[0]); + } + Arrays.sort(ads, new Comparator<AccessDescription>() { + @Override + public int compare(AccessDescription o1, AccessDescription o2) { + return o1.getAccessMethod().toString().compareTo(o2.getAccessMethod().toString()); + } + }); + for (AccessDescription ad: ads) { + if (!ad.getAccessMethod().equals(items[pos++]) || + !new Integer(ad.getAccessLocation().getType()).equals(items[pos++])) { + throw new RuntimeException("Not same type at " + pos); + } + String name = null; + switch (ad.getAccessLocation().getType()) { + case 1: + name = ((RFC822Name)ad.getAccessLocation().getName()).getName(); + break; + case 6: + name = ((URIName)ad.getAccessLocation().getName()).getURI().toString(); + break; + default: + throw new RuntimeException("Not implemented: " + ad); + } + if (!name.equals(items[pos++])) { + throw new Exception("Name not same for " + ad + " at pos " + pos); + } + } + } + } + CheckSia csia = new CheckSia(); + assertTrue(!((X509CertImpl)ks.getCertificate("sia1")).getExtension(PKIXExtensions.SubjectInfoAccess_Id).isCritical()); + csia.check(ks, "sia1", 0, AccessDescription.Ad_CAREPOSITORY_Id, 6, "ldap://ca.com/cn=CA"); + csia.check(ks, "sia2", 0, AccessDescription.Ad_TIMESTAMPING_Id, 1, "ts@ca.com"); + + // AIA + testOK("", pre+"aia1 -ext aia=cai:uri:ldap://ca.com/cn=CA"); + testOK("", pre+"aia2 -ext aia=ocsp:email:ocsp@ca.com"); + testFail("AIA never critical", pre+"aia3 -ext aia:critical=ts:email:ts@ca.com"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(!((X509CertImpl)ks.getCertificate("aia1")).getExtension(PKIXExtensions.AuthInfoAccess_Id).isCritical()); + csia.check(ks, "aia1", 1, AccessDescription.Ad_CAISSUERS_Id, 6, "ldap://ca.com/cn=CA"); + csia.check(ks, "aia2", 1, AccessDescription.Ad_OCSP_Id, 1, "ocsp@ca.com"); + + // OID + testOK("", pre+"oid1 -ext 1.2.3:critical=0102"); + testOK("", pre+"oid2 -ext 1.2.3"); + testOK("", pre+"oid12 -ext 1.2.3 -ext 1.2.4=01:02:03"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckOid { + void check(KeyStore ks, String alias, String oid, byte[] value) throws Exception { + int pos = 0; + System.err.print("x"); + Extension ex = ((X509CertImpl)ks.getCertificate(alias)).getExtension(new ObjectIdentifier(oid)); + if (!Arrays.equals(value, ex.getValue())) { + throw new RuntimeException("Not same content in " + alias + " for " + oid); + } + } + } + CheckOid coid = new CheckOid(); + assertTrue(((X509CertImpl)ks.getCertificate("oid1")).getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("oid2")).getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + coid.check(ks, "oid1", "1.2.3", new byte[]{1,2}); + coid.check(ks, "oid2", "1.2.3", new byte[]{}); + coid.check(ks, "oid12", "1.2.3", new byte[]{}); + coid.check(ks, "oid12", "1.2.4", new byte[]{1,2,3}); + + // honored + testOK("", pre+"ca"); + testOK("", pre+"a"); + // request: BC,KU,1.2.3,1.2.4,1.2.5 + testOK("", simple+"-alias a -certreq " + + "-ext BC=1 -ext KU=crl " + + "-ext 1.2.3=01 -ext 1.2.4:critical=0102 -ext 1.2.5=010203 " + + "-rfc -file test.req"); + // printcertreq + testOK("", "-printcertreq -file test.req"); + // issue: deny KU, change criticality of 1.2.3 and 1.2.4, change content of BC, add 2.3.4 + testOK("", simple+"-gencert -alias ca -infile test.req -ext " + + "honored=all,-KU,1.2.3:critical,1.2.4:non-critical " + + "-ext BC=2 -ext 2.3.4=01020304 " + + "-debug -rfc -outfile test.cert"); + testOK("", simple+"-importcert -file test.cert -alias a"); + ks = loadStore("x.jks", "changeit", "JKS"); + X509CertImpl a = (X509CertImpl)ks.getCertificate("a"); + assertTrue(a.getAuthorityKeyIdentifierExtension() != null); + assertTrue(a.getSubjectKeyIdentifierExtension() != null); + assertTrue(a.getKeyUsage() == null); + assertTrue(a.getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + assertTrue(!a.getExtension(new ObjectIdentifier("1.2.4")).isCritical()); + assertTrue(!a.getExtension(new ObjectIdentifier("1.2.5")).isCritical()); + assertTrue(a.getExtensionValue("1.2.3").length == 3); + assertTrue(a.getExtensionValue("1.2.4").length == 4); + assertTrue(a.getExtensionValue("1.2.5").length == 5); + assertTrue(a.getBasicConstraints() == 2); + assertTrue(!a.getExtension(new ObjectIdentifier("2.3.4")).isCritical()); + assertTrue(a.getExtensionValue("2.3.4").length == 6); + + remove("x.jks"); + remove("test.req"); + remove("test.cert"); + } + void i18nTest() throws Exception { // 1. keytool -help remove("x.jks"); - try { - test("", "-help"); - assertTrue(false, "Cannot come here"); - } catch(RuntimeException e) { - assertTrue(e.getMessage().indexOf("NO ERROR, SORRY") != -1, "No error"); - } + testOK("", "-help"); + // 2. keytool -genkey -v -keysize 512 Enter "a" for the keystore password. Check error (password too short). Enter "password" for the keystore password. Hit 'return' for "first and last name", "organizational unit", "City", "State", and "Country Code". Type "yes" when they ask you if everything is correct. Type 'return' for new key password. testOK("a\npassword\npassword\nMe\nHere\nNow\nPlace\nPlace\nUS\nyes\n\n", "-genkey -v -keysize 512 -keystore x.jks"); // 3. keytool -list -v -storepass password testOK("", "-list -v -storepass password -keystore x.jks"); // 4. keytool -list -v Type "a" for the keystore password. Check error (wrong keystore password). testFail("a\n", "-list -v -keystore x.jks"); - assertTrue(ex.indexOf("password was incorrect") != -1, ""); + assertTrue(ex.indexOf("password was incorrect") != -1); // 5. keytool -genkey -v -keysize 512 Enter "password" as the password. Check error (alias 'mykey' already exists). testFail("password\n", "-genkey -v -keysize 512 -keystore x.jks"); - assertTrue(ex.indexOf("alias <mykey> already exists") != -1, ""); + assertTrue(ex.indexOf("alias <mykey> already exists") != -1); // 6. keytool -genkey -v -keysize 512 -alias mykey2 -storepass password Hit 'return' for "first and last name", "organizational unit", "City", "State", and "Country Code". Type "yes" when they ask you if everything is correct. Type 'return' for new key password. testOK("\n\n\n\n\n\nyes\n\n", "-genkey -v -keysize 512 -alias mykey2 -storepass password -keystore x.jks"); // 7. keytool -list -v Type 'password' for the store password. testOK("password\n", "-list -v -keystore x.jks"); // 8. keytool -keypasswd -v -alias mykey2 -storepass password Type "a" for the new key password. Type "aaaaaa" for the new key password. Type "bbbbbb" when re-entering the new key password. Type "a" for the new key password. Check Error (too many failures). testFail("a\naaaaaa\nbbbbbb\na\n", "-keypasswd -v -alias mykey2 -storepass password -keystore x.jks"); - assertTrue(ex.indexOf("Too many failures - try later") != -1, ""); + assertTrue(ex.indexOf("Too many failures - try later") != -1); // 9. keytool -keypasswd -v -alias mykey2 -storepass password Type "aaaaaa" for the new key password. Type "aaaaaa" when re-entering the new key password. testOK("aaaaaa\naaaaaa\n", "-keypasswd -v -alias mykey2 -storepass password -keystore x.jks"); // 10. keytool -selfcert -v -alias mykey -storepass password @@ -864,7 +1207,7 @@ public class KeyToolTest { testOK("", "-export -v -alias mykey -file cert -storepass password -keystore x.jks"); // 13. keytool -import -v -file cert -storepass password Check error (Certificate reply and cert are the same) testFail("", "-import -v -file cert -storepass password -keystore x.jks"); - assertTrue(ex.indexOf("Certificate reply and certificate in keystore are identical") != -1, ""); + assertTrue(ex.indexOf("Certificate reply and certificate in keystore are identical") != -1); // 14. keytool -printcert -file cert testOK("", "-printcert -file cert -keystore x.jks"); remove("cert"); @@ -875,26 +1218,26 @@ public class KeyToolTest { // 1. keytool -storepasswd -storepass password -new abc Check error (password too short) testFail("", "-storepasswd -storepass password -new abc"); - assertTrue(ex.indexOf("New password must be at least 6 characters") != -1, ""); + assertTrue(ex.indexOf("New password must be at least 6 characters") != -1); // Changed, no NONE needed now // 2. keytool -list -storetype PKCS11 Check error (-keystore must be NONE) //testFail("", "-list -storetype PKCS11"); - //assertTrue(err.indexOf("keystore must be NONE") != -1, ""); + //assertTrue(err.indexOf("keystore must be NONE") != -1); // 3. keytool -storepasswd -storetype PKCS11 -keystore NONE Check error (unsupported operation) testFail("", "-storepasswd -storetype PKCS11 -keystore NONE"); - assertTrue(ex.indexOf("UnsupportedOperationException") != -1, ""); + assertTrue(ex.indexOf("UnsupportedOperationException") != -1); // 4. keytool -keypasswd -storetype PKCS11 -keystore NONE Check error (unsupported operation) testFail("", "-keypasswd -storetype PKCS11 -keystore NONE"); - assertTrue(ex.indexOf("UnsupportedOperationException") != -1, ""); + assertTrue(ex.indexOf("UnsupportedOperationException") != -1); // 5. keytool -list -protected -storepass password Check error (password can not be specified with -protected) testFail("", "-list -protected -storepass password -keystore x.jks"); - assertTrue(ex.indexOf("if -protected is specified, then") != -1, ""); + assertTrue(ex.indexOf("if -protected is specified, then") != -1); // 6. keytool -keypasswd -protected -keypass password Check error (password can not be specified with -protected) testFail("", "-keypasswd -protected -keypass password -keystore x.jks"); - assertTrue(ex.indexOf("if -protected is specified, then") != -1, ""); + assertTrue(ex.indexOf("if -protected is specified, then") != -1); // 7. keytool -keypasswd -protected -new password Check error (password can not be specified with -protected) testFail("", "-keypasswd -protected -new password -keystore x.jks"); - assertTrue(ex.indexOf("if -protected is specified, then") != -1, ""); + assertTrue(ex.indexOf("if -protected is specified, then") != -1); remove("x.jks"); } @@ -911,11 +1254,11 @@ public class KeyToolTest { testOK("", "-printcert -file genkey.cert"); testOK("", p11Arg + "-storepass test12 -selfcert -alias genkey -dname cn=selfCert"); testOK("", p11Arg + "-storepass test12 -list -alias genkey -v"); - assertTrue(out.indexOf("Owner: CN=selfCert") != -1, ""); + assertTrue(out.indexOf("Owner: CN=selfCert") != -1); //(check that cert subject DN is [cn=selfCert]) testOK("", p11Arg + "-storepass test12 -delete -alias genkey"); testOK("", p11Arg + "-storepass test12 -list"); - assertTrue(out.indexOf("Your keystore contains 0 entries") != -1, ""); + assertTrue(out.indexOf("Your keystore contains 0 entries") != -1); //(check for empty database listing) //Runtime.getRuntime().exec("/usr/ccs/bin/sccs unedit cert8.db key3.db"); remove("genkey.cert"); @@ -943,6 +1286,15 @@ public class KeyToolTest { t.sqeTest(); t.testAll(); t.i18nTest(); + t.v3extTest("RSA"); + t.v3extTest("DSA"); + boolean testEC = true; + try { + KeyPairGenerator.getInstance("EC"); + } catch (NoSuchAlgorithmException nae) { + testEC = false; + } + if (testEC) t.v3extTest("EC"); } if (System.getProperty("nss") != null) { diff --git a/jdk/test/sun/security/tools/keytool/NoExtNPE.sh b/jdk/test/sun/security/tools/keytool/NoExtNPE.sh new file mode 100644 index 00000000000..3e929b5354f --- /dev/null +++ b/jdk/test/sun/security/tools/keytool/NoExtNPE.sh @@ -0,0 +1,65 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 6813402 +# @summary keytool cannot -printcert entries without extensions +# +# @run shell NoExtNPE.sh + +# set a few environment variables so that the shell-script can run stand-alone +# in the source directory +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi + +if [ "${TESTJAVA}" = "" ] ; then + echo "TESTJAVA not set. Test cannot execute." + echo "FAILED!!!" + exit 1 +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + SunOS ) + FILESEP="/" + ;; + Linux ) + FILESEP="/" + ;; + Windows* ) + FILESEP="\\" + ;; + * ) + echo "Unrecognized system!" + exit 1; + ;; +esac + +${TESTJAVA}${FILESEP}bin${FILESEP}keytool \ + -list -v \ + -keystore ${TESTSRC}${FILESEP}CloneKeyAskPassword.jks \ + -storepass test123 + +exit $? diff --git a/jdk/test/sun/security/tools/keytool/autotest.sh b/jdk/test/sun/security/tools/keytool/autotest.sh index 04c00c14ebf..e3431836b1a 100644 --- a/jdk/test/sun/security/tools/keytool/autotest.sh +++ b/jdk/test/sun/security/tools/keytool/autotest.sh @@ -1,5 +1,5 @@ # -# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ # @summary (almost) all keytool behaviors # @author Weijun Wang # +# This test is only executed on several platforms +# # set a few environment variables so that the shell-script can run stand-alone # in the source directory if [ "${TESTSRC}" = "" ] ; then @@ -88,7 +90,7 @@ cp ${NSS}${FS}db${FS}secmod.db . chmod u+w key3.db chmod u+w cert8.db -echo | ${TESTJAVA}${FS}bin${FS}java -Dfile -Dnss \ +echo | ${TESTJAVA}${FS}bin${FS}java -Dnss \ -Dnss.lib=${NSS}${FS}lib${FS}${PF}${FS}${LIBNAME} \ KeyToolTest status=$? @@ -99,8 +101,8 @@ rm -f key3.db rm -f secmod.db rm HumanInputStream*.class -rm KeyToolTest.class -rm TestException.class +rm KeyToolTest*.class +rm TestException.class exit $status diff --git a/jdk/test/sun/security/tools/keytool/importreadall.sh b/jdk/test/sun/security/tools/keytool/importreadall.sh new file mode 100644 index 00000000000..6c0c65dedc7 --- /dev/null +++ b/jdk/test/sun/security/tools/keytool/importreadall.sh @@ -0,0 +1,62 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 6819272 +# @summary keytool -importcert should read the whole input +# +# @run shell importreadall.sh + +# set a few environment variables so that the shell-script can run stand-alone +# in the source directory +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi + +if [ "${TESTJAVA}" = "" ] ; then + JAVA_CMD=`which java` + TESTJAVA=`dirname $JAVA_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +KEYTOOL="${TESTJAVA}${FS}bin${FS}keytool -keystore importreadall.jks -storepass changeit -keypass changeit" + +# In case the test is run twice in the same directory + +$KEYTOOL -delete -alias a +$KEYTOOL -delete -alias ca +$KEYTOOL -genkeypair -alias a -dname CN=a || exit 1 +$KEYTOOL -genkeypair -alias ca -dname CN=ca || exit 2 +$KEYTOOL -certreq -alias a | $KEYTOOL -gencert -alias ca | $KEYTOOL -importcert -alias a + +exit $? diff --git a/jdk/test/sun/security/tools/keytool/selfissued.sh b/jdk/test/sun/security/tools/keytool/selfissued.sh new file mode 100644 index 00000000000..e6e06c040b3 --- /dev/null +++ b/jdk/test/sun/security/tools/keytool/selfissued.sh @@ -0,0 +1,69 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 6825352 +# @summary support self-issued certificate in keytool +# +# @run shell selfissued.sh +# + +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +KS=selfsigned.jks +KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore $KS" + +rm $KS + +$KT -alias ca -dname CN=CA -genkeypair +$KT -alias me -dname CN=CA -genkeypair +$KT -alias e1 -dname CN=E1 -genkeypair +$KT -alias e2 -dname CN=E2 -genkeypair + +# me signed by ca, self-issued +$KT -alias me -certreq | $KT -alias ca -gencert | $KT -alias me -importcert + +# Import e1 signed by me, should add me and ca +$KT -alias e1 -certreq | $KT -alias me -gencert | $KT -alias e1 -importcert +$KT -alias e1 -list -v | grep '\[3\]' || { echo Bad E1; exit 1; } + +# Import (e2 signed by me,ca,me), should reorder to (e2,me,ca) +( $KT -alias e2 -certreq | $KT -alias me -gencert; $KT -exportcert -alias ca; $KT -exportcert -alias me ) | $KT -alias e2 -importcert +$KT -alias e2 -list -v | grep '\[3\]' || { echo Bad E2; exit 1; } + +echo Good + diff --git a/jdk/test/sun/security/tools/keytool/standard.sh b/jdk/test/sun/security/tools/keytool/standard.sh new file mode 100644 index 00000000000..fe4a0a81312 --- /dev/null +++ b/jdk/test/sun/security/tools/keytool/standard.sh @@ -0,0 +1,64 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @summary (almost) all keytool behaviors +# @author Weijun Wang +# +# This test is always excecuted. +# +# set a few environment variables so that the shell-script can run stand-alone +# in the source directory +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi +if [ "${TESTCLASSES}" = "" ] ; then + TESTCLASSES="." +fi +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}KeyToolTest.java || exit 10 + +echo | ${TESTJAVA}${FS}bin${FS}java -Dfile KeyToolTest +status=$? + +rm HumanInputStream*.class +rm KeyToolTest*.class +rm TestException.class + +exit $status + diff --git a/jdk/test/sun/security/util/DerValue/EmptyValue.java b/jdk/test/sun/security/util/DerValue/EmptyValue.java new file mode 100644 index 00000000000..b2803802957 --- /dev/null +++ b/jdk/test/sun/security/util/DerValue/EmptyValue.java @@ -0,0 +1,44 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6804045 + * @summary DerValue does not accept empty OCTET STRING + */ + +import sun.security.util.DerValue; + +public class EmptyValue { + + public static void main(String[] args) throws Exception { + DerValue v = new DerValue(new byte[]{4,0}); + if (v.getOctetString().length != 0) { + throw new Exception("Get octet string error"); + } + v = new DerValue(new byte[]{0x30,0}); + if (v.data.available() != 0) { + throw new Exception("Get sequence error"); + } + } +} diff --git a/jdk/test/sun/security/x509/Extensions/BCNull.java b/jdk/test/sun/security/x509/Extensions/BCNull.java new file mode 100644 index 00000000000..e906f576992 --- /dev/null +++ b/jdk/test/sun/security/x509/Extensions/BCNull.java @@ -0,0 +1,37 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @summary BasicConstraintsExtension does not encode when (ca==false && pathLen<0) + * @bug 6803376 + */ + +import sun.security.x509.BasicConstraintsExtension; +import java.io.ByteArrayOutputStream; + +public class BCNull { + public static void main(String [] args) throws Exception { + new BasicConstraintsExtension(false, -1).encode(new ByteArrayOutputStream()); + } +} diff --git a/langtools/.hgtags b/langtools/.hgtags index e2051a0b816..a722b1033a1 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -23,3 +23,9 @@ e2f8f6daee9decd5721d598dacf4d0b5915651df jdk7-b43 be546a6c08e3c31fba2edcae1de43ae3515d2e59 jdk7-b46 2b8f6bab23926aa32b9cf7e4c540b9d1ce74b7d5 jdk7-b47 c53007f34195f69223bdd4125ec6c0740f7d6736 jdk7-b48 +d17d927ad9bdfafae32451645d182acb7bed7be6 jdk7-b49 +46f2f6ed96f13fc49fec3d1b6aa616686128cb57 jdk7-b50 +8c55d5b0ed71ed3a749eb97e4eab79b4831649b8 jdk7-b51 +29329051d483d39f66073752ba4afbf29d893cfe jdk7-b52 +dbdeb4a7581b2a8699644b91cae6793cb01953f7 jdk7-b53 +197a7f881937d406a01214aa9ded49c073f7d380 jdk7-b54 diff --git a/langtools/make/build.properties b/langtools/make/build.properties index 6e792bb106d..1f3b7c2e406 100644 --- a/langtools/make/build.properties +++ b/langtools/make/build.properties @@ -1,5 +1,5 @@ # -# Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/langtools/make/build.xml b/langtools/make/build.xml index 770f3dd040c..932332d295a 100644 --- a/langtools/make/build.xml +++ b/langtools/make/build.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. This code is free software; you can redistribute it and/or modify it diff --git a/langtools/make/jprt.config b/langtools/make/jprt.config deleted file mode 100644 index b112bcb1eda..00000000000 --- a/langtools/make/jprt.config +++ /dev/null @@ -1,241 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# Windows Only: -# PATH -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# -# Output environment variables: -# PATH -# Windows Only: -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Add basic solaris system paths - path4sdk=/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Add basic paths - path4sdk=/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk="${antbindir};${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - diff --git a/langtools/make/netbeans/langtools/build.xml b/langtools/make/netbeans/langtools/build.xml index 8f2b95f3031..790ded56d77 100644 --- a/langtools/make/netbeans/langtools/build.xml +++ b/langtools/make/netbeans/langtools/build.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/langtools/make/netbeans/langtools/nbproject/project.xml b/langtools/make/netbeans/langtools/nbproject/project.xml index e7509600556..2f6bd544c0c 100644 --- a/langtools/make/netbeans/langtools/nbproject/project.xml +++ b/langtools/make/netbeans/langtools/nbproject/project.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/langtools/make/netbeans/langtools/nbproject/standard-context-menu-items.ent b/langtools/make/netbeans/langtools/nbproject/standard-context-menu-items.ent index ab0568a009d..cd77a187ed9 100644 --- a/langtools/make/netbeans/langtools/nbproject/standard-context-menu-items.ent +++ b/langtools/make/netbeans/langtools/nbproject/standard-context-menu-items.ent @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/langtools/make/netbeans/langtools/nbproject/standard-ide-actions.ent b/langtools/make/netbeans/langtools/nbproject/standard-ide-actions.ent index 3081fdfcdf0..7369581bb18 100644 --- a/langtools/make/netbeans/langtools/nbproject/standard-ide-actions.ent +++ b/langtools/make/netbeans/langtools/nbproject/standard-ide-actions.ent @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/langtools/make/tools/SelectTool/SelectToolTask.java b/langtools/make/tools/SelectTool/SelectToolTask.java index 0646c306e8a..cc4e1212127 100644 --- a/langtools/make/tools/SelectTool/SelectToolTask.java +++ b/langtools/make/tools/SelectTool/SelectToolTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/apt/comp/AnnotationProcessingError.java b/langtools/src/share/classes/com/sun/tools/apt/comp/AnnotationProcessingError.java index f14dc60e6e3..87510a56791 100644 --- a/langtools/src/share/classes/com/sun/tools/apt/comp/AnnotationProcessingError.java +++ b/langtools/src/share/classes/com/sun/tools/apt/comp/AnnotationProcessingError.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/apt/comp/Apt.java b/langtools/src/share/classes/com/sun/tools/apt/comp/Apt.java index d01887b6888..68d5a458a66 100644 --- a/langtools/src/share/classes/com/sun/tools/apt/comp/Apt.java +++ b/langtools/src/share/classes/com/sun/tools/apt/comp/Apt.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/apt/comp/UsageMessageNeededException.java b/langtools/src/share/classes/com/sun/tools/apt/comp/UsageMessageNeededException.java index 64a83ddb2c4..9d0de2ed918 100644 --- a/langtools/src/share/classes/com/sun/tools/apt/comp/UsageMessageNeededException.java +++ b/langtools/src/share/classes/com/sun/tools/apt/comp/UsageMessageNeededException.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java b/langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java index 433a7dedf51..219cd8acb09 100644 --- a/langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java +++ b/langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/apt/mirror/apt/RoundCompleteEventImpl.java b/langtools/src/share/classes/com/sun/tools/apt/mirror/apt/RoundCompleteEventImpl.java index 403ea6ffb51..4a4988af516 100644 --- a/langtools/src/share/classes/com/sun/tools/apt/mirror/apt/RoundCompleteEventImpl.java +++ b/langtools/src/share/classes/com/sun/tools/apt/mirror/apt/RoundCompleteEventImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/apt/mirror/declaration/AnnotationProxyMaker.java b/langtools/src/share/classes/com/sun/tools/apt/mirror/declaration/AnnotationProxyMaker.java index 9505eb2230d..40eb0d68e12 100644 --- a/langtools/src/share/classes/com/sun/tools/apt/mirror/declaration/AnnotationProxyMaker.java +++ b/langtools/src/share/classes/com/sun/tools/apt/mirror/declaration/AnnotationProxyMaker.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/apt/mirror/type/TypeVariableImpl.java b/langtools/src/share/classes/com/sun/tools/apt/mirror/type/TypeVariableImpl.java index 3d6a9fcaa80..9e65c82f8e8 100644 --- a/langtools/src/share/classes/com/sun/tools/apt/mirror/type/TypeVariableImpl.java +++ b/langtools/src/share/classes/com/sun/tools/apt/mirror/type/TypeVariableImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Annotation.java b/langtools/src/share/classes/com/sun/tools/classfile/Annotation.java index 37423cacc67..8078365bae7 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/Annotation.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/Annotation.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/classfile/AttributeException.java b/langtools/src/share/classes/com/sun/tools/classfile/AttributeException.java index 55d23f9c63b..62ab6289a28 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/AttributeException.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/AttributeException.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Code_attribute.java b/langtools/src/share/classes/com/sun/tools/classfile/Code_attribute.java index ce99e119ade..af1b9fceb69 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/Code_attribute.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/Code_attribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,8 @@ package com.sun.tools.classfile; import java.io.IOException; +import java.util.Iterator; +import java.util.NoSuchElementException; /** * See JVMS3, section 4.8.3. @@ -100,6 +102,39 @@ public class Code_attribute extends Attribute { return visitor.visitCode(this, data); } + public Iterable<Instruction> getInstructions() { + return new Iterable<Instruction>() { + public Iterator<Instruction> iterator() { + return new Iterator<Instruction>() { + + public boolean hasNext() { + return (next != null); + } + + public Instruction next() { + if (next == null) + throw new NoSuchElementException(); + + current = next; + pc += current.length(); + next = (pc < code.length ? new Instruction(code, pc) : null); + return current; + } + + public void remove() { + throw new UnsupportedOperationException("Not supported."); + } + + Instruction current = null; + int pc = 0; + Instruction next = new Instruction(code, pc); + + }; + } + + }; + } + public final int max_stack; public final int max_locals; public final int code_length; diff --git a/langtools/src/share/classes/com/sun/tools/classfile/ConstantPool.java b/langtools/src/share/classes/com/sun/tools/classfile/ConstantPool.java index b9acd9640d9..95ac3442671 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/ConstantPool.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/classfile/ConstantPoolException.java b/langtools/src/share/classes/com/sun/tools/classfile/ConstantPoolException.java index 31d3473e6ca..a55ce37170e 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/ConstantPoolException.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/ConstantPoolException.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Descriptor.java b/langtools/src/share/classes/com/sun/tools/classfile/Descriptor.java index e446955399f..9dcdb299036 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/Descriptor.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/Descriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/classfile/DescriptorException.java b/langtools/src/share/classes/com/sun/tools/classfile/DescriptorException.java index fad9a2ff361..32a66ae8d7f 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/DescriptorException.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/DescriptorException.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java b/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java new file mode 100644 index 00000000000..c0a30ba2755 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java @@ -0,0 +1,339 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.classfile; + +/** + * See JVMS3, chapter 6. + * + * <p><b>This is NOT part of any API supported by Sun Microsystems. If + * you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + * + * @see Code_attribute#getInstructions + */ +public class Instruction { + /** The kind of an instruction, as determined by the position, size and + * types of its operands. */ + public static enum Kind { + /** Opcode is not followed by any operands. */ + NO_OPERANDS(1), + /** Opcode is followed by a byte indicating a type. */ + ATYPE(2), + /** Opcode is followed by a 2-byte branch offset. */ + BRANCH(3), + /** Opcode is followed by a 4-byte branch offset. */ + BRANCH_W(5), + /** Opcode is followed by a signed byte value. */ + BYTE(2), + /** Opcode is followed by a 1-byte index into the constant pool. */ + CPREF(2), + /** Opcode is followed by a 2-byte index into the constant pool. */ + CPREF_W(3), + /** Opcode is followed by a 2-byte index into the constant pool, + * an unsigned byte value. */ + CPREF_W_UBYTE(4), + /** Opcode is followed by a 2-byte index into the constant pool., + * an unsigned byte value, and a zero byte. */ + CPREF_W_UBYTE_ZERO(5), + /** Opcode is followed by variable number of operands, depending + * on the instruction.*/ + DYNAMIC(-1), + /** Opcode is followed by a 1-byte reference to a local variable. */ + LOCAL(2), + /** Opcode is followed by a 1-byte reference to a local variable, + * and a signed byte value. */ + LOCAL_BYTE(3), + /** Opcode is followed by a signed short value. */ + SHORT(3), + /** Wide opcode is not followed by any operands. */ + WIDE_NO_OPERANDS(2), + /** Wide opcode is followed by a 2-byte index into the constant pool. */ + WIDE_CPREF_W(4), + /** Wide opcode is followed by a 2-byte index into the constant pool, + * and a signed short value. */ + WIDE_CPREF_W_SHORT(6), + /** Opcode was not recognized. */ + UNKNOWN(1); + + Kind(int length) { + this.length = length; + } + + /** The length, in bytes, of this kind of instruction, or -1 is the + * length depends on the specific instruction. */ + public final int length; + }; + + /** A utility visitor to help decode the operands of an instruction. + * @see Instruction#accept */ + public interface KindVisitor<R,P> { + /** See {@link Kind#NO_OPERANDS}, {@link Kind#WIDE_NO_OPERANDS}. */ + R visitNoOperands(Instruction instr, P p); + /** See {@link Kind#ATYPE}. */ + R visitArrayType(Instruction instr, TypeKind kind, P p); + /** See {@link Kind#BRANCH}, {@link Kind#BRANCH_W}. */ + R visitBranch(Instruction instr, int offset, P p); + /** See {@link Kind#CPREF}, {@link Kind#CPREF_W}, {@link Kind#WIDE_CPREF_W}. */ + R visitConstantPoolRef(Instruction instr, int index, P p); + /** See {@link Kind#CPREF_W_UBYTE}, {@link Kind#CPREF_W_UBYTE_ZERO}, {@link Kind#WIDE_CPREF_W_SHORT}. */ + R visitConstantPoolRefAndValue(Instruction instr, int index, int value, P p); + /** See {@link Kind#LOCAL}. */ + R visitLocal(Instruction instr, int index, P p); + /** See {@link Kind#LOCAL_UBYTE}. */ + R visitLocalAndValue(Instruction instr, int index, int value, P p); + /** See {@link Kind#DYNAMIC}. */ + R visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets); + /** See {@link Kind#DYNAMIC}. */ + R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets); + /** See {@link Kind#BYTE}, {@link Kind#SHORT}. */ + R visitValue(Instruction instr, int value, P p); + /** Instruction is unrecognized. */ + R visitUnknown(Instruction instr, P p); + + } + + /** The kind of primitive array type to create. + * See JVMS chapter 6, newarray. */ + public static enum TypeKind { + T_BOOLEAN(4, "boolean"), + T_CHAR(5, "char"), + T_FLOAT(6, "float"), + T_DOUBLE(7, "double"), + T_BYTE(8, "byte"), + T_SHORT(9, "short"), + T_INT (10, "int"), + T_LONG (11, "long"); + TypeKind(int value, String name) { + this.value = value; + this.name = name; + } + + public static TypeKind get(int value) { + switch (value) { + case 4: return T_BOOLEAN; + case 5: return T_CHAR; + case 6: return T_FLOAT; + case 7: return T_DOUBLE; + case 8: return T_BYTE; + case 9: return T_SHORT; + case 10: return T_INT; + case 11: return T_LONG; + default: return null; + } + } + + public final int value; + public final String name; + } + + /** An instruction is defined by its position in a bytecode array. */ + public Instruction(byte[] bytes, int pc) { + this.bytes = bytes; + this.pc = pc; + } + + /** Get the position of the instruction within the bytecode array. */ + public int getPC() { + return pc; + } + + /** Get a byte value, relative to the start of this instruction. */ + public int getByte(int offset) { + return bytes[pc + offset]; + } + + /** Get an unsigned byte value, relative to the start of this instruction. */ + public int getUnsignedByte(int offset) { + return getByte(offset) & 0xff; + } + + /** Get a 2-byte value, relative to the start of this instruction. */ + public int getShort(int offset) { + return (getByte(offset) << 8) | getUnsignedByte(offset + 1); + } + + /** Get a unsigned 2-byte value, relative to the start of this instruction. */ + public int getUnsignedShort(int offset) { + return getShort(offset) & 0xFFFF; + } + + /** Get a 4-byte value, relative to the start of this instruction. */ + public int getInt(int offset) { + return (getShort(offset) << 16) | (getUnsignedShort(offset + 2)); + } + + /** Get the Opcode for this instruction, or null if the instruction is + * unrecognized. */ + public Opcode getOpcode() { + int b = getUnsignedByte(0); + switch (b) { + case Opcode.NONPRIV: + case Opcode.PRIV: + case Opcode.WIDE: + return Opcode.get(b, getUnsignedByte(1)); + } + return Opcode.get(b); + } + + /** Get the mnemonic for this instruction, or a default string if the + * instruction is unrecognized. */ + public String getMnemonic() { + Opcode opcode = getOpcode(); + if (opcode == null) + return "bytecode " + getUnsignedByte(0); + else + return opcode.toString().toLowerCase(); + } + + /** Get the length, in bytes, of this instruction, including the opcode + * and all its operands. */ + public int length() { + Opcode opcode = getOpcode(); + if (opcode == null) + return 1; + + switch (opcode) { + case TABLESWITCH: { + int pad = align(pc + 1) - pc; + int low = getInt(pad + 4); + int high = getInt(pad + 8); + return pad + 12 + 4 * (high - low + 1); + } + case LOOKUPSWITCH: { + int pad = align(pc + 1) - pc; + int npairs = getInt(pad + 4); + return pad + 8 + 8 * npairs; + + } + default: + return opcode.kind.length; + } + } + + /** Get the {@link Kind} of this instruction. */ + public Kind getKind() { + Opcode opcode = getOpcode(); + return (opcode != null ? opcode.kind : Kind.UNKNOWN); + } + + /** Invoke a method on the visitor according to the kind of this + * instruction, passing in the decoded operands for the instruction. */ + public <R,P> R accept(KindVisitor<R,P> visitor, P p) { + switch (getKind()) { + case NO_OPERANDS: + return visitor.visitNoOperands(this, p); + + case ATYPE: + return visitor.visitArrayType( + this, TypeKind.get(getUnsignedByte(1)), p); + + case BRANCH: + return visitor.visitBranch(this, getShort(1), p); + + case BRANCH_W: + return visitor.visitBranch(this, getInt(1), p); + + case BYTE: + return visitor.visitValue(this, getByte(1), p); + + case CPREF: + return visitor.visitConstantPoolRef(this, getUnsignedByte(1), p); + + case CPREF_W: + return visitor.visitConstantPoolRef(this, getUnsignedShort(1), p); + + case CPREF_W_UBYTE: + case CPREF_W_UBYTE_ZERO: + return visitor.visitConstantPoolRefAndValue( + this, getUnsignedShort(1), getUnsignedByte(3), p); + + case DYNAMIC: { + switch (getOpcode()) { + case TABLESWITCH: { + int pad = align(pc + 1) - pc; + int default_ = getInt(pad); + int low = getInt(pad + 4); + int high = getInt(pad + 8); + int[] values = new int[high - low + 1]; + for (int i = 0; i < values.length; i++) + values[i] = getInt(pad + 12 + 4 * i); + return visitor.visitTableSwitch( + this, default_, low, high, values); + } + case LOOKUPSWITCH: { + int pad = align(pc + 1) - pc; + int default_ = getInt(pad); + int npairs = getInt(pad + 4); + int[] matches = new int[npairs]; + int[] offsets = new int[npairs]; + for (int i = 0; i < npairs; i++) { + matches[i] = getInt(pad + 8 + i * 8); + offsets[i] = getInt(pad + 12 + i * 8); + } + return visitor.visitLookupSwitch( + this, default_, npairs, matches, offsets); + } + default: + throw new IllegalStateException(); + } + } + + case LOCAL: + return visitor.visitLocal(this, getUnsignedByte(1), p); + + case LOCAL_BYTE: + return visitor.visitLocalAndValue( + this, getUnsignedByte(1), getByte(2), p); + + case SHORT: + return visitor.visitValue(this, getShort(1), p); + + case WIDE_NO_OPERANDS: + return visitor.visitNoOperands(this, p); + + case WIDE_CPREF_W: + return visitor.visitConstantPoolRef(this, getUnsignedShort(2), p); + + case WIDE_CPREF_W_SHORT: + return visitor.visitConstantPoolRefAndValue( + this, getUnsignedShort(2), getUnsignedByte(4), p); + + case UNKNOWN: + return visitor.visitUnknown(this, p); + + default: + throw new IllegalStateException(); + } + } + + private static int align(int n) { + return (n + 3) & ~3; + } + + private byte[] bytes; + private int pc; +} diff --git a/langtools/src/share/classes/com/sun/tools/classfile/OpCodes.java b/langtools/src/share/classes/com/sun/tools/classfile/OpCodes.java deleted file mode 100644 index 12fa7fbedf8..00000000000 --- a/langtools/src/share/classes/com/sun/tools/classfile/OpCodes.java +++ /dev/null @@ -1,868 +0,0 @@ -/* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -package com.sun.tools.classfile; - -import java.util.HashMap; - -/** - * See JVMS3, section 6. - * - * <p><b>This is NOT part of any API supported by Sun Microsystems. If - * you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice.</b> - */ -public class OpCodes { - - public static int opcLength(int opc) throws IllegalArgumentException { - switch (opc >> 8) { - case 0: - return opcLengthsTab[opc]; - case opc_wide: - switch (opc & 0xFF) { - case opc_aload: - case opc_astore: - case opc_fload: - case opc_fstore: - case opc_iload: - case opc_istore: - case opc_lload: - case opc_lstore: - case opc_dload: - case opc_dstore: - case opc_ret: - return 4; - case opc_iinc: - return 6; - default: - throw new IllegalArgumentException(); - } - case opc_nonpriv: - case opc_priv: - return 2; - default: - throw new IllegalArgumentException(); - } - } - - public static String opcName(int opc) { - try { - switch (opc >> 8) { - case 0: - return opcNamesTab[opc]; - case opc_wide: - { - String mnem = opcNamesTab[opc & 0xFF] + "_w"; - if (mnemocodes.get(mnem) == null) { - return null; // non-existent opcode - } - return mnem; - } - case opc_nonpriv: - return opcExtNamesTab[opc & 0xFF]; - case opc_priv: - return opcPrivExtNamesTab[opc & 0xFF]; - default: - return null; - } - } catch (ArrayIndexOutOfBoundsException e) { - switch (opc) { - case opc_nonpriv: - return "nonpriv"; - case opc_priv: - return "priv"; - default: - return null; - } - } - } - - /* Opcodes */ - public static final int opc_dead = -2; - public static final int opc_label = -1; - public static final int opc_nop = 0; - public static final int opc_aconst_null = 1; - public static final int opc_iconst_m1 = 2; - public static final int opc_iconst_0 = 3; - public static final int opc_iconst_1 = 4; - public static final int opc_iconst_2 = 5; - public static final int opc_iconst_3 = 6; - public static final int opc_iconst_4 = 7; - public static final int opc_iconst_5 = 8; - public static final int opc_lconst_0 = 9; - public static final int opc_lconst_1 = 10; - public static final int opc_fconst_0 = 11; - public static final int opc_fconst_1 = 12; - public static final int opc_fconst_2 = 13; - public static final int opc_dconst_0 = 14; - public static final int opc_dconst_1 = 15; - public static final int opc_bipush = 16; - public static final int opc_sipush = 17; - public static final int opc_ldc = 18; - public static final int opc_ldc_w = 19; - public static final int opc_ldc2_w = 20; - public static final int opc_iload = 21; - public static final int opc_lload = 22; - public static final int opc_fload = 23; - public static final int opc_dload = 24; - public static final int opc_aload = 25; - public static final int opc_iload_0 = 26; - public static final int opc_iload_1 = 27; - public static final int opc_iload_2 = 28; - public static final int opc_iload_3 = 29; - public static final int opc_lload_0 = 30; - public static final int opc_lload_1 = 31; - public static final int opc_lload_2 = 32; - public static final int opc_lload_3 = 33; - public static final int opc_fload_0 = 34; - public static final int opc_fload_1 = 35; - public static final int opc_fload_2 = 36; - public static final int opc_fload_3 = 37; - public static final int opc_dload_0 = 38; - public static final int opc_dload_1 = 39; - public static final int opc_dload_2 = 40; - public static final int opc_dload_3 = 41; - public static final int opc_aload_0 = 42; - public static final int opc_aload_1 = 43; - public static final int opc_aload_2 = 44; - public static final int opc_aload_3 = 45; - public static final int opc_iaload = 46; - public static final int opc_laload = 47; - public static final int opc_faload = 48; - public static final int opc_daload = 49; - public static final int opc_aaload = 50; - public static final int opc_baload = 51; - public static final int opc_caload = 52; - public static final int opc_saload = 53; - public static final int opc_istore = 54; - public static final int opc_lstore = 55; - public static final int opc_fstore = 56; - public static final int opc_dstore = 57; - public static final int opc_astore = 58; - public static final int opc_istore_0 = 59; - public static final int opc_istore_1 = 60; - public static final int opc_istore_2 = 61; - public static final int opc_istore_3 = 62; - public static final int opc_lstore_0 = 63; - public static final int opc_lstore_1 = 64; - public static final int opc_lstore_2 = 65; - public static final int opc_lstore_3 = 66; - public static final int opc_fstore_0 = 67; - public static final int opc_fstore_1 = 68; - public static final int opc_fstore_2 = 69; - public static final int opc_fstore_3 = 70; - public static final int opc_dstore_0 = 71; - public static final int opc_dstore_1 = 72; - public static final int opc_dstore_2 = 73; - public static final int opc_dstore_3 = 74; - public static final int opc_astore_0 = 75; - public static final int opc_astore_1 = 76; - public static final int opc_astore_2 = 77; - public static final int opc_astore_3 = 78; - public static final int opc_iastore = 79; - public static final int opc_lastore = 80; - public static final int opc_fastore = 81; - public static final int opc_dastore = 82; - public static final int opc_aastore = 83; - public static final int opc_bastore = 84; - public static final int opc_castore = 85; - public static final int opc_sastore = 86; - public static final int opc_pop = 87; - public static final int opc_pop2 = 88; - public static final int opc_dup = 89; - public static final int opc_dup_x1 = 90; - public static final int opc_dup_x2 = 91; - public static final int opc_dup2 = 92; - public static final int opc_dup2_x1 = 93; - public static final int opc_dup2_x2 = 94; - public static final int opc_swap = 95; - public static final int opc_iadd = 96; - public static final int opc_ladd = 97; - public static final int opc_fadd = 98; - public static final int opc_dadd = 99; - public static final int opc_isub = 100; - public static final int opc_lsub = 101; - public static final int opc_fsub = 102; - public static final int opc_dsub = 103; - public static final int opc_imul = 104; - public static final int opc_lmul = 105; - public static final int opc_fmul = 106; - public static final int opc_dmul = 107; - public static final int opc_idiv = 108; - public static final int opc_ldiv = 109; - public static final int opc_fdiv = 110; - public static final int opc_ddiv = 111; - public static final int opc_irem = 112; - public static final int opc_lrem = 113; - public static final int opc_frem = 114; - public static final int opc_drem = 115; - public static final int opc_ineg = 116; - public static final int opc_lneg = 117; - public static final int opc_fneg = 118; - public static final int opc_dneg = 119; - public static final int opc_ishl = 120; - public static final int opc_lshl = 121; - public static final int opc_ishr = 122; - public static final int opc_lshr = 123; - public static final int opc_iushr = 124; - public static final int opc_lushr = 125; - public static final int opc_iand = 126; - public static final int opc_land = 127; - public static final int opc_ior = 128; - public static final int opc_lor = 129; - public static final int opc_ixor = 130; - public static final int opc_lxor = 131; - public static final int opc_iinc = 132; - public static final int opc_i2l = 133; - public static final int opc_i2f = 134; - public static final int opc_i2d = 135; - public static final int opc_l2i = 136; - public static final int opc_l2f = 137; - public static final int opc_l2d = 138; - public static final int opc_f2i = 139; - public static final int opc_f2l = 140; - public static final int opc_f2d = 141; - public static final int opc_d2i = 142; - public static final int opc_d2l = 143; - public static final int opc_d2f = 144; - public static final int opc_i2b = 145; - public static final int opc_int2byte = 145; - public static final int opc_i2c = 146; - public static final int opc_int2char = 146; - public static final int opc_i2s = 147; - public static final int opc_int2short = 147; - public static final int opc_lcmp = 148; - public static final int opc_fcmpl = 149; - public static final int opc_fcmpg = 150; - public static final int opc_dcmpl = 151; - public static final int opc_dcmpg = 152; - public static final int opc_ifeq = 153; - public static final int opc_ifne = 154; - public static final int opc_iflt = 155; - public static final int opc_ifge = 156; - public static final int opc_ifgt = 157; - public static final int opc_ifle = 158; - public static final int opc_if_icmpeq = 159; - public static final int opc_if_icmpne = 160; - public static final int opc_if_icmplt = 161; - public static final int opc_if_icmpge = 162; - public static final int opc_if_icmpgt = 163; - public static final int opc_if_icmple = 164; - public static final int opc_if_acmpeq = 165; - public static final int opc_if_acmpne = 166; - public static final int opc_goto = 167; - public static final int opc_jsr = 168; - public static final int opc_ret = 169; - public static final int opc_tableswitch = 170; - public static final int opc_lookupswitch = 171; - public static final int opc_ireturn = 172; - public static final int opc_lreturn = 173; - public static final int opc_freturn = 174; - public static final int opc_dreturn = 175; - public static final int opc_areturn = 176; - public static final int opc_return = 177; - public static final int opc_getstatic = 178; - public static final int opc_putstatic = 179; - public static final int opc_getfield = 180; - public static final int opc_putfield = 181; - public static final int opc_invokevirtual = 182; - public static final int opc_invokenonvirtual = 183; - public static final int opc_invokespecial = 183; - public static final int opc_invokestatic = 184; - public static final int opc_invokeinterface = 185; -// public static final int opc_xxxunusedxxx = 186; - public static final int opc_new = 187; - public static final int opc_newarray = 188; - public static final int opc_anewarray = 189; - public static final int opc_arraylength = 190; - public static final int opc_athrow = 191; - public static final int opc_checkcast = 192; - public static final int opc_instanceof = 193; - public static final int opc_monitorenter = 194; - public static final int opc_monitorexit = 195; - public static final int opc_wide = 196; - public static final int opc_multianewarray = 197; - public static final int opc_ifnull = 198; - public static final int opc_ifnonnull = 199; - public static final int opc_goto_w = 200; - public static final int opc_jsr_w = 201; - - /* Pseudo-instructions */ - public static final int opc_bytecode = 203; - public static final int opc_try = 204; - public static final int opc_endtry = 205; - public static final int opc_catch = 206; - public static final int opc_var = 207; - public static final int opc_endvar = 208; - public static final int opc_localsmap = 209; - public static final int opc_stackmap = 210; - - /* PicoJava prefixes */ - public static final int opc_nonpriv = 254; - public static final int opc_priv = 255; - - /* Wide instructions */ - public static final int opc_iload_w = (opc_wide << 8 ) | opc_iload; - public static final int opc_lload_w = (opc_wide << 8 ) | opc_lload; - public static final int opc_fload_w = (opc_wide << 8 ) | opc_fload; - public static final int opc_dload_w = (opc_wide << 8 ) | opc_dload; - public static final int opc_aload_w = (opc_wide << 8 ) | opc_aload; - public static final int opc_istore_w = (opc_wide << 8 ) | opc_istore; - public static final int opc_lstore_w = (opc_wide << 8 ) | opc_lstore; - public static final int opc_fstore_w = (opc_wide << 8 ) | opc_fstore; - public static final int opc_dstore_w = (opc_wide << 8 ) | opc_dstore; - public static final int opc_astore_w = (opc_wide << 8 ) | opc_astore; - public static final int opc_ret_w = (opc_wide << 8 ) | opc_ret; - public static final int opc_iinc_w = (opc_wide << 8 ) | opc_iinc; - - /* Opcode Names */ - private static final String opcNamesTab[] = { - "nop", - "aconst_null", - "iconst_m1", - "iconst_0", - "iconst_1", - "iconst_2", - "iconst_3", - "iconst_4", - "iconst_5", - "lconst_0", - "lconst_1", - "fconst_0", - "fconst_1", - "fconst_2", - "dconst_0", - "dconst_1", - "bipush", - "sipush", - "ldc", - "ldc_w", - "ldc2_w", - "iload", - "lload", - "fload", - "dload", - "aload", - "iload_0", - "iload_1", - "iload_2", - "iload_3", - "lload_0", - "lload_1", - "lload_2", - "lload_3", - "fload_0", - "fload_1", - "fload_2", - "fload_3", - "dload_0", - "dload_1", - "dload_2", - "dload_3", - "aload_0", - "aload_1", - "aload_2", - "aload_3", - "iaload", - "laload", - "faload", - "daload", - "aaload", - "baload", - "caload", - "saload", - "istore", - "lstore", - "fstore", - "dstore", - "astore", - "istore_0", - "istore_1", - "istore_2", - "istore_3", - "lstore_0", - "lstore_1", - "lstore_2", - "lstore_3", - "fstore_0", - "fstore_1", - "fstore_2", - "fstore_3", - "dstore_0", - "dstore_1", - "dstore_2", - "dstore_3", - "astore_0", - "astore_1", - "astore_2", - "astore_3", - "iastore", - "lastore", - "fastore", - "dastore", - "aastore", - "bastore", - "castore", - "sastore", - "pop", - "pop2", - "dup", - "dup_x1", - "dup_x2", - "dup2", - "dup2_x1", - "dup2_x2", - "swap", - "iadd", - "ladd", - "fadd", - "dadd", - "isub", - "lsub", - "fsub", - "dsub", - "imul", - "lmul", - "fmul", - "dmul", - "idiv", - "ldiv", - "fdiv", - "ddiv", - "irem", - "lrem", - "frem", - "drem", - "ineg", - "lneg", - "fneg", - "dneg", - "ishl", - "lshl", - "ishr", - "lshr", - "iushr", - "lushr", - "iand", - "land", - "ior", - "lor", - "ixor", - "lxor", - "iinc", - "i2l", - "i2f", - "i2d", - "l2i", - "l2f", - "l2d", - "f2i", - "f2l", - "f2d", - "d2i", - "d2l", - "d2f", - "i2b", - "i2c", - "i2s", - "lcmp", - "fcmpl", - "fcmpg", - "dcmpl", - "dcmpg", - "ifeq", - "ifne", - "iflt", - "ifge", - "ifgt", - "ifle", - "if_icmpeq", - "if_icmpne", - "if_icmplt", - "if_icmpge", - "if_icmpgt", - "if_icmple", - "if_acmpeq", - "if_acmpne", - "goto", - "jsr", - "ret", - "tableswitch", - "lookupswitch", - "ireturn", - "lreturn", - "freturn", - "dreturn", - "areturn", - "return", - "getstatic", - "putstatic", - "getfield", - "putfield", - "invokevirtual", - "invokespecial", // was "invokenonvirtual", - "invokestatic", - "invokeinterface", - "bytecode 186", //"xxxunusedxxx", - "new", - "newarray", - "anewarray", - "arraylength", - "athrow", - "checkcast", - "instanceof", - "monitorenter", - "monitorexit", - null, // "wide", - "multianewarray", - "ifnull", - "ifnonnull", - "goto_w", - "jsr_w", - "bytecode 202", // "breakpoint", - "bytecode", - "try", - "endtry", - "catch", - "var", - "endvar", - "locals_map", - "stack_map" - }; - - /* Opcode Lengths */ - private static final int opcLengthsTab[] = { - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, - 3, - 2, - 3, - 3, - 2, - 2, - 2, - 2, - 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 2, - 99, - 99, - 1, - 1, - 1, - 1, - 1, - 1, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 5, - 0, - 3, - 2, - 3, - 1, - 1, - 3, - 3, - 1, - 1, - 0, // wide - 4, - 3, - 3, - 5, - 5, - 1, - 1, 0, 0, 0, 0, 0 // pseudo - }; - - /* Type codes, used in newarray opcode */ - public static final int T_CLASS = 0x00000002; - public static final int T_BOOLEAN = 0x00000004; - public static final int T_CHAR = 0x00000005; - public static final int T_FLOAT = 0x00000006; - public static final int T_DOUBLE = 0x00000007; - public static final int T_BYTE = 0x00000008; - public static final int T_SHORT = 0x00000009; - public static final int T_INT = 0x0000000a; - public static final int T_LONG = 0x0000000b; - - private static HashMap<String,Integer> mnemocodes = new HashMap<String,Integer>(301, 0.5f); - private static String opcExtNamesTab[]=new String[128]; - private static String opcPrivExtNamesTab[]=new String[128]; - - private static void defineNonPriv(int opc, String mnem) { - mnemocodes.put(opcExtNamesTab[opc] = mnem, opc_nonpriv * 256 + opc); - } - - private static void definePriv(int opc, String mnem) { - mnemocodes.put(opcPrivExtNamesTab[opc] = "priv_" + mnem, opc_priv * 256 + opc); - } - - private static void defineExt(int opc, String mnem) { - defineNonPriv(opc, mnem); - definePriv(opc, mnem); - } - - static { - for (int i = 0; i < opc_wide; i++) { - mnemocodes.put(opcNamesTab[i], i); - } - for (int i = opc_wide + 1; i < opcNamesTab.length; i++) { - mnemocodes.put(opcNamesTab[i], i); - } - mnemocodes.put("invokenonvirtual", opc_invokespecial); - - mnemocodes.put("iload_w", opc_iload_w); - mnemocodes.put("lload_w", opc_lload_w); - mnemocodes.put("fload_w", opc_fload_w); - mnemocodes.put("dload_w", opc_dload_w); - mnemocodes.put("aload_w", opc_aload_w); - mnemocodes.put("istore_w", opc_istore_w); - mnemocodes.put("lstore_w", opc_lstore_w); - mnemocodes.put("fstore_w", opc_fstore_w); - mnemocodes.put("dstore_w", opc_dstore_w); - mnemocodes.put("astore_w", opc_astore_w); - mnemocodes.put("ret_w", opc_ret_w); - mnemocodes.put("iinc_w", opc_iinc_w); - - mnemocodes.put("nonpriv", opc_nonpriv); - mnemocodes.put("priv", opc_priv); - - defineExt(0, "load_ubyte"); - defineExt(1, "load_byte"); - defineExt(2, "load_char"); - defineExt(3, "load_short"); - defineExt(4, "load_word"); - defineExt(10, "load_char_oe"); - defineExt(11, "load_short_oe"); - defineExt(12, "load_word_oe"); - defineExt(16, "ncload_ubyte"); - defineExt(17, "ncload_byte"); - defineExt(18, "ncload_char"); - defineExt(19, "ncload_short"); - defineExt(20, "ncload_word"); - defineExt(26, "ncload_char_oe"); - defineExt(27, "ncload_short_oe"); - defineExt(28, "ncload_word_oe"); - defineExt(30, "cache_flush"); - defineExt(32, "store_byte"); - defineExt(34, "store_short"); - defineExt(36, "store_word"); - defineExt(42, "store_short_oe"); - defineExt(44, "store_word_oe"); - defineExt(48, "ncstore_byte"); - defineExt(50, "ncstore_short"); - defineExt(52, "ncstore_word"); - defineExt(58, "ncstore_short_oe"); - defineExt(60, "ncstore_word_oe"); - defineExt(62, "zero_line"); - defineNonPriv(5, "ret_from_sub"); - defineNonPriv(63, "enter_sync_method"); - definePriv(5, "ret_from_trap"); - definePriv(6, "read_dcache_tag"); - definePriv(7, "read_dcache_data"); - definePriv(14, "read_icache_tag"); - definePriv(15, "read_icache_data"); - definePriv(22, "powerdown"); - definePriv(23, "read_scache_data"); - definePriv(31, "cache_index_flush"); - definePriv(38, "write_dcache_tag"); - definePriv(39, "write_dcache_data"); - definePriv(46, "write_icache_tag"); - definePriv(47, "write_icache_data"); - definePriv(54, "reset"); - definePriv(55, "write_scache_data"); - for (int i = 0; i < 32; i++) { - definePriv(i + 64, "read_reg_" + i); - } - for (int i = 0; i < 32; i++) { - definePriv(i + 96, "write_reg_" + i); - } - } -} diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java b/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java new file mode 100644 index 00000000000..562c3876934 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java @@ -0,0 +1,472 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.classfile; + +import static com.sun.tools.classfile.Instruction.Kind.*; +import static com.sun.tools.classfile.Opcode.Set.*; + +/** + * See JVMS3, chapter 6. + * + * <p>In addition to providing all the standard opcodes defined in JVMS, + * this class also provides legacy support for the PicoJava extensions. + * + * <p><b>This is NOT part of any API supported by Sun Microsystems. If + * you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public enum Opcode { + NOP(0x0), + ACONST_NULL(0x1), + ICONST_M1(0x2), + ICONST_0(0x3), + ICONST_1(0x4), + ICONST_2(0x5), + ICONST_3(0x6), + ICONST_4(0x7), + ICONST_5(0x8), + LCONST_0(0x9), + LCONST_1(0xa), + FCONST_0(0xb), + FCONST_1(0xc), + FCONST_2(0xd), + DCONST_0(0xe), + DCONST_1(0xf), + BIPUSH(0x10, BYTE), + SIPUSH(0x11, SHORT), + LDC(0x12, CPREF), + LDC_W(0x13, CPREF_W), + LDC2_W(0x14, CPREF_W), + ILOAD(0x15, LOCAL), + LLOAD(0x16, LOCAL), + FLOAD(0x17, LOCAL), + DLOAD(0x18, LOCAL), + ALOAD(0x19, LOCAL), + ILOAD_0(0x1a), + ILOAD_1(0x1b), + ILOAD_2(0x1c), + ILOAD_3(0x1d), + LLOAD_0(0x1e), + LLOAD_1(0x1f), + LLOAD_2(0x20), + LLOAD_3(0x21), + FLOAD_0(0x22), + FLOAD_1(0x23), + FLOAD_2(0x24), + FLOAD_3(0x25), + DLOAD_0(0x26), + DLOAD_1(0x27), + DLOAD_2(0x28), + DLOAD_3(0x29), + ALOAD_0(0x2a), + ALOAD_1(0x2b), + ALOAD_2(0x2c), + ALOAD_3(0x2d), + IALOAD(0x2e), + LALOAD(0x2f), + FALOAD(0x30), + DALOAD(0x31), + AALOAD(0x32), + BALOAD(0x33), + CALOAD(0x34), + SALOAD(0x35), + ISTORE(0x36, LOCAL), + LSTORE(0x37, LOCAL), + FSTORE(0x38, LOCAL), + DSTORE(0x39, LOCAL), + ASTORE(0x3a, LOCAL), + ISTORE_0(0x3b), + ISTORE_1(0x3c), + ISTORE_2(0x3d), + ISTORE_3(0x3e), + LSTORE_0(0x3f), + LSTORE_1(0x40), + LSTORE_2(0x41), + LSTORE_3(0x42), + FSTORE_0(0x43), + FSTORE_1(0x44), + FSTORE_2(0x45), + FSTORE_3(0x46), + DSTORE_0(0x47), + DSTORE_1(0x48), + DSTORE_2(0x49), + DSTORE_3(0x4a), + ASTORE_0(0x4b), + ASTORE_1(0x4c), + ASTORE_2(0x4d), + ASTORE_3(0x4e), + IASTORE(0x4f), + LASTORE(0x50), + FASTORE(0x51), + DASTORE(0x52), + AASTORE(0x53), + BASTORE(0x54), + CASTORE(0x55), + SASTORE(0x56), + POP(0x57), + POP2(0x58), + DUP(0x59), + DUP_X1(0x5a), + DUP_X2(0x5b), + DUP2(0x5c), + DUP2_X1(0x5d), + DUP2_X2(0x5e), + SWAP(0x5f), + IADD(0x60), + LADD(0x61), + FADD(0x62), + DADD(0x63), + ISUB(0x64), + LSUB(0x65), + FSUB(0x66), + DSUB(0x67), + IMUL(0x68), + LMUL(0x69), + FMUL(0x6a), + DMUL(0x6b), + IDIV(0x6c), + LDIV(0x6d), + FDIV(0x6e), + DDIV(0x6f), + IREM(0x70), + LREM(0x71), + FREM(0x72), + DREM(0x73), + INEG(0x74), + LNEG(0x75), + FNEG(0x76), + DNEG(0x77), + ISHL(0x78), + LSHL(0x79), + ISHR(0x7a), + LSHR(0x7b), + IUSHR(0x7c), + LUSHR(0x7d), + IAND(0x7e), + LAND(0x7f), + IOR(0x80), + LOR(0x81), + IXOR(0x82), + LXOR(0x83), + IINC(0x84, LOCAL_BYTE), + I2L(0x85), + I2F(0x86), + I2D(0x87), + L2I(0x88), + L2F(0x89), + L2D(0x8a), + F2I(0x8b), + F2L(0x8c), + F2D(0x8d), + D2I(0x8e), + D2L(0x8f), + D2F(0x90), + I2B(0x91), + I2C(0x92), + I2S(0x93), + LCMP(0x94), + FCMPL(0x95), + FCMPG(0x96), + DCMPL(0x97), + DCMPG(0x98), + IFEQ(0x99, BRANCH), + IFNE(0x9a, BRANCH), + IFLT(0x9b, BRANCH), + IFGE(0x9c, BRANCH), + IFGT(0x9d, BRANCH), + IFLE(0x9e, BRANCH), + IF_ICMPEQ(0x9f, BRANCH), + IF_ICMPNE(0xa0, BRANCH), + IF_ICMPLT(0xa1, BRANCH), + IF_ICMPGE(0xa2, BRANCH), + IF_ICMPGT(0xa3, BRANCH), + IF_ICMPLE(0xa4, BRANCH), + IF_ACMPEQ(0xa5, BRANCH), + IF_ACMPNE(0xa6, BRANCH), + GOTO(0xa7, BRANCH), + JSR(0xa8, BRANCH), + RET(0xa9, LOCAL), + TABLESWITCH(0xaa, DYNAMIC), + LOOKUPSWITCH(0xab, DYNAMIC), + IRETURN(0xac), + LRETURN(0xad), + FRETURN(0xae), + DRETURN(0xaf), + ARETURN(0xb0), + RETURN(0xb1), + GETSTATIC(0xb2, CPREF_W), + PUTSTATIC(0xb3, CPREF_W), + GETFIELD(0xb4, CPREF_W), + PUTFIELD(0xb5, CPREF_W), + INVOKEVIRTUAL(0xb6, CPREF_W), + INVOKESPECIAL(0xb7, CPREF_W), + INVOKESTATIC(0xb8, CPREF_W), + INVOKEINTERFACE(0xb9, CPREF_W_UBYTE_ZERO), + // unused 0xba + NEW(0xbb, CPREF_W), + NEWARRAY(0xbc, ATYPE), + ANEWARRAY(0xbd, CPREF_W), + ARRAYLENGTH(0xbe), + ATHROW(0xbf), + CHECKCAST(0xc0, CPREF_W), + INSTANCEOF(0xc1, CPREF_W), + MONITORENTER(0xc2), + MONITOREXIT(0xc3), + // wide 0xc4 + MULTIANEWARRAY(0xc5, CPREF_W_UBYTE), + IFNULL(0xc6, BRANCH), + IFNONNULL(0xc7, BRANCH), + GOTO_W(0xc8, BRANCH_W), + JSR_W(0xc9, BRANCH_W), + // impdep 0xfe: PicoJava nonpriv + // impdep 0xff: Picojava priv + + // wide opcodes + ILOAD_W(0xc415, WIDE_CPREF_W), + LLOAD_W(0xc416, WIDE_CPREF_W), + FLOAD_W(0xc417, WIDE_CPREF_W), + DLOAD_W(0xc418, WIDE_CPREF_W), + ALOAD_W(0xc419, WIDE_CPREF_W), + ISTORE_W(0xc436, WIDE_CPREF_W), + LSTORE_W(0xc437, WIDE_CPREF_W), + FSTORE_W(0xc438, WIDE_CPREF_W), + DSTORE_W(0xc439, WIDE_CPREF_W), + ASTORE_W(0xc43a, WIDE_CPREF_W), + IINC_W(0xc484, WIDE_CPREF_W_SHORT), + RET_W(0xc4a9, WIDE_CPREF_W), + + // PicoJava nonpriv instructions + LOAD_UBYTE(PICOJAVA, 0xfe00), + LOAD_BYTE(PICOJAVA, 0xfe01), + LOAD_CHAR(PICOJAVA, 0xfe02), + LOAD_SHORT(PICOJAVA, 0xfe03), + LOAD_WORD(PICOJAVA, 0xfe04), + RET_FROM_SUB(PICOJAVA, 0xfe05), + LOAD_CHAR_OE(PICOJAVA, 0xfe0a), + LOAD_SHORT_OE(PICOJAVA, 0xfe0b), + LOAD_WORD_OE(PICOJAVA, 0xfe0c), + NCLOAD_UBYTE(PICOJAVA, 0xfe10), + NCLOAD_BYTE(PICOJAVA, 0xfe11), + NCLOAD_CHAR(PICOJAVA, 0xfe12), + NCLOAD_SHORT(PICOJAVA, 0xfe13), + NCLOAD_WORD(PICOJAVA, 0xfe14), + NCLOAD_CHAR_OE(PICOJAVA, 0xfe1a), + NCLOAD_SHORT_OE(PICOJAVA, 0xfe1b), + NCLOAD_WORD_OE(PICOJAVA, 0xfe1c), + CACHE_FLUSH(PICOJAVA, 0xfe1e), + STORE_BYTE(PICOJAVA, 0xfe20), + STORE_SHORT(PICOJAVA, 0xfe22), + STORE_WORD(PICOJAVA, 0xfe24), + STORE_SHORT_OE(PICOJAVA, 0xfe2a), + STORE_WORD_OE(PICOJAVA, 0xfe2c), + NCSTORE_BYTE(PICOJAVA, 0xfe30), + NCSTORE_SHORT(PICOJAVA, 0xfe32), + NCSTORE_WORD(PICOJAVA, 0xfe34), + NCSTORE_SHORT_OE(PICOJAVA, 0xfe3a), + NCSTORE_WORD_OE(PICOJAVA, 0xfe3c), + ZERO_LINE(PICOJAVA, 0xfe3e), + ENTER_SYNC_METHOD(PICOJAVA, 0xfe3f), + + // PicoJava priv instructions + PRIV_LOAD_UBYTE(PICOJAVA, 0xff00), + PRIV_LOAD_BYTE(PICOJAVA, 0xff01), + PRIV_LOAD_CHAR(PICOJAVA, 0xff02), + PRIV_LOAD_SHORT(PICOJAVA, 0xff03), + PRIV_LOAD_WORD(PICOJAVA, 0xff04), + PRIV_RET_FROM_TRAP(PICOJAVA, 0xff05), + PRIV_READ_DCACHE_TAG(PICOJAVA, 0xff06), + PRIV_READ_DCACHE_DATA(PICOJAVA, 0xff07), + PRIV_LOAD_CHAR_OE(PICOJAVA, 0xff0a), + PRIV_LOAD_SHORT_OE(PICOJAVA, 0xff0b), + PRIV_LOAD_WORD_OE(PICOJAVA, 0xff0c), + PRIV_READ_ICACHE_TAG(PICOJAVA, 0xff0e), + PRIV_READ_ICACHE_DATA(PICOJAVA, 0xff0f), + PRIV_NCLOAD_UBYTE(PICOJAVA, 0xff10), + PRIV_NCLOAD_BYTE(PICOJAVA, 0xff11), + PRIV_NCLOAD_CHAR(PICOJAVA, 0xff12), + PRIV_NCLOAD_SHORT(PICOJAVA, 0xff13), + PRIV_NCLOAD_WORD(PICOJAVA, 0xff14), + PRIV_POWERDOWN(PICOJAVA, 0xff16), + PRIV_READ_SCACHE_DATA(PICOJAVA, 0xff17), + PRIV_NCLOAD_CHAR_OE(PICOJAVA, 0xff1a), + PRIV_NCLOAD_SHORT_OE(PICOJAVA, 0xff1b), + PRIV_NCLOAD_WORD_OE(PICOJAVA, 0xff1c), + PRIV_CACHE_FLUSH(PICOJAVA, 0xff1e), + PRIV_CACHE_INDEX_FLUSH(PICOJAVA, 0xff1f), + PRIV_STORE_BYTE(PICOJAVA, 0xff20), + PRIV_STORE_SHORT(PICOJAVA, 0xff22), + PRIV_STORE_WORD(PICOJAVA, 0xff24), + PRIV_WRITE_DCACHE_TAG(PICOJAVA, 0xff26), + PRIV_WRITE_DCACHE_DATA(PICOJAVA, 0xff27), + PRIV_STORE_SHORT_OE(PICOJAVA, 0xff2a), + PRIV_STORE_WORD_OE(PICOJAVA, 0xff2c), + PRIV_WRITE_ICACHE_TAG(PICOJAVA, 0xff2e), + PRIV_WRITE_ICACHE_DATA(PICOJAVA, 0xff2f), + PRIV_NCSTORE_BYTE(PICOJAVA, 0xff30), + PRIV_NCSTORE_SHORT(PICOJAVA, 0xff32), + PRIV_NCSTORE_WORD(PICOJAVA, 0xff34), + PRIV_RESET(PICOJAVA, 0xff36), + PRIV_WRITE_SCACHE_DATA(PICOJAVA, 0xff37), + PRIV_NCSTORE_SHORT_OE(PICOJAVA, 0xff3a), + PRIV_NCSTORE_WORD_OE(PICOJAVA, 0xff3c), + PRIV_ZERO_LINE(PICOJAVA, 0xff3e), + PRIV_READ_REG_0(PICOJAVA, 0xff40), + PRIV_READ_REG_1(PICOJAVA, 0xff41), + PRIV_READ_REG_2(PICOJAVA, 0xff42), + PRIV_READ_REG_3(PICOJAVA, 0xff43), + PRIV_READ_REG_4(PICOJAVA, 0xff44), + PRIV_READ_REG_5(PICOJAVA, 0xff45), + PRIV_READ_REG_6(PICOJAVA, 0xff46), + PRIV_READ_REG_7(PICOJAVA, 0xff47), + PRIV_READ_REG_8(PICOJAVA, 0xff48), + PRIV_READ_REG_9(PICOJAVA, 0xff49), + PRIV_READ_REG_10(PICOJAVA, 0xff4a), + PRIV_READ_REG_11(PICOJAVA, 0xff4b), + PRIV_READ_REG_12(PICOJAVA, 0xff4c), + PRIV_READ_REG_13(PICOJAVA, 0xff4d), + PRIV_READ_REG_14(PICOJAVA, 0xff4e), + PRIV_READ_REG_15(PICOJAVA, 0xff4f), + PRIV_READ_REG_16(PICOJAVA, 0xff50), + PRIV_READ_REG_17(PICOJAVA, 0xff51), + PRIV_READ_REG_18(PICOJAVA, 0xff52), + PRIV_READ_REG_19(PICOJAVA, 0xff53), + PRIV_READ_REG_20(PICOJAVA, 0xff54), + PRIV_READ_REG_21(PICOJAVA, 0xff55), + PRIV_READ_REG_22(PICOJAVA, 0xff56), + PRIV_READ_REG_23(PICOJAVA, 0xff57), + PRIV_READ_REG_24(PICOJAVA, 0xff58), + PRIV_READ_REG_25(PICOJAVA, 0xff59), + PRIV_READ_REG_26(PICOJAVA, 0xff5a), + PRIV_READ_REG_27(PICOJAVA, 0xff5b), + PRIV_READ_REG_28(PICOJAVA, 0xff5c), + PRIV_READ_REG_29(PICOJAVA, 0xff5d), + PRIV_READ_REG_30(PICOJAVA, 0xff5e), + PRIV_READ_REG_31(PICOJAVA, 0xff5f), + PRIV_WRITE_REG_0(PICOJAVA, 0xff60), + PRIV_WRITE_REG_1(PICOJAVA, 0xff61), + PRIV_WRITE_REG_2(PICOJAVA, 0xff62), + PRIV_WRITE_REG_3(PICOJAVA, 0xff63), + PRIV_WRITE_REG_4(PICOJAVA, 0xff64), + PRIV_WRITE_REG_5(PICOJAVA, 0xff65), + PRIV_WRITE_REG_6(PICOJAVA, 0xff66), + PRIV_WRITE_REG_7(PICOJAVA, 0xff67), + PRIV_WRITE_REG_8(PICOJAVA, 0xff68), + PRIV_WRITE_REG_9(PICOJAVA, 0xff69), + PRIV_WRITE_REG_10(PICOJAVA, 0xff6a), + PRIV_WRITE_REG_11(PICOJAVA, 0xff6b), + PRIV_WRITE_REG_12(PICOJAVA, 0xff6c), + PRIV_WRITE_REG_13(PICOJAVA, 0xff6d), + PRIV_WRITE_REG_14(PICOJAVA, 0xff6e), + PRIV_WRITE_REG_15(PICOJAVA, 0xff6f), + PRIV_WRITE_REG_16(PICOJAVA, 0xff70), + PRIV_WRITE_REG_17(PICOJAVA, 0xff71), + PRIV_WRITE_REG_18(PICOJAVA, 0xff72), + PRIV_WRITE_REG_19(PICOJAVA, 0xff73), + PRIV_WRITE_REG_20(PICOJAVA, 0xff74), + PRIV_WRITE_REG_21(PICOJAVA, 0xff75), + PRIV_WRITE_REG_22(PICOJAVA, 0xff76), + PRIV_WRITE_REG_23(PICOJAVA, 0xff77), + PRIV_WRITE_REG_24(PICOJAVA, 0xff78), + PRIV_WRITE_REG_25(PICOJAVA, 0xff79), + PRIV_WRITE_REG_26(PICOJAVA, 0xff7a), + PRIV_WRITE_REG_27(PICOJAVA, 0xff7b), + PRIV_WRITE_REG_28(PICOJAVA, 0xff7c), + PRIV_WRITE_REG_29(PICOJAVA, 0xff7d), + PRIV_WRITE_REG_30(PICOJAVA, 0xff7e), + PRIV_WRITE_REG_31(PICOJAVA, 0xff7f); + + Opcode(int opcode) { + this(STANDARD, opcode, NO_OPERANDS); + } + + Opcode(int opcode, Instruction.Kind kind) { + this(STANDARD, opcode, kind); + } + + Opcode(Set set, int opcode) { + this(set, opcode, (set == STANDARD ? NO_OPERANDS : WIDE_NO_OPERANDS)); + } + + Opcode(Set set, int opcode, Instruction.Kind kind) { + this.set = set; + this.opcode = opcode; + this.kind = kind; + } + + public final Set set; + public final int opcode; + public final Instruction.Kind kind; + + /** Get the Opcode for a simple standard 1-byte opcode. */ + public static Opcode get(int opcode) { + return stdOpcodes[opcode]; + } + + /** Get the Opcode for 1- or 2-byte opcode. */ + public static Opcode get(int opcodePrefix, int opcode) { + Opcode[] block = getOpcodeBlock(opcodePrefix); + return (block == null ? null : block[opcode]); + } + + private static Opcode[] getOpcodeBlock(int opcodePrefix) { + switch (opcodePrefix) { + case 0: + return stdOpcodes; + case WIDE: + return wideOpcodes; + case NONPRIV: + return nonPrivOpcodes; + case PRIV: + return privOpcodes; + default: + return null; + } + + } + + private static Opcode[] stdOpcodes = new Opcode[256]; + private static Opcode[] wideOpcodes = new Opcode[256]; + private static Opcode[] nonPrivOpcodes = new Opcode[256]; + private static Opcode[] privOpcodes = new Opcode[256]; + static { + for (Opcode o: values()) + getOpcodeBlock(o.opcode >> 8)[o.opcode & 0xff] = o; + } + + /** The byte prefix for the wide instructions. */ + public static final int WIDE = 0xc4; + /** The byte prefix for the PicoJava nonpriv instructions. */ + public static final int NONPRIV = 0xfe; + /** The byte prefix for the PicoJava priv instructions. */ + public static final int PRIV = 0xff; + + public enum Set { + /** Standard opcodes. */ + STANDARD, + /** Legacy support for PicoJava opcodes. */ + PICOJAVA }; +} diff --git a/langtools/src/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java b/langtools/src/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java index 26a9b6f9736..2fae45edad1 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractIndexWriter.java index a7cad980bbc..0809e184705 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractIndexWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractIndexWriter.java @@ -25,12 +25,12 @@ package com.sun.tools.doclets.formats.html; -import com.sun.tools.doclets.internal.toolkit.util.*; - -import com.sun.javadoc.*; import java.io.*; import java.util.*; +import com.sun.javadoc.*; +import com.sun.tools.doclets.internal.toolkit.util.*; + /** * Generate Index for all the Member Names with Indexing in * Unicode Order. This class is a base class for {@link SingleIndexWriter} and @@ -100,18 +100,22 @@ public class AbstractIndexWriter extends HtmlDocletWriter { h2(); strong(unicode.toString()); h2End(); - dl(); - for (int i = 0; i < memberlist.size(); i++) { - Doc element = memberlist.get(i); - if (element instanceof MemberDoc) { - printDescription((MemberDoc)element); - } else if (element instanceof ClassDoc) { - printDescription((ClassDoc)element); - } else if (element instanceof PackageDoc) { - printDescription((PackageDoc)element); + int memberListSize = memberlist.size(); + // Display the list only if there are elements to be displayed. + if (memberListSize > 0) { + dl(); + for (int i = 0; i < memberListSize; i++) { + Doc element = memberlist.get(i); + if (element instanceof MemberDoc) { + printDescription((MemberDoc)element); + } else if (element instanceof ClassDoc) { + printDescription((ClassDoc)element); + } else if (element instanceof PackageDoc) { + printDescription((PackageDoc)element); + } } + dlEnd(); } - dlEnd(); hr(); } @@ -126,8 +130,10 @@ public class AbstractIndexWriter extends HtmlDocletWriter { printPackageLink(pkg, Util.getPackageName(pkg), true); print(" - "); print(configuration.getText("doclet.package") + " " + pkg.name()); + dtEnd(); dd(); printSummaryComment(pkg); + ddEnd(); } /** @@ -140,8 +146,10 @@ public class AbstractIndexWriter extends HtmlDocletWriter { printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_INDEX, cd, true)); print(" - "); printClassInfo(cd); + dtEnd(); dd(); printComment(cd); + ddEnd(); } /** @@ -178,8 +186,10 @@ public class AbstractIndexWriter extends HtmlDocletWriter { println(" - "); printMemberDesc(member); println(); + dtEnd(); dd(); printComment(member); + ddEnd(); println(); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java index 268dbe009fb..273b42558ed 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java @@ -25,12 +25,12 @@ package com.sun.tools.doclets.formats.html; -import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.tools.doclets.internal.toolkit.taglets.*; +import java.lang.reflect.Modifier; +import java.util.*; import com.sun.javadoc.*; -import java.util.*; -import java.lang.reflect.Modifier; +import com.sun.tools.doclets.internal.toolkit.util.*; +import com.sun.tools.doclets.internal.toolkit.taglets.*; /** * The base class for member writers. @@ -38,6 +38,7 @@ import java.lang.reflect.Modifier; * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (Re-write) + * @author Bhavesh Patel (Modified) */ public abstract class AbstractMemberWriter { @@ -59,7 +60,11 @@ public abstract class AbstractMemberWriter { /*** abstracts ***/ - public abstract void printSummaryLabel(ClassDoc cd); + public abstract void printSummaryLabel(); + + public abstract void printTableSummary(); + + public abstract void printSummaryTableHeader(ProgramElementDoc member); public abstract void printInheritedSummaryLabel(ClassDoc cd); @@ -232,10 +237,26 @@ public abstract class AbstractMemberWriter { } } + /** + * Print the deprecated output for the given member. + * + * @param member the member being documented. + */ + protected void printDeprecated(ProgramElementDoc member) { + String output = (new DeprecatedTaglet()).getTagletOutput(member, + writer.getTagletWriterInstance(false)).toString().trim(); + if (!output.isEmpty()) { + writer.printMemberDetailsListStartTag(); + writer.print(output); + } + } + protected void printComment(ProgramElementDoc member) { if (member.inlineTags().length > 0) { + writer.printMemberDetailsListStartTag(); writer.dd(); writer.printInlineComment(member); + writer.ddEnd(); } } @@ -266,6 +287,14 @@ public abstract class AbstractMemberWriter { writer.printTags(member); } + /** + * Write the member footer. + */ + protected void printMemberFooter() { + writer.printMemberDetailsListEndTag(); + assert !writer.getMemberDetailsListPrinted(); + } + /** * Forward to containing writer */ @@ -317,12 +346,13 @@ public abstract class AbstractMemberWriter { * format for listing the API. Call methods from the sub-class to complete * the generation. */ - protected void printDeprecatedAPI(List<Doc> deprmembers, String headingKey) { + protected void printDeprecatedAPI(List<Doc> deprmembers, String headingKey, String tableSummary, String[] tableHeader) { if (deprmembers.size() > 0) { - writer.tableIndexSummary(); - writer.tableHeaderStart("#CCCCFF"); - writer.strongText(headingKey); - writer.tableHeaderEnd(); + writer.tableIndexSummary(tableSummary); + writer.tableCaptionStart(); + writer.printText(headingKey); + writer.tableCaptionEnd(); + writer.summaryTableHeader(tableHeader, "col"); for (int i = 0; i < deprmembers.size(); i++) { ProgramElementDoc member =(ProgramElementDoc)deprmembers.get(i); writer.trBgcolorStyle("white", "TableRowColor"); @@ -345,19 +375,26 @@ public abstract class AbstractMemberWriter { /** * Print use info. */ - protected void printUseInfo(List<? extends ProgramElementDoc> mems, String heading) { + protected void printUseInfo(List<? extends ProgramElementDoc> mems, String heading, String tableSummary) { if (mems == null) { return; } List<? extends ProgramElementDoc> members = mems; + boolean printedUseTableHeader = false; if (members.size() > 0) { - writer.tableIndexSummary(); - writer.tableUseInfoHeaderStart("#CCCCFF"); + writer.tableIndexSummary(tableSummary); + writer.tableSubCaptionStart(); writer.print(heading); - writer.tableHeaderEnd(); + writer.tableCaptionEnd(); for (Iterator<? extends ProgramElementDoc> it = members.iterator(); it.hasNext(); ) { ProgramElementDoc pgmdoc = it.next(); ClassDoc cd = pgmdoc.containingClass(); + if (!printedUseTableHeader) { + // Passing ProgramElementDoc helps decides printing + // interface or class header in case of nested classes. + this.printSummaryTableHeader(pgmdoc); + printedUseTableHeader = true; + } writer.printSummaryLinkType(this, pgmdoc); if (cd != null && !(pgmdoc instanceof ConstructorDoc) diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java index 36742cf7f95..b743aeacd2d 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java @@ -35,6 +35,7 @@ import java.util.*; * generate overview-frame.html as well as overview-summary.html. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { @@ -61,7 +62,7 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { protected abstract void printOverviewHeader(); - protected abstract void printIndexHeader(String text); + protected abstract void printIndexHeader(String text, String tableSummary); protected abstract void printIndexRow(PackageDoc pkg); @@ -101,7 +102,10 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { * Generate the frame or non-frame package index. */ protected void generateIndex() { - printIndexContents(packages, "doclet.Package_Summary"); + printIndexContents(packages, "doclet.Package_Summary", + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Package_Summary"), + configuration.getText("doclet.packages"))); } /** @@ -111,10 +115,10 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { * @param packages Array of packages to be documented. * @param text String which will be used as the heading. */ - protected void printIndexContents(PackageDoc[] packages, String text) { + protected void printIndexContents(PackageDoc[] packages, String text, String tableSummary) { if (packages.length > 0) { Arrays.sort(packages); - printIndexHeader(text); + printIndexHeader(text, tableSummary); printAllClassesPackagesLink(); for(int i = 0; i < packages.length; i++) { if (packages[i] != null) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java index 570f27542dd..5bf2f8e19fe 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java @@ -25,15 +25,16 @@ package com.sun.tools.doclets.formats.html; -import com.sun.tools.doclets.internal.toolkit.*; -import com.sun.javadoc.*; - import java.io.*; +import com.sun.javadoc.*; +import com.sun.tools.doclets.internal.toolkit.*; + /** * Writes annotation type optional member documentation in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class AnnotationTypeOptionalMemberWriterImpl extends AnnotationTypeRequiredMemberWriterImpl @@ -63,14 +64,20 @@ public class AnnotationTypeOptionalMemberWriterImpl extends * {@inheritDoc} */ public void writeDefaultValueInfo(MemberDoc member) { - writer.dl(); - writer.dt(); - writer.strong(ConfigurationImpl.getInstance(). - getText("doclet.Default")); - writer.dd(); - writer.print(((AnnotationTypeElementDoc) member).defaultValue()); - writer.ddEnd(); - writer.dlEnd(); + if (((AnnotationTypeElementDoc) member).defaultValue() != null) { + writer.printMemberDetailsListStartTag(); + writer.dd(); + writer.dl(); + writer.dt(); + writer.strong(ConfigurationImpl.getInstance(). + getText("doclet.Default")); + writer.dtEnd(); + writer.dd(); + writer.print(((AnnotationTypeElementDoc) member).defaultValue()); + writer.ddEnd(); + writer.dlEnd(); + writer.ddEnd(); + } } /** @@ -83,8 +90,27 @@ public class AnnotationTypeOptionalMemberWriterImpl extends /** * {@inheritDoc} */ - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Annotation_Type_Optional_Member_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Annotation_Type_Optional_Member_Summary"); + } + + /** + * {@inheritDoc} + */ + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Annotation_Type_Optional_Member_Summary"), + configuration().getText("doclet.annotation_type_optional_members"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Annotation_Type_Optional_Member"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java index 801ec8a241d..9b745c68187 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java @@ -25,16 +25,16 @@ package com.sun.tools.doclets.formats.html; -import com.sun.tools.doclets.internal.toolkit.*; -import com.sun.tools.doclets.internal.toolkit.taglets.*; -import com.sun.javadoc.*; - import java.io.*; +import com.sun.javadoc.*; +import com.sun.tools.doclets.internal.toolkit.*; + /** * Writes annotation type required member documentation in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter implements AnnotationTypeRequiredMemberWriter, MemberSummaryWriter { @@ -134,17 +134,14 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter strong(member.name()); } writer.preEnd(); - writer.dl(); + assert !writer.getMemberDetailsListPrinted(); } /** * {@inheritDoc} */ public void writeComments(MemberDoc member) { - if (member.inlineTags().length > 0) { - writer.dd(); - writer.printInlineComment(member); - } + printComment(member); } /** @@ -160,7 +157,7 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter * Write the annotation type member footer. */ public void writeMemberFooter() { - writer.dlEnd(); + printMemberFooter(); } /** @@ -182,8 +179,27 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter /** * {@inheritDoc} */ - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Annotation_Type_Required_Member_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Annotation_Type_Required_Member_Summary"); + } + + /** + * {@inheritDoc} + */ + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Annotation_Type_Required_Member_Summary"), + configuration().getText("doclet.annotation_type_required_members"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Annotation_Type_Required_Member"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } /** @@ -267,9 +283,7 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter * {@inheritDoc} */ public void writeDeprecated(MemberDoc member) { - print(((TagletOutputImpl) - (new DeprecatedTaglet()).getTagletOutput(member, - writer.getTagletWriterInstance(false))).toString()); + printDeprecated(member); } private Type getType(MemberDoc member) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeWriterImpl.java index fc2527db89b..594ce856a05 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeWriterImpl.java @@ -25,10 +25,10 @@ package com.sun.tools.doclets.formats.html; +import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.util.*; import com.sun.tools.doclets.internal.toolkit.builders.*; -import com.sun.javadoc.*; /** * Generate the Class Information Page. @@ -165,8 +165,6 @@ public class AnnotationTypeWriterImpl extends SubWriterHolderWriter * {@inheritDoc} */ public void writeAnnotationTypeSignature(String modifiers) { - dl(); - dt(); preNoNewLine(); writeAnnotationInfo(annotationType); print(modifiers); @@ -178,7 +176,6 @@ public class AnnotationTypeWriterImpl extends SubWriterHolderWriter } else { strong(name); } - dlEnd(); preEnd(); p(); } @@ -334,6 +331,7 @@ public class AnnotationTypeWriterImpl extends SubWriterHolderWriter } else { strongText("doclet.Enclosing_Class"); } + dtEnd(); dd(); printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, outerClass, false)); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java index 73d957e3c4e..6baec7af9d8 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java @@ -34,6 +34,7 @@ import java.util.*; * Generate class usage information. * * @author Robert G. Field + * @author Bhavesh Patel (Modified) */ public class ClassUseWriter extends SubWriterHolderWriter { @@ -65,6 +66,13 @@ public class ClassUseWriter extends SubWriterHolderWriter { final ConstructorWriterImpl constrSubWriter; final FieldWriterImpl fieldSubWriter; final NestedClassWriterImpl classSubWriter; + // Summary for various use tables. + final String classUseTableSummary; + final String subclassUseTableSummary; + final String subinterfaceUseTableSummary; + final String fieldUseTableSummary; + final String methodUseTableSummary; + final String constructorUseTableSummary; /** @@ -116,6 +124,18 @@ public class ClassUseWriter extends SubWriterHolderWriter { constrSubWriter = new ConstructorWriterImpl(this); fieldSubWriter = new FieldWriterImpl(this); classSubWriter = new NestedClassWriterImpl(this); + classUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.classes")); + subclassUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.subclasses")); + subinterfaceUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.subinterfaces")); + fieldUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.fields")); + methodUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.methods")); + constructorUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.constructors")); } /** @@ -213,12 +233,13 @@ public class ClassUseWriter extends SubWriterHolderWriter { } protected void generatePackageList() throws IOException { - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(useTableSummary); + tableCaptionStart(); printText("doclet.ClassUse_Packages.that.use.0", getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS_USE_HEADER, classdoc, false))); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); for (Iterator<PackageDoc> it = pkgSet.iterator(); it.hasNext();) { PackageDoc pkg = it.next(); @@ -234,12 +255,13 @@ public class ClassUseWriter extends SubWriterHolderWriter { pkgToPackageAnnotations == null || pkgToPackageAnnotations.size() == 0) return; - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(useTableSummary); + tableCaptionStart(); printText("doclet.ClassUse_PackageAnnotation", getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS_USE_HEADER, classdoc, false))); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); for (Iterator<PackageDoc> it = pkgToPackageAnnotations.iterator(); it.hasNext();) { PackageDoc pkg = it.next(); trBgcolorStyle("white", "TableRowColor"); @@ -300,83 +322,68 @@ public class ClassUseWriter extends SubWriterHolderWriter { LinkInfoImpl.CONTEXT_CLASS_USE_HEADER, classdoc, false)); String pkgLink = getPackageLink(pkg, Util.getPackageName(pkg), false); classSubWriter.printUseInfo(pkgToClassAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_Annotation", classLink, - pkgLink)); - + configuration.getText("doclet.ClassUse_Annotation", classLink, + pkgLink), classUseTableSummary); classSubWriter.printUseInfo(pkgToClassTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_TypeParameter", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_TypeParameter", classLink, + pkgLink), classUseTableSummary); classSubWriter.printUseInfo(pkgToSubclass.get(pkg.name()), - configuration.getText("doclet.ClassUse_Subclass", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_Subclass", classLink, + pkgLink), subclassUseTableSummary); classSubWriter.printUseInfo(pkgToSubinterface.get(pkg.name()), - configuration.getText("doclet.ClassUse_Subinterface", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_Subinterface", classLink, + pkgLink), subinterfaceUseTableSummary); classSubWriter.printUseInfo(pkgToImplementingClass.get(pkg.name()), - configuration.getText("doclet.ClassUse_ImplementingClass", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ImplementingClass", classLink, + pkgLink), classUseTableSummary); fieldSubWriter.printUseInfo(pkgToField.get(pkg.name()), - configuration.getText("doclet.ClassUse_Field", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_Field", classLink, + pkgLink), fieldUseTableSummary); fieldSubWriter.printUseInfo(pkgToFieldAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_FieldAnnotations", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_FieldAnnotations", classLink, + pkgLink), fieldUseTableSummary); fieldSubWriter.printUseInfo(pkgToFieldTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_FieldTypeParameter", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_FieldTypeParameter", classLink, + pkgLink), fieldUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodAnnotations", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodAnnotations", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodParameterAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodParameterAnnotations", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodParameterAnnotations", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodTypeParameter", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodTypeParameter", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodReturn.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodReturn", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodReturn", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodReturnTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodReturnTypeParameter", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodReturnTypeParameter", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodArgs.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodArgs", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodArgs", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodArgTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodArgsTypeParameters", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodArgsTypeParameters", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodThrows.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodThrows", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodThrows", classLink, + pkgLink), methodUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorAnnotations", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorAnnotations", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorParameterAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorParameterAnnotations", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorParameterAnnotations", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorArgs.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorArgs", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorArgs", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorArgTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorArgsTypeParameters", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorArgsTypeParameters", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorThrows.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorThrows", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorThrows", classLink, + pkgLink), constructorUseTableSummary); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java index c15f76367dc..8044b42dcbf 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java @@ -25,12 +25,12 @@ package com.sun.tools.doclets.formats.html; +import java.util.*; + +import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.util.*; import com.sun.tools.doclets.internal.toolkit.builders.*; -import com.sun.javadoc.*; - -import java.util.*; import com.sun.tools.doclets.internal.toolkit.taglets.*; /** @@ -171,8 +171,6 @@ public class ClassWriterImpl extends SubWriterHolderWriter */ public void writeClassSignature(String modifiers) { boolean isInterface = classDoc.isInterface(); - dl(); - dt(); preNoNewLine(); writeAnnotationInfo(classDoc); print(modifiers); @@ -191,7 +189,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter Type superclass = Util.getFirstVisibleSuperClass(classDoc, configuration()); if (superclass != null) { - dt(); + println(); print("extends "); printLink(new LinkInfoImpl( LinkInfoImpl.CONTEXT_CLASS_SIGNATURE_PARENT_NAME, @@ -208,7 +206,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter continue; } if (counter == 0) { - dt(); + println(); print(isInterface? "extends " : "implements "); } else { print(", "); @@ -219,7 +217,6 @@ public class ClassWriterImpl extends SubWriterHolderWriter counter++; } } - dlEnd(); preEnd(); p(); } @@ -342,6 +339,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter TagletOutput output = (new ParamTaglet()).getTagletOutput(classDoc, getTagletWriterInstance(false)); print(output.toString()); + dtEnd(); dlEnd(); } } @@ -360,8 +358,10 @@ public class ClassWriterImpl extends SubWriterHolderWriter dl(); dt(); strongText("doclet.Subclasses"); + dtEnd(); writeClassLinks(LinkInfoImpl.CONTEXT_SUBCLASSES, subclasses); + dlEnd(); } } } @@ -376,8 +376,10 @@ public class ClassWriterImpl extends SubWriterHolderWriter dl(); dt(); strongText("doclet.Subinterfaces"); + dtEnd(); writeClassLinks(LinkInfoImpl.CONTEXT_SUBINTERFACES, subInterfaces); + dlEnd(); } } } @@ -398,8 +400,10 @@ public class ClassWriterImpl extends SubWriterHolderWriter dl(); dt(); strongText("doclet.Implementing_Classes"); + dtEnd(); writeClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_CLASSES, implcl); + dlEnd(); } } @@ -414,8 +418,10 @@ public class ClassWriterImpl extends SubWriterHolderWriter dl(); dt(); strongText("doclet.All_Implemented_Interfaces"); + dtEnd(); writeClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_INTERFACES, interfaceArray); + dlEnd(); } } @@ -430,8 +436,10 @@ public class ClassWriterImpl extends SubWriterHolderWriter dl(); dt(); strongText("doclet.All_Superinterfaces"); + dtEnd(); writeClassLinks(LinkInfoImpl.CONTEXT_SUPER_INTERFACES, interfaceArray); + dlEnd(); } } @@ -455,7 +463,6 @@ public class ClassWriterImpl extends SubWriterHolderWriter } } ddEnd(); - dlEnd(); } protected void navLinkTree() { @@ -574,6 +581,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter } else { strongText("doclet.Enclosing_Class"); } + dtEnd(); dd(); printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, outerClass, false)); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConfigurationImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConfigurationImpl.java index 70d487da2ba..702f6f3fd3c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConfigurationImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConfigurationImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java index d64b2656d59..ddf51063a0a 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java @@ -35,6 +35,7 @@ import java.util.*; * Write the Constants Summary Page in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) * @since 1.4 */ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter @@ -50,6 +51,10 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter */ private ClassDoc currentClassDoc; + private final String constantsTableSummary; + + private final String[] constantsTableHeader; + /** * Construct a ConstantsSummaryWriter. * @param configuration the configuration used in this run @@ -59,6 +64,13 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter throws IOException { super(configuration, ConfigurationImpl.CONSTANTS_FILE_NAME); this.configuration = configuration; + constantsTableSummary = configuration.getText("doclet.Constants_Table_Summary", + configuration.getText("doclet.Constants_Summary")); + constantsTableHeader = new String[] { + getModifierTypeHeader(), + configuration.getText("doclet.ConstantField"), + configuration.getText("doclet.Value") + }; } /** @@ -151,12 +163,11 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter * @param classStr the heading to print. */ protected void writeClassName(String classStr) { - table(1, 3, 0); - trBgcolorStyle("#EEEEFF", "TableSubHeadingColor"); - thAlignColspan("left", 3); + table(1, 3, 0, constantsTableSummary); + tableSubCaptionStart(); write(classStr); - thEnd(); - trEnd(); + tableCaptionEnd(); + summaryTableHeader(constantsTableHeader, "col"); } private void tableFooter(boolean isHeader) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java index 72d2e7ca4c5..cc38edd8f2c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java @@ -25,18 +25,19 @@ package com.sun.tools.doclets.formats.html; +import java.io.*; +import java.util.*; + +import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.tools.doclets.internal.toolkit.taglets.*; -import com.sun.javadoc.*; -import java.util.*; -import java.io.*; /** * Writes constructor documentation. * * @author Robert Field * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter implements ConstructorWriter, MemberSummaryWriter { @@ -149,7 +150,7 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter writeParameters(constructor); writeExceptions(constructor); writer.preEnd(); - writer.dl(); + assert !writer.getMemberDetailsListPrinted(); } /** @@ -158,12 +159,7 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter * @param constructor the constructor being documented. */ public void writeDeprecated(ConstructorDoc constructor) { - String output = ((TagletOutputImpl) - (new DeprecatedTaglet()).getTagletOutput(constructor, - writer.getTagletWriterInstance(false))).toString(); - if (output != null && output.trim().length() > 0) { - writer.print(output); - } + printDeprecated(constructor); } /** @@ -172,10 +168,7 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter * @param constructor the constructor being documented. */ public void writeComments(ConstructorDoc constructor) { - if (constructor.inlineTags().length > 0) { - writer.dd(); - writer.printInlineComment(constructor); - } + printComment(constructor); } /** @@ -191,7 +184,7 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter * Write the constructor footer. */ public void writeConstructorFooter() { - writer.dlEnd(); + printMemberFooter(); } /** @@ -219,8 +212,34 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter this.foundNonPubConstructor = foundNonPubConstructor; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Constructor_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Constructor_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Constructor_Summary"), + configuration().getText("doclet.constructors"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header; + if (foundNonPubConstructor) { + header = new String[] { + configuration().getText("doclet.Modifier"), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Constructor"), + configuration().getText("doclet.Description")) + }; + } + else { + header = new String[] { + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Constructor"), + configuration().getText("doclet.Description")) + }; + } + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java index 68b04a7d72a..46c257b4b47 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java @@ -35,6 +35,7 @@ import java.io.*; * * @see java.util.List * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class DeprecatedListWriter extends SubWriterHolderWriter { @@ -55,6 +56,28 @@ public class DeprecatedListWriter extends SubWriterHolderWriter { "doclet.Deprecated_Annotation_Type_Members" }; + private static final String[] SUMMARY_KEYS = new String[] { + "doclet.deprecated_interfaces", "doclet.deprecated_classes", + "doclet.deprecated_enums", "doclet.deprecated_exceptions", + "doclet.deprecated_errors", + "doclet.deprecated_annotation_types", + "doclet.deprecated_fields", + "doclet.deprecated_methods", "doclet.deprecated_constructors", + "doclet.deprecated_enum_constants", + "doclet.deprecated_annotation_type_members" + }; + + private static final String[] HEADER_KEYS = new String[] { + "doclet.Interface", "doclet.Class", + "doclet.Enum", "doclet.Exceptions", + "doclet.Errors", + "doclet.AnnotationType", + "doclet.Field", + "doclet.Method", "doclet.Constructor", + "doclet.Enum_Constant", + "doclet.Annotation_Type_Member" + }; + private AbstractMemberWriter[] writers; private ConfigurationImpl configuration; @@ -119,11 +142,20 @@ public class DeprecatedListWriter extends SubWriterHolderWriter { ulEnd(); println(); + String memberTableSummary; + String[] memberTableHeader = new String[1]; for (int i = 0; i < DeprecatedAPIListBuilder.NUM_TYPES; i++) { if (deprapi.hasDocumentation(i)) { writeAnchor(deprapi, i); + memberTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText(HEADING_KEYS[i]), + configuration.getText(SUMMARY_KEYS[i])); + memberTableHeader[0] = configuration.getText("doclet.0_and_1", + configuration.getText(HEADER_KEYS[i]), + configuration.getText("doclet.Description")); writers[i].printDeprecatedAPI(deprapi.getList(i), - HEADING_KEYS[i]); + HEADING_KEYS[i], memberTableSummary, memberTableHeader); } } printDeprecatedFooter(); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java index 226d9086eeb..2e7c08bcfb5 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java @@ -25,17 +25,17 @@ package com.sun.tools.doclets.formats.html; -import com.sun.tools.doclets.internal.toolkit.*; -import com.sun.tools.doclets.internal.toolkit.taglets.*; -import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.javadoc.*; - import java.io.*; +import com.sun.javadoc.*; +import com.sun.tools.doclets.internal.toolkit.*; +import com.sun.tools.doclets.internal.toolkit.util.*; + /** * Writes enum constant documentation in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class EnumConstantWriterImpl extends AbstractMemberWriter implements EnumConstantWriter, MemberSummaryWriter { @@ -146,26 +146,21 @@ public class EnumConstantWriterImpl extends AbstractMemberWriter strong(enumConstant.name()); } writer.preEnd(); - writer.dl(); + assert !writer.getMemberDetailsListPrinted(); } /** * {@inheritDoc} */ public void writeDeprecated(FieldDoc enumConstant) { - print(((TagletOutputImpl) - (new DeprecatedTaglet()).getTagletOutput(enumConstant, - writer.getTagletWriterInstance(false))).toString()); + printDeprecated(enumConstant); } /** * {@inheritDoc} */ public void writeComments(FieldDoc enumConstant) { - if (enumConstant.inlineTags().length > 0) { - writer.dd(); - writer.printInlineComment(enumConstant); - } + printComment(enumConstant); } /** @@ -179,7 +174,7 @@ public class EnumConstantWriterImpl extends AbstractMemberWriter * {@inheritDoc} */ public void writeEnumConstantFooter() { - writer.dlEnd(); + printMemberFooter(); } /** @@ -200,8 +195,23 @@ public class EnumConstantWriterImpl extends AbstractMemberWriter return VisibleMemberMap.ENUM_CONSTANTS; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Enum_Constant_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Enum_Constant_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Enum_Constant_Summary"), + configuration().getText("doclet.enum_constants"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Enum_Constant"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java index cf37e9ad958..0f3b1cc0ef3 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java @@ -25,19 +25,19 @@ package com.sun.tools.doclets.formats.html; -import com.sun.tools.doclets.internal.toolkit.*; -import com.sun.tools.doclets.internal.toolkit.taglets.*; -import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.javadoc.*; - import java.io.*; +import com.sun.javadoc.*; +import com.sun.tools.doclets.internal.toolkit.*; +import com.sun.tools.doclets.internal.toolkit.util.*; + /** * Writes field documentation in HTML format. * * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) */ public class FieldWriterImpl extends AbstractMemberWriter implements FieldWriter, MemberSummaryWriter { @@ -156,7 +156,7 @@ public class FieldWriterImpl extends AbstractMemberWriter strong(field.name()); } writer.preEnd(); - writer.dl(); + assert !writer.getMemberDetailsListPrinted(); } /** @@ -165,9 +165,7 @@ public class FieldWriterImpl extends AbstractMemberWriter * @param field the field being documented. */ public void writeDeprecated(FieldDoc field) { - print(((TagletOutputImpl) - (new DeprecatedTaglet()).getTagletOutput(field, - writer.getTagletWriterInstance(false))).toString()); + printDeprecated(field); } /** @@ -178,10 +176,12 @@ public class FieldWriterImpl extends AbstractMemberWriter public void writeComments(FieldDoc field) { ClassDoc holder = field.containingClass(); if (field.inlineTags().length > 0) { + writer.printMemberDetailsListStartTag(); if (holder.equals(classdoc) || (! (holder.isPublic() || Util.isLinkable(holder, configuration())))) { writer.dd(); writer.printInlineComment(field); + writer.ddEnd(); } else { String classlink = writer.codeText( writer.getDocLink(LinkInfoImpl.CONTEXT_FIELD_DOC_COPY, @@ -196,6 +196,7 @@ public class FieldWriterImpl extends AbstractMemberWriter writer.ddEnd(); writer.dd(); writer.printInlineComment(field); + writer.ddEnd(); } } } @@ -213,7 +214,7 @@ public class FieldWriterImpl extends AbstractMemberWriter * Write the field footer. */ public void writeFieldFooter() { - writer.dlEnd(); + printMemberFooter(); } /** @@ -236,8 +237,24 @@ public class FieldWriterImpl extends AbstractMemberWriter return VisibleMemberMap.FIELDS; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Field_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Field_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Field_Summary"), + configuration().getText("doclet.fields"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Field"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java index 8a668cdc819..453b8e8e74a 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,17 +24,16 @@ */ package com.sun.tools.doclets.formats.html; -import com.sun.tools.doclets.formats.html.markup.*; -import com.sun.tools.doclets.internal.toolkit.*; -import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.tools.doclets.internal.toolkit.taglets.*; - -import com.sun.javadoc.*; import java.io.*; import java.text.SimpleDateFormat; import java.util.*; +import com.sun.javadoc.*; +import com.sun.tools.doclets.formats.html.markup.*; +import com.sun.tools.doclets.internal.toolkit.*; +import com.sun.tools.doclets.internal.toolkit.util.*; +import com.sun.tools.doclets.internal.toolkit.taglets.*; /** * Class for the Html Format Code Generation specific to JavaDoc. @@ -44,6 +43,7 @@ import java.util.*; * @since 1.2 * @author Atul M Dambalkar * @author Robert Field + * @author Bhavesh Patel (Modified) */ public class HtmlDocletWriter extends HtmlDocWriter { @@ -205,7 +205,13 @@ public class HtmlDocletWriter extends HtmlDocWriter { private void printMethodInfo(MethodDoc method) { ClassDoc[] intfacs = method.containingClass().interfaces(); MethodDoc overriddenMethod = method.overriddenMethod(); - if (intfacs.length > 0 || overriddenMethod != null) { + // Check whether there is any implementation or overridden info to be + // printed. If no overridden or implementation info needs to be + // printed, do not print this section. + if ((intfacs.length > 0 && + new ImplementedMethods(method, this.configuration).build().length > 0) || + overriddenMethod != null) { + printMemberDetailsListStartTag(); dd(); printTagsInfoHeader(); MethodWriterImpl.printImplementsInfo(this, method); @@ -216,7 +222,6 @@ public class HtmlDocletWriter extends HtmlDocWriter { printTagsInfoFooter(); ddEnd(); } - dd(); } protected void printTags(Doc doc) { @@ -230,20 +235,39 @@ public class HtmlDocletWriter extends HtmlDocWriter { TagletWriter.genTagOuput(configuration.tagletManager, doc, configuration.tagletManager.getCustomTags(doc), getTagletWriterInstance(false), output); - if (output.toString().trim().length() > 0) { - printTagsInfoHeader(); - print(output.toString()); - printTagsInfoFooter(); - } else if (! (doc instanceof ConstructorDoc || - doc instanceof RootDoc || doc instanceof ClassDoc)) { - //To be consistent with 1.4.2 output. - //I hate to do this but we have to pass the diff test to prove - //nothing has broken. + String outputString = output.toString().trim(); + // For RootDoc, ClassDoc and PackageDoc, this section is not the + // definition description but the start of definition list. + if (!outputString.isEmpty()) { + if (!(doc instanceof RootDoc || doc instanceof ClassDoc || + doc instanceof PackageDoc)) { + printMemberDetailsListStartTag(); + dd(); + } printTagsInfoHeader(); + print(outputString); printTagsInfoFooter(); + if (!(doc instanceof RootDoc || doc instanceof ClassDoc || + doc instanceof PackageDoc)) + ddEnd(); } } + /** + * Check whether there are any tags for Serialization Overview + * section to be printed. + * + * @param field the FieldDoc object to check for tags. + * @return true if there are tags to be printed else return false. + */ + protected boolean hasSerializationOverviewTags(FieldDoc field) { + TagletOutputImpl output = new TagletOutputImpl(""); + TagletWriter.genTagOuput(configuration.tagletManager, field, + configuration.tagletManager.getCustomTags(field), + getTagletWriterInstance(false), output); + return (!output.toString().trim().isEmpty()); + } + /** * Returns a TagletWriter that knows how to write HTML. * @@ -762,6 +786,15 @@ public class HtmlDocletWriter extends HtmlDocWriter { table(1, "100%", 3, 0); } + /** + * Print the Html table tag for the index summary tables. + * + * @param summary the summary for the table tag summary attribute. + */ + public void tableIndexSummary(String summary) { + table(1, "100%", 3, 0, summary); + } + /** * Same as {@link #tableIndexSummary()}. */ @@ -777,6 +810,40 @@ public class HtmlDocletWriter extends HtmlDocWriter { print("<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\">"); } + /** + * Print table caption. + */ + public void tableCaptionStart() { + captionStyle("TableCaption"); + } + + /** + * Print table sub-caption. + */ + public void tableSubCaptionStart() { + captionStyle("TableSubCaption"); + } + + /** + * Print table caption end tags. + */ + public void tableCaptionEnd() { + captionEnd(); + } + + /** + * Print summary table header. + */ + public void summaryTableHeader(String[] header, String scope) { + tr(); + for ( int i=0; i < header.length; i++ ) { + thScopeNoWrap("TableHeader", scope); + print(header[i]); + thEnd(); + } + trEnd(); + } + /** * Prine table header information about color, column span and the font. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialFieldWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialFieldWriter.java index 5b770658eca..8f8c072cac1 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialFieldWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialFieldWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,12 @@ package com.sun.tools.doclets.formats.html; +import java.util.*; + +import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.taglets.*; import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.javadoc.*; -import java.util.*; /** * Generate serialized form for serializable fields. @@ -37,6 +38,7 @@ import java.util.*; * <code>serialField</code> is processed. * * @author Joe Fialli + * @author Bhavesh Patel (Modified) */ public class HtmlSerialFieldWriter extends FieldWriterImpl implements SerializedFormWriter.SerialFieldWriter { @@ -75,7 +77,7 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl writer.println(); if (heading.equals( configuration().getText("doclet.Serialized_Form_class"))) { - writer.dl(); + assert !writer.getMemberDetailsListPrinted(); } } else { writer.printTableHeadingBackground(heading); @@ -102,7 +104,7 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl print(fieldDimensions + ' '); strong(fieldName); writer.preEnd(); - writer.dl(); + assert !writer.getMemberDetailsListPrinted(); } /** @@ -111,9 +113,7 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl * @param field the field to document. */ public void writeMemberDeprecatedInfo(FieldDoc field) { - print(((TagletOutputImpl) - (new DeprecatedTaglet()).getTagletOutput(field, - writer.getTagletWriterInstance(false))).toString()); + printDeprecated(field); } /** @@ -123,14 +123,17 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl */ public void writeMemberDescription(FieldDoc field) { if (field.inlineTags().length > 0) { + writer.printMemberDetailsListStartTag(); writer.dd(); writer.printInlineComment(field); + writer.ddEnd(); } Tag[] tags = field.tags("serial"); if (tags.length > 0) { - writer.dt(); + writer.printMemberDetailsListStartTag(); writer.dd(); writer.printInlineComment(field, tags[0]); + writer.ddEnd(); } } @@ -140,9 +143,14 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl * @param serialFieldTag the field to document (represented by tag). */ public void writeMemberDescription(SerialFieldTag serialFieldTag) { - writer.dd(); - writer.print(serialFieldTag.description()); - writer.dlEnd(); + String serialFieldTagDesc = serialFieldTag.description().trim(); + if (!serialFieldTagDesc.isEmpty()) { + writer.dl(); + writer.dd(); + writer.print(serialFieldTagDesc); + writer.ddEnd(); + writer.dlEnd(); + } } /** @@ -151,17 +159,57 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl * @param field the field to document. */ public void writeMemberTags(FieldDoc field) { - writer.dl(); TagletOutputImpl output = new TagletOutputImpl(""); TagletWriter.genTagOuput(configuration().tagletManager, field, configuration().tagletManager.getCustomTags(field), writer.getTagletWriterInstance(false), output); - if (output.toString().length() > 0) { - print(output.toString()); + String outputString = output.toString().trim(); + if (!outputString.isEmpty()) { + writer.printMemberDetailsListStartTag(); + writer.dd(); + writer.dl(); + print(outputString); + writer.dlEnd(); + writer.ddEnd(); } - writer.dlEnd(); } - public void writeMemberFooter(FieldDoc member) { - writer.dlEnd(); + + /** + * Check to see if overview details should be printed. If + * nocomment option set or if there is no text to be printed + * for deprecation info, comment or tags, do not print overview details. + * + * @param field the field to check overview details for. + * @return true if overview details need to be printed + */ + public boolean shouldPrintOverview(FieldDoc field) { + if (!configuration().nocomment) { + if(!field.commentText().isEmpty() || + writer.hasSerializationOverviewTags(field)) + return true; + } + if (field.tags("deprecated").length > 0) + return true; + return false; + } + + public void writeMemberFooter() { + printMemberFooter(); + } + + /** + * Write the footer information. If the serilization overview section was + * printed, check for definition list and close list tag. + * + * @param heading the heading that was written. + */ + public void writeFooter(String heading) { + if (printedOverallAnchor) { + if (heading.equals( + configuration().getText("doclet.Serialized_Form_class"))) { + writer.printMemberDetailsListEndTag(); + assert !writer.getMemberDetailsListPrinted(); + } + } } } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialMethodWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialMethodWriter.java index 9c0daf8e8cf..083ee7f25cd 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialMethodWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialMethodWriter.java @@ -25,9 +25,9 @@ package com.sun.tools.doclets.formats.html; +import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.taglets.*; -import com.sun.javadoc.*; /** * Generate serialized form for Serializable/Externalizable methods. @@ -66,14 +66,12 @@ public class HtmlSerialMethodWriter extends MethodWriterImpl implements writeSignature(member); } - public void writeMemberFooter(MethodDoc member) { - writer.dlEnd(); + public void writeMemberFooter() { + printMemberFooter(); } public void writeDeprecatedMemberInfo(MethodDoc member) { - print(((TagletOutputImpl) - (new DeprecatedTaglet()).getTagletOutput(member, - writer.getTagletWriterInstance(false))).toString()); + printDeprecated(member); } public void writeMemberDescription(MethodDoc member) { @@ -81,23 +79,27 @@ public class HtmlSerialMethodWriter extends MethodWriterImpl implements } public void writeMemberTags(MethodDoc member) { - writer.dd(); - writer.dl(); TagletOutputImpl output = new TagletOutputImpl(""); TagletManager tagletManager = ConfigurationImpl.getInstance().tagletManager; TagletWriter.genTagOuput(tagletManager, member, tagletManager.getSerializedFormTags(), writer.getTagletWriterInstance(false), output); - print(output.toString()); + String outputString = output.toString().trim(); + if (!outputString.isEmpty()) { + writer.printMemberDetailsListStartTag(); + writer.dd(); + writer.dl(); + print(outputString); + writer.dlEnd(); + writer.ddEnd(); + } MethodDoc method = member; if (method.name().compareTo("writeExternal") == 0 && method.tags("serialData").length == 0) { serialWarning(member.position(), "doclet.MissingSerialDataTag", method.containingClass().qualifiedName(), method.name()); } - writer.ddEnd(); - writer.dlEnd(); } protected void printTypeLinkNoDimension(Type type) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java index 7a4da14b0d6..c5500a34e4c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java @@ -25,19 +25,20 @@ package com.sun.tools.doclets.formats.html; +import java.io.*; + +import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.util.*; import com.sun.tools.doclets.internal.toolkit.taglets.*; -import java.io.*; -import com.sun.javadoc.*; - /** * Writes method documentation in HTML format. * * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) */ public class MethodWriterImpl extends AbstractExecutableMemberWriter implements MethodWriter, MemberSummaryWriter { @@ -172,7 +173,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter writeParameters(method); writeExceptions(method); writer.preEnd(); - writer.dl(); + assert !writer.getMemberDetailsListPrinted(); } /** @@ -181,12 +182,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter * @param method the method being documented. */ public void writeDeprecated(MethodDoc method) { - String output = ((TagletOutputImpl) - (new DeprecatedTaglet()).getTagletOutput(method, - writer.getTagletWriterInstance(false))).toString(); - if (output != null && output.trim().length() > 0) { - writer.print(output); - } + printDeprecated(method); } /** @@ -197,11 +193,13 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter public void writeComments(Type holder, MethodDoc method) { ClassDoc holderClassDoc = holder.asClassDoc(); if (method.inlineTags().length > 0) { + writer.printMemberDetailsListStartTag(); if (holder.asClassDoc().equals(classdoc) || (! (holderClassDoc.isPublic() || Util.isLinkable(holderClassDoc, configuration())))) { writer.dd(); writer.printInlineComment(method); + writer.ddEnd(); } else { String classlink = writer.codeText( writer.getDocLink(LinkInfoImpl.CONTEXT_METHOD_DOC_COPY, @@ -217,6 +215,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter writer.ddEnd(); writer.dd(); writer.printInlineComment(method); + writer.ddEnd(); } } } @@ -234,8 +233,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter * Write the method footer. */ public void writeMethodFooter() { - writer.ddEnd(); - writer.dlEnd(); + printMemberFooter(); } /** @@ -258,8 +256,24 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter return VisibleMemberMap.METHODS; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Method_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Method_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Method_Summary"), + configuration().getText("doclet.methods"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Method"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { @@ -318,6 +332,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter String name = method.name(); writer.dt(); writer.strongText(label); + writer.dtEnd(); writer.dd(); String methLink = writer.codeText( writer.getLink( @@ -326,6 +341,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter writer.getAnchor(method), name, false) )); writer.printText("doclet.in_class", methLink, overriddenTypeLink); + writer.ddEnd(); } } @@ -364,11 +380,13 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter LinkInfoImpl.CONTEXT_METHOD_SPECIFIED_BY, intfac))); writer.dt(); writer.strongText("doclet.Specified_By"); + writer.dtEnd(); writer.dd(); methlink = writer.codeText(writer.getDocLink( LinkInfoImpl.CONTEXT_MEMBER, implementedMeth, implementedMeth.name(), false)); writer.printText("doclet.in_interface", methlink, intfaclink); + writer.ddEnd(); } } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java index 2b3d2ea3709..c133708c108 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java @@ -25,11 +25,11 @@ package com.sun.tools.doclets.formats.html; +import java.io.*; + +import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.javadoc.*; - -import java.io.*; /** * Writes nested class documentation in HTML format. @@ -37,6 +37,7 @@ import java.io.*; * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) */ public class NestedClassWriterImpl extends AbstractMemberWriter implements MemberSummaryWriter { @@ -129,7 +130,6 @@ public class NestedClassWriterImpl extends AbstractMemberWriter writer.println(""); } writer.anchor(nestedClass.name()); - writer.dl(); writer.h3(); writer.print(nestedClass.name()); writer.h3End(); @@ -148,8 +148,35 @@ public class NestedClassWriterImpl extends AbstractMemberWriter return VisibleMemberMap.INNERCLASSES; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Nested_Class_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Nested_Class_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Nested_Class_Summary"), + configuration().getText("doclet.nested_classes"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header; + if (member.isInterface()) { + header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Interface"), + configuration().getText("doclet.Description")) + }; + } + else { + header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Class"), + configuration().getText("doclet.Description")) + }; + } + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java index ebc7118ab5d..035c48cfa80 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java @@ -114,7 +114,7 @@ public class PackageIndexFrameWriter extends AbstractPackageIndexWriter { * * @param text Text string will not be used in this method. */ - protected void printIndexHeader(String text) { + protected void printIndexHeader(String text, String tableSummary) { printTableHeader(false); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java index d7e7ee1696e..b785bf67c42 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import java.util.*; * with the "pacakge-summary.html" file for the clicked package. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class PackageIndexWriter extends AbstractPackageIndexWriter { @@ -123,7 +124,10 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter { List<PackageDoc> list = groupPackageMap.get(groupname); if (list != null && list.size() > 0) { printIndexContents(list.toArray(new PackageDoc[list.size()]), - groupname); + groupname, + configuration.getText("doclet.Member_Table_Summary", + groupname, + configuration.getText("doclet.packages"))); } } } @@ -149,11 +153,12 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter { /** * Print Html tags for the table for this package index. */ - protected void printIndexHeader(String text) { - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); - strong(text); - tableHeaderEnd(); + protected void printIndexHeader(String text, String tableSummary) { + tableIndexSummary(tableSummary); + tableCaptionStart(); + print(text); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageTreeWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageTreeWriter.java index 638c6d4d75f..12f6d4e0466 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageTreeWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageTreeWriter.java @@ -25,10 +25,11 @@ package com.sun.tools.doclets.formats.html; -import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.javadoc.*; import java.io.*; +import com.sun.javadoc.*; +import com.sun.tools.doclets.internal.toolkit.util.*; + /** * Class to generate Tree page for a package. The name of the file generated is * "package-tree.html" and it is generated in the respective package directory. @@ -145,8 +146,10 @@ public class PackageTreeWriter extends AbstractTreeWriter { dl(); dt(); strongText("doclet.Package_Hierarchies"); + dtEnd(); dd(); navLinkMainTree(configuration.getText("doclet.All_Packages")); + ddEnd(); dlEnd(); hr(); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java index a83cc3d70a0..d817ca5ad3b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java @@ -34,6 +34,7 @@ import java.util.*; * Generate package usage information. * * @author Robert G. Field + * @author Bhavesh Patel (Modified) */ public class PackageUseWriter extends SubWriterHolderWriter { @@ -131,11 +132,12 @@ public class PackageUseWriter extends SubWriterHolderWriter { } protected void generatePackageList() throws IOException { - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(useTableSummary); + tableCaptionStart(); printText("doclet.ClassUse_Packages.that.use.0", getPackageLink(pkgdoc, Util.getPackageName(pkgdoc), false)); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); Iterator<String> it = usingPackageToUsedClasses.keySet().iterator(); while (it.hasNext()) { PackageDoc pkg = configuration.root.packageNamed(it.next()); @@ -147,6 +149,11 @@ public class PackageUseWriter extends SubWriterHolderWriter { } protected void generateClassList() throws IOException { + String[] classTableHeader = new String[] { + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Class"), + configuration.getText("doclet.Description")) + }; Iterator<String> itp = usingPackageToUsedClasses.keySet().iterator(); while (itp.hasNext()) { String packageName = itp.next(); @@ -154,12 +161,14 @@ public class PackageUseWriter extends SubWriterHolderWriter { if (usingPackage != null) { anchor(usingPackage.name()); } - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.classes"))); + tableCaptionStart(); printText("doclet.ClassUse_Classes.in.0.used.by.1", getPackageLink(pkgdoc, Util.getPackageName(pkgdoc), false), getPackageLink(usingPackage,Util.getPackageName(usingPackage), false)); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(classTableHeader, "col"); Iterator<ClassDoc> itc = usingPackageToUsedClasses.get(packageName).iterator(); while (itc.hasNext()) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java index eca6d49bbbf..60aa692ce0f 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java @@ -38,6 +38,7 @@ import java.util.*; * class-kind will update the frame with the clicked class-kind page. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class PackageWriterImpl extends HtmlDocletWriter implements PackageSummaryWriter { @@ -107,14 +108,15 @@ public class PackageWriterImpl extends HtmlDocletWriter /** * {@inheritDoc} */ - public void writeClassesSummary(ClassDoc[] classes, String label) { + public void writeClassesSummary(ClassDoc[] classes, String label, String tableSummary, String[] tableHeader) { if(classes.length > 0) { Arrays.sort(classes); - tableIndexSummary(); + tableIndexSummary(tableSummary); boolean printedHeading = false; for (int i = 0; i < classes.length; i++) { if (!printedHeading) { - printFirstRow(label); + printTableCaption(label); + printFirstRow(tableHeader); printedHeading = true; } if (!Util.isCoreClass(classes[i]) || @@ -148,15 +150,24 @@ public class PackageWriterImpl extends HtmlDocletWriter } } + /** + * Print the table caption for the class-listing. + * + * @param label label for the Class kind listing. + */ + protected void printTableCaption(String label) { + tableCaptionStart(); + print(label); + tableCaptionEnd(); + } + /** * Print the table heading for the class-listing. * - * @param label Label for the Class kind listing. + * @param tableHeader table header string for the Class listing. */ - protected void printFirstRow(String label) { - tableHeaderStart("#CCCCFF"); - strong(label); - tableHeaderEnd(); + protected void printFirstRow(String[] tableHeader) { + summaryTableHeader(tableHeader, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java index 1384bbb2bd5..f6664f94c1c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java @@ -33,6 +33,7 @@ import java.io.*; * Writes the style sheet for the doclet output. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class StylesheetWriter extends HtmlDocletWriter { @@ -115,6 +116,13 @@ public class StylesheetWriter extends HtmlDocletWriter { println("background-color:#FFFFFF; color:#000000}"); print(".NavBarCell3 { font-family: Arial, Helvetica, sans-serif; "); println("background-color:#FFFFFF; color:#000000}"); + + print("/* "); printText("doclet.Style_line_12"); println(" */"); + print(".TableCaption { background: #CCCCFF; color:#000000; text-align: left; font-size: 150%; font-weight: bold; border-left: 2px ridge; border-right: 2px ridge; border-top: 2px ridge; padding-left: 5px; }"); + print(" /* "); printText("doclet.Style_line_5"); println(" */"); + print(".TableSubCaption { background: #EEEEFF; color:#000000; text-align: left; font-weight: bold; border-left: 2px ridge; border-right: 2px ridge; border-top: 2px ridge; padding-left: 5px; }"); + print(" /* "); printText("doclet.Style_line_6"); println(" */"); + print(".TableHeader { text-align: center; font-size: 80%; font-weight: bold; }"); println(""); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java index f6b6b98b6e5..b1a2f868687 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java @@ -43,6 +43,7 @@ import java.io.*; * * @author Robert Field * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { @@ -72,10 +73,11 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { public void printSummaryHeader(AbstractMemberWriter mw, ClassDoc cd) { mw.printSummaryAnchor(cd); - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); - mw.printSummaryLabel(cd); - tableHeaderEnd(); + mw.printTableSummary(); + tableCaptionStart(); + mw.printSummaryLabel(); + tableCaptionEnd(); + mw.printSummaryTableHeader(cd); } public void printTableHeadingBackground(String str) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletOutputImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletOutputImpl.java index af8532486fe..f78b0e84a3b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletOutputImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletOutputImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,4 +67,10 @@ public class TagletOutputImpl implements TagletOutput { return output.toString(); } + /** + * Check whether the taglet output is empty. + */ + public boolean isEmpty() { + return (toString().trim().isEmpty()); + } } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletWriterImpl.java index 353937f630a..e83e6f9bdfe 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletWriterImpl.java @@ -25,17 +25,18 @@ package com.sun.tools.doclets.formats.html; +import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.builders.SerializedFormBuilder; import com.sun.tools.doclets.internal.toolkit.taglets.*; import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.javadoc.*; /** * The taglet writer that writes HTML. * * @since 1.5 * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class TagletWriterImpl extends TagletWriter { @@ -99,11 +100,12 @@ public class TagletWriterImpl extends TagletWriter { output.append(DocletConstants.NL + "<P>" + DocletConstants.NL); } + output.append("</DD>"); } else { if (Util.isDeprecated(member.containingClass())) { output.append("<DD><STRONG>" + ConfigurationImpl.getInstance(). - getText("doclet.Deprecated") + "</STRONG> "); + getText("doclet.Deprecated") + "</STRONG> </DD>"); } } } @@ -123,7 +125,7 @@ public class TagletWriterImpl extends TagletWriter { public TagletOutput getParamHeader(String header) { StringBuffer result = new StringBuffer(); result.append("<DT>"); - result.append("<STRONG>" + header + "</STRONG>"); + result.append("<STRONG>" + header + "</STRONG></DT>"); return new TagletOutputImpl(result.toString()); } @@ -132,7 +134,7 @@ public class TagletWriterImpl extends TagletWriter { */ public TagletOutput paramTagOutput(ParamTag paramTag, String paramName) { TagletOutput result = new TagletOutputImpl("<DD><CODE>" + paramName + "</CODE>" - + " - " + htmlWriter.commentTagsToString(paramTag, null, paramTag.inlineTags(), false)); + + " - " + htmlWriter.commentTagsToString(paramTag, null, paramTag.inlineTags(), false) + "</DD>"); return result; } @@ -142,9 +144,9 @@ public class TagletWriterImpl extends TagletWriter { public TagletOutput returnTagOutput(Tag returnTag) { TagletOutput result = new TagletOutputImpl(DocletConstants.NL + "<DT>" + "<STRONG>" + htmlWriter.configuration.getText("doclet.Returns") + - "</STRONG>" + "<DD>" + + "</STRONG>" + "</DT>" + "<DD>" + htmlWriter.commentTagsToString(returnTag, null, returnTag.inlineTags(), - false)); + false) + "</DD>"); return result; } @@ -174,22 +176,21 @@ public class TagletWriterImpl extends TagletWriter { } if (holder.isClass() && ((ClassDoc)holder).isSerializable()) { //Automatically add link to serialized form page for serializable classes. - if (!(SerializedFormBuilder.serialInclude(holder) && + if ((SerializedFormBuilder.serialInclude(holder) && SerializedFormBuilder.serialInclude(((ClassDoc)holder).containingPackage()))) { - return result.equals("") ? null : new TagletOutputImpl(result); + result = addSeeHeader(result); + result += htmlWriter.getHyperLink(htmlWriter.relativePath + "serialized-form.html", + ((ClassDoc)holder).qualifiedName(), htmlWriter.configuration.getText("doclet.Serialized_Form"), false); } - result = addSeeHeader(result); - result += htmlWriter.getHyperLink(htmlWriter.relativePath + "serialized-form.html", - ((ClassDoc)holder).qualifiedName(), htmlWriter.configuration.getText("doclet.Serialized_Form"), false); } - return result.equals("") ? null : new TagletOutputImpl(result); + return result.equals("") ? null : new TagletOutputImpl(result + "</DD>"); } private String addSeeHeader(String result) { if (result != null && result.length() > 0) { return result + ", " + DocletConstants.NL; } else { - return "<DT><STRONG>" + htmlWriter.configuration().getText("doclet.See_Also") + "</STRONG><DD>"; + return "<DT><STRONG>" + htmlWriter.configuration().getText("doclet.See_Also") + "</STRONG></DT><DD>"; } } @@ -205,7 +206,8 @@ public class TagletWriterImpl extends TagletWriter { } result += htmlWriter.commentTagsToString(simpleTags[i], null, simpleTags[i].inlineTags(), false); } - return new TagletOutputImpl(result + "</DD>" + DocletConstants.NL); + result += "</DD>" + DocletConstants.NL; + return new TagletOutputImpl(result); } /** @@ -222,7 +224,7 @@ public class TagletWriterImpl extends TagletWriter { */ public TagletOutput getThrowsHeader() { return new TagletOutputImpl(DocletConstants.NL + "<DT>" + "<STRONG>" + - htmlWriter.configuration().getText("doclet.Throws") + "</STRONG>"); + htmlWriter.configuration().getText("doclet.Throws") + "</STRONG></DT>"); } /** @@ -241,6 +243,7 @@ public class TagletWriterImpl extends TagletWriter { if (text != null && text.toString().length() > 0) { result += " - " + text; } + result += "</DD>"; return new TagletOutputImpl(result); } @@ -250,7 +253,7 @@ public class TagletWriterImpl extends TagletWriter { public TagletOutput throwsTagOutput(Type throwsType) { return new TagletOutputImpl(DocletConstants.NL + "<DD>" + htmlWriter.codeText(htmlWriter.getLink( - new LinkInfoImpl(LinkInfoImpl.CONTEXT_MEMBER, throwsType)))); + new LinkInfoImpl(LinkInfoImpl.CONTEXT_MEMBER, throwsType))) + "</DD>"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TreeWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TreeWriter.java index 669cd1c86a1..7760df955d9 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TreeWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TreeWriter.java @@ -25,9 +25,11 @@ package com.sun.tools.doclets.formats.html; -import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.javadoc.*; import java.io.*; + +import com.sun.javadoc.*; +import com.sun.tools.doclets.internal.toolkit.util.*; + /** * Generate Class Hierarchy page for all the Classes in this run. Use * ClassTree for building the Tree. The name of @@ -120,6 +122,7 @@ public class TreeWriter extends AbstractTreeWriter { dl(); dt(); strongText("doclet.Package_Hierarchies"); + dtEnd(); dd(); for (int i = 0; i < packages.length; i++) { if (packages[i].name().length() == 0) { @@ -131,6 +134,7 @@ public class TreeWriter extends AbstractTreeWriter { print(", "); } } + ddEnd(); dlEnd(); hr(); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java index d4cdd39b1ce..57f57fc1287 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,6 +244,31 @@ public abstract class HtmlDocWriter extends HtmlWriter { return ""; } + /** + * Keep track of member details list. Print the definition list start tag + * if it is not printed yet. + */ + public void printMemberDetailsListStartTag () { + if (!getMemberDetailsListPrinted()) { + dl(); + memberDetailsListPrinted = true; + } + } + + /** + * Print the definition list end tag if the list start tag was printed. + */ + public void printMemberDetailsListEndTag () { + if (getMemberDetailsListPrinted()) { + dlEnd(); + memberDetailsListPrinted = false; + } + } + + public boolean getMemberDetailsListPrinted() { + return memberDetailsListPrinted; + } + /** * Print the frameset version of the Html file header. * Called only when generating an HTML frameset file. diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java index cdafe1be907..cad683d9fa4 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,10 @@ package com.sun.tools.doclets.formats.html.markup; +import java.io.*; + import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.util.*; -import java.io.*; /** * Class for the Html format code generation. @@ -36,6 +37,7 @@ import java.io.*; * * @since 1.2 * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class HtmlWriter extends PrintWriter { @@ -60,6 +62,26 @@ public class HtmlWriter extends PrintWriter { */ protected Configuration configuration; + /** + * The flag to indicate whether a member details list is printed or not. + */ + protected boolean memberDetailsListPrinted; + + /** + * Header for tables displaying packages and description.. + */ + protected final String[] packageTableHeader; + + /** + * Summary for use tables displaying class and package use. + */ + protected final String useTableSummary; + + /** + * Column header for class docs displaying Modifier and Type header. + */ + protected final String modifierTypeHeader; + /** * Constructor. * @@ -79,6 +101,16 @@ public class HtmlWriter extends PrintWriter { super(Util.genWriter(configuration, path, filename, docencoding)); this.configuration = configuration; htmlFilename = filename; + this.memberDetailsListPrinted = false; + packageTableHeader = new String[] { + configuration.getText("doclet.Package"), + configuration.getText("doclet.Description") + }; + useTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.packages")); + modifierTypeHeader = configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Modifier"), + configuration.getText("doclet.Type")); } /** @@ -529,7 +561,14 @@ public class HtmlWriter extends PrintWriter { } /** - * Print <DT> tag. + * Print </DT> tag. + */ + public void dtEnd() { + print("</DT>"); + } + + /** + * Print <DD> tag. */ public void dd() { print("<DD>"); @@ -788,6 +827,26 @@ public class HtmlWriter extends PrintWriter { "\" SUMMARY=\"\">"); } + /** + * Print HTML <TABLE BORDER="border" WIDTH="width" + * CELLPADDING="cellpadding" CELLSPACING="cellspacing" SUMMARY="summary"> tag. + * + * @param border Border size. + * @param width Width of the table. + * @param cellpadding Cellpadding for the table cells. + * @param cellspacing Cellspacing for the table cells. + * @param summary Table summary. + */ + public void table(int border, String width, int cellpadding, + int cellspacing, String summary) { + println(DocletConstants.NL + + "<TABLE BORDER=\"" + border + + "\" WIDTH=\"" + width + + "\" CELLPADDING=\"" + cellpadding + + "\" CELLSPACING=\"" + cellspacing + + "\" SUMMARY=\"" + summary + "\">"); + } + /** * Print HTML <TABLE BORDER="border" CELLPADDING="cellpadding" * CELLSPACING="cellspacing"> tag. @@ -804,6 +863,23 @@ public class HtmlWriter extends PrintWriter { "\" SUMMARY=\"\">"); } + /** + * Print HTML <TABLE BORDER="border" CELLPADDING="cellpadding" + * CELLSPACING="cellspacing" SUMMARY="summary"> tag. + * + * @param border Border size. + * @param cellpadding Cellpadding for the table cells. + * @param cellspacing Cellspacing for the table cells. + * @param summary Table summary. + */ + public void table(int border, int cellpadding, int cellspacing, String summary) { + println(DocletConstants.NL + + "<TABLE BORDER=\"" + border + + "\" CELLPADDING=\"" + cellpadding + + "\" CELLSPACING=\"" + cellspacing + + "\" SUMMARY=\"" + summary + "\">"); + } + /** * Print HTML <TABLE BORDER="border" WIDTH="width"> * @@ -898,6 +974,23 @@ public class HtmlWriter extends PrintWriter { println("-->"); } + /** + * Print <CAPTION CLASS="stylename"> tag. Adds a newline character + * at the end. + * + * @param stylename style to be applied. + */ + public void captionStyle(String stylename) { + println("<CAPTION CLASS=\"" + stylename + "\">"); + } + + /** + * Print </CAPTION> tag. Add a newline character at the end. + */ + public void captionEnd() { + println("</CAPTION>"); + } + /** * Print <TR BGCOLOR="color" CLASS="stylename"> tag. Adds a newline character * at the end. @@ -938,6 +1031,23 @@ public class HtmlWriter extends PrintWriter { print("<TH ALIGN=\"" + align + "\">"); } + /** + * Print <TH CLASS="stylename" SCOPE="scope" NOWRAP> tag. + * + * @param stylename style to be applied. + * @param scope the scope attribute. + */ + public void thScopeNoWrap(String stylename, String scope) { + print("<TH CLASS=\"" + stylename + "\" SCOPE=\"" + scope + "\" NOWRAP>"); + } + + /* + * Returns a header for Modifier and Type column of a table. + */ + public String getModifierTypeHeader() { + return modifierTypeHeader; + } + /** * Print <TH align="align" COLSPAN=i> tag. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties index 492a77e7fcc..f4d86e3d5d8 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties @@ -83,6 +83,17 @@ doclet.Deprecated_Constructors=Deprecated Constructors doclet.Deprecated_Methods=Deprecated Methods doclet.Deprecated_Enum_Constants=Deprecated Enum Constants doclet.Deprecated_Annotation_Type_Members=Deprecated Annotation Type Elements +doclet.deprecated_classes=deprecated classes +doclet.deprecated_enums=deprecated enums +doclet.deprecated_interfaces=deprecated interfaces +doclet.deprecated_exceptions=deprecated exceptions +doclet.deprecated_annotation_types=deprecated annotation types +doclet.deprecated_errors=deprecated errors +doclet.deprecated_fields=deprecated fields +doclet.deprecated_constructors=deprecated constructors +doclet.deprecated_methods=deprecated methods +doclet.deprecated_enum_constants=deprecated enum constants +doclet.deprecated_annotation_type_members=deprecated annotation type elements doclet.Frame_Output=Frame Output doclet.Docs_generated_by_Javadoc=Documentation generated by Javadoc. doclet.Generated_Docs_Untitled=Generated Documentation (Untitled) @@ -171,6 +182,7 @@ doclet.Style_line_8=Font used in left-hand frame lists doclet.Style_line_9=Example of smaller, sans-serif font in frames doclet.Style_line_10=Navigation bar fonts and colors doclet.Style_line_11=Dark Blue +doclet.Style_line_12=Table caption style doclet.ClassUse_Packages.that.use.0=Packages that use {0} doclet.ClassUse_Uses.of.0.in.1=Uses of {0} in {1} doclet.ClassUse_Classes.in.0.used.by.1=Classes in {0} used by {1} diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java index eb8960f4c65..88e76405a8d 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java index eb86fbea2d9..d46807d02e4 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java @@ -64,7 +64,7 @@ public interface PackageSummaryWriter { * @param classes the array of classes to document. * @param label the label for this table. */ - public abstract void writeClassesSummary(ClassDoc[] classes, String label); + public abstract void writeClassesSummary(ClassDoc[] classes, String label, String tableSummary, String[] tableHeader); /** * Write the header for the summary. diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/SerializedFormWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/SerializedFormWriter.java index 06fbb613365..133f218877d 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/SerializedFormWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/SerializedFormWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,10 @@ package com.sun.tools.doclets.internal.toolkit; -import com.sun.javadoc.*; import java.io.*; +import com.sun.javadoc.*; + /** * The interface for writing serialized form output. * @@ -146,12 +147,28 @@ public interface SerializedFormWriter { public void writeMemberHeader(ClassDoc fieldType, String fieldTypeStr, String fieldDimensions, String fieldName); + /** + * Write the member footer. + */ + public void writeMemberFooter(); + + /** + * Check to see if overview details should be printed. If + * nocomment option set or if there is no text to be printed + * for deprecation info, inline comment or tags, + * do not print overview details. + * + * @param field the field to check overview details for. + * @return true if overview details need to be printed + */ + public boolean shouldPrintOverview(FieldDoc field); + /** * Write the footer. * - * @param member the member to write the header for. + * @param heading the heading that was written. */ - public void writeMemberFooter(FieldDoc member); + public void writeFooter (String heading); } /** @@ -182,10 +199,8 @@ public interface SerializedFormWriter { /** * Write the footer. - * - * @param member the member to write the header for. */ - public void writeMemberFooter(MethodDoc member); + public void writeMemberFooter(); /** * Write the deprecated information for this member. diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java index c85b0b30b8d..ac25c257739 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java @@ -40,6 +40,7 @@ import java.lang.reflect.*; * Do not use it as an API * * @author Jamie Ho + * @author Bhavesh Patel (Modified) * @since 1.5 */ public class PackageSummaryBuilder extends AbstractBuilder { @@ -184,7 +185,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the classes in this package. */ public void buildClassSummary() { - ClassDoc[] classes = + String classTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Class_Summary"), + configuration.getText("doclet.classes")); + String[] classTableHeader = new String[] { + configuration.getText("doclet.Class"), + configuration.getText("doclet.Description") + }; + ClassDoc[] classes = packageDoc.isIncluded() ? packageDoc.ordinaryClasses() : configuration.classDocCatalog.ordinaryClasses( @@ -192,7 +201,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (classes.length > 0) { packageWriter.writeClassesSummary( classes, - configuration.getText("doclet.Class_Summary")); + configuration.getText("doclet.Class_Summary"), + classTableSummary, classTableHeader); } } @@ -200,7 +210,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the interfaces in this package. */ public void buildInterfaceSummary() { - ClassDoc[] interfaces = + String interfaceTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Interface_Summary"), + configuration.getText("doclet.interfaces")); + String[] interfaceTableHeader = new String[] { + configuration.getText("doclet.Interface"), + configuration.getText("doclet.Description") + }; + ClassDoc[] interfaces = packageDoc.isIncluded() ? packageDoc.interfaces() : configuration.classDocCatalog.interfaces( @@ -208,7 +226,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (interfaces.length > 0) { packageWriter.writeClassesSummary( interfaces, - configuration.getText("doclet.Interface_Summary")); + configuration.getText("doclet.Interface_Summary"), + interfaceTableSummary, interfaceTableHeader); } } @@ -216,7 +235,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the enums in this package. */ public void buildAnnotationTypeSummary() { - ClassDoc[] annotationTypes = + String annotationtypeTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Annotation_Types_Summary"), + configuration.getText("doclet.annotationtypes")); + String[] annotationtypeTableHeader = new String[] { + configuration.getText("doclet.AnnotationType"), + configuration.getText("doclet.Description") + }; + ClassDoc[] annotationTypes = packageDoc.isIncluded() ? packageDoc.annotationTypes() : configuration.classDocCatalog.annotationTypes( @@ -224,7 +251,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (annotationTypes.length > 0) { packageWriter.writeClassesSummary( annotationTypes, - configuration.getText("doclet.Annotation_Types_Summary")); + configuration.getText("doclet.Annotation_Types_Summary"), + annotationtypeTableSummary, annotationtypeTableHeader); } } @@ -232,7 +260,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the enums in this package. */ public void buildEnumSummary() { - ClassDoc[] enums = + String enumTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Enum_Summary"), + configuration.getText("doclet.enums")); + String[] enumTableHeader = new String[] { + configuration.getText("doclet.Enum"), + configuration.getText("doclet.Description") + }; + ClassDoc[] enums = packageDoc.isIncluded() ? packageDoc.enums() : configuration.classDocCatalog.enums( @@ -240,7 +276,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (enums.length > 0) { packageWriter.writeClassesSummary( enums, - configuration.getText("doclet.Enum_Summary")); + configuration.getText("doclet.Enum_Summary"), + enumTableSummary, enumTableHeader); } } @@ -248,7 +285,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the exceptions in this package. */ public void buildExceptionSummary() { - ClassDoc[] exceptions = + String exceptionTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Exception_Summary"), + configuration.getText("doclet.exceptions")); + String[] exceptionTableHeader = new String[] { + configuration.getText("doclet.Exception"), + configuration.getText("doclet.Description") + }; + ClassDoc[] exceptions = packageDoc.isIncluded() ? packageDoc.exceptions() : configuration.classDocCatalog.exceptions( @@ -256,7 +301,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (exceptions.length > 0) { packageWriter.writeClassesSummary( exceptions, - configuration.getText("doclet.Exception_Summary")); + configuration.getText("doclet.Exception_Summary"), + exceptionTableSummary, exceptionTableHeader); } } @@ -264,7 +310,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the errors in this package. */ public void buildErrorSummary() { - ClassDoc[] errors = + String errorTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Error_Summary"), + configuration.getText("doclet.errors")); + String[] errorTableHeader = new String[] { + configuration.getText("doclet.Error"), + configuration.getText("doclet.Description") + }; + ClassDoc[] errors = packageDoc.isIncluded() ? packageDoc.errors() : configuration.classDocCatalog.errors( @@ -272,7 +326,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (errors.length > 0) { packageWriter.writeClassesSummary( errors, - configuration.getText("doclet.Error_Summary")); + configuration.getText("doclet.Error_Summary"), + errorTableSummary, errorTableHeader); } } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/SerializedFormBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/SerializedFormBuilder.java index 636db90d02a..59a8f94f2a5 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/SerializedFormBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/SerializedFormBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,14 @@ package com.sun.tools.doclets.internal.toolkit.builders; -import com.sun.tools.doclets.internal.toolkit.util.*; -import com.sun.tools.doclets.internal.toolkit.*; -import com.sun.javadoc.*; import java.io.*; import java.lang.reflect.*; import java.util.*; +import com.sun.javadoc.*; +import com.sun.tools.doclets.internal.toolkit.util.*; +import com.sun.tools.doclets.internal.toolkit.*; + /** * Builds the serialized form. * @@ -40,6 +41,7 @@ import java.util.*; * Do not use it as an API * * @author Jamie Ho + * @author Bhavesh Patel (Modified) * @since 1.5 */ public class SerializedFormBuilder extends AbstractBuilder { @@ -379,7 +381,7 @@ public class SerializedFormBuilder extends AbstractBuilder { * Build the method footer. */ public void buildMethodFooter() { - methodWriter.writeMemberFooter((MethodDoc) currentMember); + methodWriter.writeMemberFooter(); } /** @@ -403,16 +405,20 @@ public class SerializedFormBuilder extends AbstractBuilder { if (classDoc.definesSerializableFields()) { FieldDoc serialPersistentField = Util.asList(classDoc.serializableFields()).get(0); - String comment = serialPersistentField.commentText(); - if (comment.length() > 0) { + // Check to see if there are inline comments, tags or deprecation + // information to be printed. + if (fieldWriter.shouldPrintOverview(serialPersistentField)) { fieldWriter.writeHeader( - configuration.getText("doclet.Serialized_Form_class")); + configuration.getText("doclet.Serialized_Form_class")); + fieldWriter.writeMemberDeprecatedInfo(serialPersistentField); if (!configuration.nocomment) { - fieldWriter.writeMemberDeprecatedInfo(serialPersistentField); fieldWriter.writeMemberDescription(serialPersistentField); fieldWriter.writeMemberTags(serialPersistentField); - fieldWriter.writeMemberFooter(serialPersistentField); } + // Footer required to close the definition list tag + // for serialization overview. + fieldWriter.writeFooter( + configuration.getText("doclet.Serialized_Form_class")); } } } @@ -428,6 +434,16 @@ public class SerializedFormBuilder extends AbstractBuilder { } } + /** + * Build the field deprecation information. + */ + public void buildFieldDeprecationInfo() { + if (!currentClass.definesSerializableFields()) { + FieldDoc field = (FieldDoc)currentMember; + fieldWriter.writeMemberDeprecatedInfo(field); + } + } + /** * Build the field information. */ @@ -459,18 +475,17 @@ public class SerializedFormBuilder extends AbstractBuilder { "doclet.MissingSerialTag", cd.qualifiedName(), field.name()); } - fieldWriter.writeMemberDeprecatedInfo(field); fieldWriter.writeMemberDescription(field); fieldWriter.writeMemberTags(field); } } /** - * Build the field footer. + * Build the field sub footer. */ - public void buildFieldFooter() { + public void buildFieldSubFooter() { if (! currentClass.definesSerializableFields()) { - fieldWriter.writeMemberFooter((FieldDoc) currentMember); + fieldWriter.writeMemberFooter(); } } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml index 2ecd8369005..fa1f6181782 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml @@ -1,7 +1,7 @@ -<?xml version='1.0' encoding='utf-8'?> +<?xml version='1.0' encoding='utf-8'?> <!-- - Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. This code is free software; you can redistribute it and/or modify it @@ -25,180 +25,181 @@ have any questions. --> - -<Doclet> - - <PackageDoc> - <PackageHeader/> - <Summary> - <SummaryHeader/> - <InterfaceSummary/> - <ClassSummary/> - <EnumSummary/> - <ExceptionSummary/> - <ErrorSummary/> - <AnnotationTypeSummary/> - <SummaryFooter/> - </Summary> - <PackageDescription/> - <PackageTags/> - <PackageFooter/> - </PackageDoc> - - <AnnotationTypeDoc> - <AnnotationTypeHeader/> - <DeprecationInfo/> - <AnnotationTypeSignature/> - <AnnotationTypeDescription/> - <AnnotationTypeTagInfo/> - <MemberSummary> - <AnnotationTypeRequiredMemberSummary/> - <AnnotationTypeOptionalMemberSummary/> - </MemberSummary> - <AnnotationTypeRequiredMemberDetails> - <Header/> - <AnnotationTypeRequiredMember> - <MemberHeader/> - <Signature/> - <DeprecationInfo/> - <MemberComments/> - <TagInfo/> - <MemberFooter/> - </AnnotationTypeRequiredMember> - </AnnotationTypeRequiredMemberDetails> - <AnnotationTypeOptionalMemberDetails> - <AnnotationTypeOptionalMember> - <MemberHeader/> - <Signature/> - <DeprecationInfo/> - <MemberComments/> - <TagInfo/> - <DefaultValueInfo/> - <MemberFooter/> - </AnnotationTypeOptionalMember> - <Footer/> - </AnnotationTypeOptionalMemberDetails> - <AnnotationTypeFooter/> - </AnnotationTypeDoc> - - <ClassDoc> - <ClassHeader/> - <ClassTree/> - <TypeParamInfo/> - <SuperInterfacesInfo/> - <ImplementedInterfacesInfo/> - <SubClassInfo/> - <SubInterfacesInfo/> - <InterfaceUsageInfo/> - <NestedClassInfo/> - <DeprecationInfo/> - <ClassSignature/> - <ClassDescription/> - <ClassTagInfo/> - <MemberSummary> - <NestedClassesSummary/> - <NestedClassesInheritedSummary/> - <EnumConstantsSummary/> - <FieldsSummary/> - <FieldsInheritedSummary/> - <ConstructorsSummary/> - <MethodsSummary/> - <MethodsInheritedSummary/> - </MemberSummary> - <EnumConstantsDetails> - <Header/> - <EnumConstant> - <EnumConstantHeader/> - <Signature/> - <DeprecationInfo/> - <EnumConstantComments/> - <TagInfo/> - <EnumConstantFooter/> - </EnumConstant> - <Footer/> - </EnumConstantsDetails> - <FieldDetails> - <Header/> - <FieldDoc> - <FieldHeader/> - <Signature/> - <DeprecationInfo/> - <FieldComments/> - <TagInfo/> - <FieldFooter/> - </FieldDoc> - <Footer/> - </FieldDetails> - <ConstructorDetails> - <Header/> - <ConstructorDoc> - <ConstructorHeader/> - <Signature/> - <DeprecationInfo/> - <ConstructorComments/> - <TagInfo/> - <ConstructorFooter/> - </ConstructorDoc> - <Footer/> - </ConstructorDetails> - <MethodDetails> - <Header/> - <MethodDoc> - <MethodHeader/> - <Signature/> - <DeprecationInfo/> - <MethodComments/> - <TagInfo/> - <MethodFooter/> - </MethodDoc> - <Footer/> - </MethodDetails> - <ClassFooter/> - </ClassDoc> - - <ConstantSummary> - <Header/> - <Contents/> - <ConstantSummaries> - <PackageConstantSummary> - <PackageHeader/> - <ClassConstantSummary> - <ClassHeader/> - <ConstantMembers/> - <ClassFooter/> - </ClassConstantSummary> - </PackageConstantSummary> - </ConstantSummaries> - <Footer/> - </ConstantSummary> - - <SerializedForm> - <Header/> - <SerializedFormSummaries> - <PackageSerializedForm> - <PackageHeader/> - <ClassSerializedForm> - <ClassHeader/> - <SerialUIDInfo/> - <MethodHeader/> - <SerializableMethods> - <MethodSubHeader/> - <MethodInfo> - <DeprecatedMethodInfo/> - <MethodDescription/> - <MethodTags/> - </MethodInfo> - <MethodFooter/> - </SerializableMethods> - <FieldHeader/> - <SerializableFields> - <FieldSubHeader/> - <FieldInfo/> - <FieldFooter/> - </SerializableFields> - </ClassSerializedForm> - </PackageSerializedForm> - </SerializedFormSummaries> - <Footer/> - </SerializedForm> -</Doclet> + +<Doclet> + + <PackageDoc> + <PackageHeader/> + <Summary> + <SummaryHeader/> + <InterfaceSummary/> + <ClassSummary/> + <EnumSummary/> + <ExceptionSummary/> + <ErrorSummary/> + <AnnotationTypeSummary/> + <SummaryFooter/> + </Summary> + <PackageDescription/> + <PackageTags/> + <PackageFooter/> + </PackageDoc> + + <AnnotationTypeDoc> + <AnnotationTypeHeader/> + <DeprecationInfo/> + <AnnotationTypeSignature/> + <AnnotationTypeDescription/> + <AnnotationTypeTagInfo/> + <MemberSummary> + <AnnotationTypeRequiredMemberSummary/> + <AnnotationTypeOptionalMemberSummary/> + </MemberSummary> + <AnnotationTypeRequiredMemberDetails> + <Header/> + <AnnotationTypeRequiredMember> + <MemberHeader/> + <Signature/> + <DeprecationInfo/> + <MemberComments/> + <TagInfo/> + <MemberFooter/> + </AnnotationTypeRequiredMember> + </AnnotationTypeRequiredMemberDetails> + <AnnotationTypeOptionalMemberDetails> + <AnnotationTypeOptionalMember> + <MemberHeader/> + <Signature/> + <DeprecationInfo/> + <MemberComments/> + <TagInfo/> + <DefaultValueInfo/> + <MemberFooter/> + </AnnotationTypeOptionalMember> + <Footer/> + </AnnotationTypeOptionalMemberDetails> + <AnnotationTypeFooter/> + </AnnotationTypeDoc> + + <ClassDoc> + <ClassHeader/> + <ClassTree/> + <TypeParamInfo/> + <SuperInterfacesInfo/> + <ImplementedInterfacesInfo/> + <SubClassInfo/> + <SubInterfacesInfo/> + <InterfaceUsageInfo/> + <NestedClassInfo/> + <DeprecationInfo/> + <ClassSignature/> + <ClassDescription/> + <ClassTagInfo/> + <MemberSummary> + <NestedClassesSummary/> + <NestedClassesInheritedSummary/> + <EnumConstantsSummary/> + <FieldsSummary/> + <FieldsInheritedSummary/> + <ConstructorsSummary/> + <MethodsSummary/> + <MethodsInheritedSummary/> + </MemberSummary> + <EnumConstantsDetails> + <Header/> + <EnumConstant> + <EnumConstantHeader/> + <Signature/> + <DeprecationInfo/> + <EnumConstantComments/> + <TagInfo/> + <EnumConstantFooter/> + </EnumConstant> + <Footer/> + </EnumConstantsDetails> + <FieldDetails> + <Header/> + <FieldDoc> + <FieldHeader/> + <Signature/> + <DeprecationInfo/> + <FieldComments/> + <TagInfo/> + <FieldFooter/> + </FieldDoc> + <Footer/> + </FieldDetails> + <ConstructorDetails> + <Header/> + <ConstructorDoc> + <ConstructorHeader/> + <Signature/> + <DeprecationInfo/> + <ConstructorComments/> + <TagInfo/> + <ConstructorFooter/> + </ConstructorDoc> + <Footer/> + </ConstructorDetails> + <MethodDetails> + <Header/> + <MethodDoc> + <MethodHeader/> + <Signature/> + <DeprecationInfo/> + <MethodComments/> + <TagInfo/> + <MethodFooter/> + </MethodDoc> + <Footer/> + </MethodDetails> + <ClassFooter/> + </ClassDoc> + + <ConstantSummary> + <Header/> + <Contents/> + <ConstantSummaries> + <PackageConstantSummary> + <PackageHeader/> + <ClassConstantSummary> + <ClassHeader/> + <ConstantMembers/> + <ClassFooter/> + </ClassConstantSummary> + </PackageConstantSummary> + </ConstantSummaries> + <Footer/> + </ConstantSummary> + + <SerializedForm> + <Header/> + <SerializedFormSummaries> + <PackageSerializedForm> + <PackageHeader/> + <ClassSerializedForm> + <ClassHeader/> + <SerialUIDInfo/> + <MethodHeader/> + <SerializableMethods> + <MethodSubHeader/> + <DeprecatedMethodInfo/> + <MethodInfo> + <MethodDescription/> + <MethodTags/> + </MethodInfo> + <MethodFooter/> + </SerializableMethods> + <FieldHeader/> + <SerializableFields> + <FieldSubHeader/> + <FieldDeprecationInfo/> + <FieldInfo/> + <FieldSubFooter/> + </SerializableFields> + </ClassSerializedForm> + </PackageSerializedForm> + </SerializedFormSummaries> + <Footer/> + </SerializedForm> +</Doclet> diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties index 57382de9ab2..371bdf596f1 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties @@ -82,6 +82,7 @@ doclet.Exceptions=Exceptions doclet.Errors=Errors doclet.Classes=Classes doclet.Packages=Packages +doclet.packages=packages doclet.All_Classes=All Classes doclet.All_Superinterfaces=All Superinterfaces: doclet.All_Implemented_Interfaces=All Implemented Interfaces: @@ -92,14 +93,20 @@ doclet.Interface=Interface doclet.Class=Class doclet.AnnotationType=Annotation Type doclet.annotationtype=annotation type +doclet.annotationtypes=annotation types doclet.Enum=Enum doclet.enum=enum +doclet.enums=enums doclet.interface=interface +doclet.interfaces=interfaces doclet.class=class +doclet.classes=classes doclet.Error=Error doclet.error=error +doclet.errors=errors doclet.Exception=Exception doclet.exception=exception +doclet.exceptions=exceptions doclet.extended_by=extended by doclet.extends=extends doclet.Package_private=(package private) @@ -125,6 +132,32 @@ doclet.value_tag_invalid_reference={0} (referenced by @value tag) is an unknown doclet.value_tag_invalid_constant=@value tag (which references {0}) can only be used in constants. doclet.dest_dir_create=Creating destination directory: "{0}" doclet.in={0} in {1} +doclet.Use_Table_Summary=Use table, listing {0}, and an explanation +doclet.Constants_Table_Summary={0} table, listing constant fields, and values +doclet.Member_Table_Summary={0} table, listing {1}, and an explanation +doclet.fields=fields +doclet.constructors=constructors +doclet.methods=methods +doclet.annotation_type_optional_members=optional elements +doclet.annotation_type_required_members=required elements +doclet.enum_constants=enum constants +doclet.nested_classes=nested classes +doclet.subclasses=subclasses +doclet.subinterfaces=subinterfaces +doclet.Modifier=Modifier +doclet.Type=Type +doclet.Field=Field +doclet.Constructor=Constructor +doclet.Method=Method +doclet.Annotation_Type_Optional_Member=Optional Element +doclet.Annotation_Type_Required_Member=Required Element +doclet.Annotation_Type_Member=Annotation Type Element +doclet.Enum_Constant=Enum Constant +doclet.Class=Class +doclet.Description=Description +doclet.ConstantField=Constant Field +doclet.Value=Value +doclet.0_and_1={0} and {1} #Documentation for Enums doclet.enum_values_doc=\n\ diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocletAbortException.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocletAbortException.java index c08965e5b7d..0dfe3152b63 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocletAbortException.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocletAbortException.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java index 9f0b6417d6c..7a641becf42 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/SourceToHTMLConverter.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/SourceToHTMLConverter.java index 3de2951e062..aeb024c057c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/SourceToHTMLConverter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/SourceToHTMLConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java index 1d5eb19c22e..5f739d9de8a 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/DiagnosticFormatter.java b/langtools/src/share/classes/com/sun/tools/javac/api/DiagnosticFormatter.java index 6fd51b146b1..576a1687f89 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/api/DiagnosticFormatter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/api/DiagnosticFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,18 @@ package com.sun.tools.javac.api; import java.util.Locale; +import java.util.Set; import javax.tools.Diagnostic; +import com.sun.tools.javac.api.DiagnosticFormatter.*; /** - * Provides simple functionalities for javac diagnostic formatting + * Provides simple functionalities for javac diagnostic formatting. * @param <D> type of diagnostic handled by this formatter */ public interface DiagnosticFormatter<D extends Diagnostic<?>> { /** - * Whether the source code output for this diagnostic is to be displayed + * Whether the source code output for this diagnostic is to be displayed. * * @param diag diagnostic to be formatted * @return true if the source line this diagnostic refers to is to be displayed @@ -42,7 +44,7 @@ public interface DiagnosticFormatter<D extends Diagnostic<?>> { boolean displaySource(D diag); /** - * Format the contents of a diagnostics + * Format the contents of a diagnostics. * * @param diag the diagnostic to be formatted * @param l locale object to be used for i18n @@ -115,4 +117,97 @@ public interface DiagnosticFormatter<D extends Diagnostic<?>> { */ OFFSET } + + /** + * Get a list of all the enabled verbosity options. + * @return verbosity options + */ + public Configuration getConfiguration(); + //where + + /** + * This interface provides functionalities for tuning the output of a + * diagnostic formatter in multiple ways. + */ + interface Configuration { + /** + * Configure the set of diagnostic parts that should be displayed + * by the formatter. + * @param options options to set + */ + public void setVisible(Set<DiagnosticPart> visibleParts); + + /** + * Retrieve the set of diagnostic parts that should be displayed + * by the formatter. + * @return verbosity options + */ + public Set<DiagnosticPart> getVisible(); + + //where + /** + * A given diagnostic message can be divided into sub-parts each of which + * might/might not be displayed by the formatter, according to the + * current configuration settings. + */ + public enum DiagnosticPart { + /** + * Short description of the diagnostic - usually one line long. + */ + SUMMARY, + /** + * Longer description that provides additional details w.r.t. the ones + * in the diagnostic's description. + */ + DETAILS, + /** + * Source line the diagnostic refers to (if applicable). + */ + SOURCE, + /** + * Subdiagnostics attached to a given multiline diagnostic. + */ + SUBDIAGNOSTICS, + /** + * JLS paragraph this diagnostic might refer to (if applicable). + */ + JLS; + } + + /** + * Set a limit for multiline diagnostics. + * Note: Setting a limit has no effect if multiline diagnostics are either + * fully enabled or disabled. + * + * @param limit the kind of limit to be set + * @param value the limit value + */ + public void setMultilineLimit(MultilineLimit limit, int value); + + /** + * Get a multiline diagnostic limit. + * + * @param limit the kind of limit to be retrieved + * @return limit value or -1 if no limit is set + */ + public int getMultilineLimit(MultilineLimit limit); + //where + /** + * A multiline limit control the verbosity of multiline diagnostics + * either by setting a maximum depth of nested multidiagnostics, + * or by limiting the amount of subdiagnostics attached to a given + * diagnostic (or both). + */ + public enum MultilineLimit { + /** + * Controls the maximum depth of nested multiline diagnostics. + */ + DEPTH, + /** + * Controls the maximum amount of subdiagnostics that are part of a + * given multiline diagnostic. + */ + LENGTH; + } + } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/Messages.java b/langtools/src/share/classes/com/sun/tools/javac/api/Messages.java index 7b67fe617cd..ad76d6ce794 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/api/Messages.java +++ b/langtools/src/share/classes/com/sun/tools/javac/api/Messages.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ public interface Messages { void add(String bundleName) throws MissingResourceException; /** - * Get a localized formatted string + * Get a localized formatted string. * @param l locale in which the text is to be localized * @param key locale-independent message key * @param args misc message arguments diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java new file mode 100644 index 00000000000..27e7823fe1b --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java @@ -0,0 +1,324 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.javac.code; + +import java.util.Locale; + +import com.sun.tools.javac.api.Messages; +import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; + +import static com.sun.tools.javac.code.TypeTags.*; +import static com.sun.tools.javac.code.BoundKind.*; +import static com.sun.tools.javac.code.Flags.*; + +/** + * A combined type/symbol visitor for generating non-trivial localized string + * representation of types and symbols. + */ +public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Visitor<String, Locale> { + + /** + * This method should be overriden in order to provide proper i18n support. + * + * @param locale the locale in which the string is to be rendered + * @param key the key corresponding to the message to be displayed + * @param args a list of optional arguments + * @return localized string representation + */ + protected abstract String localize(Locale locale, String key, Object... args); + + /** + * Create a printer with default i18n support provided my Messages. + * @param messages Messages class to be used for i18n + * @return printer visitor instance + */ + public static Printer createStandardPrinter(final Messages messages) { + return new Printer() { + @Override + protected String localize(Locale locale, String key, Object... args) { + return messages.getLocalizedString(locale, key, args); + }}; + } + + /** + * Get a localized string representation for all the types in the input list. + * + * @param ts types to be displayed + * @param locale the locale in which the string is to be rendered + * @return localized string representation + */ + public String visitTypes(List<Type> ts, Locale locale) { + ListBuffer<String> sbuf = ListBuffer.lb(); + for (Type t : ts) { + sbuf.append(visit(t, locale)); + } + return sbuf.toList().toString(); + } + + /** + * * Get a localized string represenation for all the symbols in the input list. + * + * @param ts symbols to be displayed + * @param locale the locale in which the string is to be rendered + * @return localized string representation + */ + public String visitSymbols(List<Symbol> ts, Locale locale) { + ListBuffer<String> sbuf = ListBuffer.lb(); + for (Symbol t : ts) { + sbuf.append(visit(t, locale)); + } + return sbuf.toList().toString(); + } + + /** + * Get a localized string represenation for a given type. + * + * @param ts type to be displayed + * @param locale the locale in which the string is to be rendered + * @return localized string representation + */ + public String visit(Type t, Locale locale) { + return t.accept(this, locale); + } + + /** + * Get a localized string represenation for a given symbol. + * + * @param ts symbol to be displayed + * @param locale the locale in which the string is to be rendered + * @return localized string representation + */ + public String visit(Symbol s, Locale locale) { + return s.accept(this, locale); + } + + @Override + public String visitCapturedType(CapturedType t, Locale locale) { + return localize(locale, "compiler.misc.type.captureof", + (t.hashCode() & 0xFFFFFFFFL) % Type.CapturedType.PRIME, + visit(t.wildcard, locale)); + } + + @Override + public String visitForAll(ForAll t, Locale locale) { + return "<" + visitTypes(t.tvars, locale) + ">" + visit(t.qtype, locale); + } + + @Override + public String visitUndetVar(UndetVar t, Locale locale) { + if (t.inst != null) { + return visit(t.inst, locale); + } else { + return visit(t.qtype, locale) + "?"; + } + } + + @Override + public String visitArrayType(ArrayType t, Locale locale) { + return visit(t.elemtype, locale) + "[]"; + } + + @Override + public String visitClassType(ClassType t, Locale locale) { + StringBuffer buf = new StringBuffer(); + if (t.getEnclosingType().tag == CLASS && t.tsym.owner.kind == Kinds.TYP) { + buf.append(visit(t.getEnclosingType(), locale)); + buf.append("."); + buf.append(className(t, false, locale)); + } else { + buf.append(className(t, true, locale)); + } + if (t.getTypeArguments().nonEmpty()) { + buf.append('<'); + buf.append(visitTypes(t.getTypeArguments(), locale)); + buf.append(">"); + } + return buf.toString(); + } + + @Override + public String visitMethodType(MethodType t, Locale locale) { + return "(" + printMethodArgs(t.argtypes, false, locale) + ")" + visit(t.restype, locale); + } + + @Override + public String visitPackageType(PackageType t, Locale locale) { + return t.tsym.getQualifiedName().toString(); + } + + @Override + public String visitWildcardType(WildcardType t, Locale locale) { + StringBuffer s = new StringBuffer(); + s.append(t.kind); + if (t.kind != UNBOUND) { + s.append(visit(t.type, locale)); + } + return s.toString(); + } + + @Override + public String visitErrorType(ErrorType t, Locale locale) { + return visitType(t, locale); + } + + @Override + public String visitTypeVar(TypeVar t, Locale locale) { + return visitType(t, locale); + } + + public String visitType(Type t, Locale locale) { + String s = (t.tsym == null || t.tsym.name == null) + ? localize(locale, "compiler.misc.type.none") + : t.tsym.name.toString(); + return s; + } + + /** + * Converts a class name into a (possibly localized) string. Anonymous + * inner classes gets converted into a localized string. + * + * @param t the type of the class whose name is to be rendered + * @param longform if set, the class' fullname is displayed - if unset the + * short name is chosen (w/o package) + * @param locale the locale in which the string is to be rendered + * @return localized string representation + */ + protected String className(ClassType t, boolean longform, Locale locale) { + Symbol sym = t.tsym; + if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) { + StringBuffer s = new StringBuffer(visit(t.supertype_field, locale)); + for (List<Type> is = t.interfaces_field; is.nonEmpty(); is = is.tail) { + s.append("&"); + s.append(visit(is.head, locale)); + } + return s.toString(); + } else if (sym.name.length() == 0) { + String s; + ClassType norm = (ClassType) t.tsym.type; + if (norm == null) { + s = localize(locale, "compiler.misc.anonymous.class", (Object) null); + } else if (norm.interfaces_field.nonEmpty()) { + s = localize(locale, "compiler.misc.anonymous.class", + visit(norm.interfaces_field.head, locale)); + } else { + s = localize(locale, "compiler.misc.anonymous.class", + visit(norm.supertype_field, locale)); + } + return s; + } else if (longform) { + return sym.getQualifiedName().toString(); + } else { + return sym.name.toString(); + } + } + + /** + * Converts a set of method argument types into their corresponding + * localized string representation. + * + * @param args arguments to be rendered + * @param varArgs if true, the last method argument is regarded as a vararg + * @param locale the locale in which the string is to be rendered + * @return localized string representation + */ + protected String printMethodArgs(List<Type> args, boolean varArgs, Locale locale) { + if (!varArgs) { + return visitTypes(args, locale); + } else { + StringBuffer buf = new StringBuffer(); + while (args.tail.nonEmpty()) { + buf.append(visit(args.head, locale)); + args = args.tail; + buf.append(','); + } + if (args.head.tag == ARRAY) { + buf.append(visit(((ArrayType) args.head).elemtype, locale)); + buf.append("..."); + } else { + buf.append(visit(args.head, locale)); + } + return buf.toString(); + } + } + + @Override + public String visitClassSymbol(ClassSymbol sym, Locale locale) { + return sym.name.isEmpty() + ? localize(locale, "compiler.misc.anonymous.class", sym.flatname) + : sym.fullname.toString(); + } + + @Override + public String visitMethodSymbol(MethodSymbol s, Locale locale) { + if ((s.flags() & BLOCK) != 0) { + return s.owner.name.toString(); + } else { + String ms = (s.name == s.name.table.names.init) + ? s.owner.name.toString() + : s.name.toString(); + if (s.type != null) { + if (s.type.tag == FORALL) { + ms = "<" + visitTypes(s.type.getTypeArguments(), locale) + ">" + ms; + } + ms += "(" + printMethodArgs( + s.type.getParameterTypes(), + (s.flags() & VARARGS) != 0, + locale) + ")"; + } + return ms; + } + } + + @Override + public String visitOperatorSymbol(OperatorSymbol s, Locale locale) { + return visitMethodSymbol(s, locale); + } + + @Override + public String visitPackageSymbol(PackageSymbol s, Locale locale) { + return s.isUnnamed() + ? localize(locale, "compiler.misc.unnamed.package") + : s.fullname.toString(); + } + + @Override + public String visitTypeSymbol(TypeSymbol s, Locale locale) { + return visitSymbol(s, locale); + } + + @Override + public String visitVarSymbol(VarSymbol s, Locale locale) { + return visitSymbol(s, locale); + } + + @Override + public String visitSymbol(Symbol s, Locale locale) { + return s.name.toString(); + } +} diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java index cc9c8100069..b8ae943c7dd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,8 @@ package com.sun.tools.javac.code; import java.util.*; +import com.sun.tools.javac.api.Messages; + import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.List; @@ -1010,8 +1012,8 @@ public class Types { && !disjointTypes(aHigh.allparams(), lowSub.allparams()) && !disjointTypes(aLow.allparams(), highSub.allparams()) && !disjointTypes(aLow.allparams(), lowSub.allparams())) { - if (upcast ? giveWarning(a, highSub) || giveWarning(a, lowSub) - : giveWarning(highSub, a) || giveWarning(lowSub, a)) + if (upcast ? giveWarning(a, b) : + giveWarning(b, a)) warnStack.head.warnUnchecked(); return true; } @@ -2019,7 +2021,7 @@ public class Types { return t; else return visit(t); - } + } List<Type> subst(List<Type> ts) { if (from.tail == null) @@ -2279,225 +2281,21 @@ public class Types { } // </editor-fold> - // <editor-fold defaultstate="collapsed" desc="printType"> /** - * Visitor for generating a string representation of a given type + * Helper method for generating a string representation of a given type * accordingly to a given locale */ public String toString(Type t, Locale locale) { - return typePrinter.visit(t, locale); + return Printer.createStandardPrinter(messages).visit(t, locale); } - // where - private TypePrinter typePrinter = new TypePrinter(); - public class TypePrinter extends DefaultTypeVisitor<String, Locale> { - - public String visit(List<Type> ts, Locale locale) { - ListBuffer<String> sbuf = lb(); - for (Type t : ts) { - sbuf.append(visit(t, locale)); - } - return sbuf.toList().toString(); - } - - @Override - public String visitCapturedType(CapturedType t, Locale locale) { - return messages.getLocalizedString("compiler.misc.type.captureof", - (t.hashCode() & 0xFFFFFFFFL) % Type.CapturedType.PRIME, - visit(t.wildcard, locale)); - } - - @Override - public String visitForAll(ForAll t, Locale locale) { - return "<" + visit(t.tvars, locale) + ">" + visit(t.qtype, locale); - } - - @Override - public String visitUndetVar(UndetVar t, Locale locale) { - if (t.inst != null) { - return visit(t.inst, locale); - } else { - return visit(t.qtype, locale) + "?"; - } - } - - @Override - public String visitArrayType(ArrayType t, Locale locale) { - return visit(t.elemtype, locale) + "[]"; - } - - @Override - public String visitClassType(ClassType t, Locale locale) { - StringBuffer buf = new StringBuffer(); - if (t.getEnclosingType().tag == CLASS && t.tsym.owner.kind == Kinds.TYP) { - buf.append(visit(t.getEnclosingType(), locale)); - buf.append("."); - buf.append(className(t, false, locale)); - } else { - buf.append(className(t, true, locale)); - } - if (t.getTypeArguments().nonEmpty()) { - buf.append('<'); - buf.append(visit(t.getTypeArguments(), locale)); - buf.append(">"); - } - return buf.toString(); - } - - @Override - public String visitMethodType(MethodType t, Locale locale) { - return "(" + printMethodArgs(t.argtypes, false, locale) + ")" + visit(t.restype, locale); - } - - @Override - public String visitPackageType(PackageType t, Locale locale) { - return t.tsym.getQualifiedName().toString(); - } - - @Override - public String visitWildcardType(WildcardType t, Locale locale) { - StringBuffer s = new StringBuffer(); - s.append(t.kind); - if (t.kind != UNBOUND) { - s.append(visit(t.type, locale)); - } - return s.toString(); - } - - - public String visitType(Type t, Locale locale) { - String s = (t.tsym == null || t.tsym.name == null) - ? messages.getLocalizedString("compiler.misc.type.none") - : t.tsym.name.toString(); - return s; - } - - protected String className(ClassType t, boolean longform, Locale locale) { - Symbol sym = t.tsym; - if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) { - StringBuffer s = new StringBuffer(visit(supertype(t), locale)); - for (List<Type> is = interfaces(t); is.nonEmpty(); is = is.tail) { - s.append("&"); - s.append(visit(is.head, locale)); - } - return s.toString(); - } else if (sym.name.length() == 0) { - String s; - ClassType norm = (ClassType) t.tsym.type; - if (norm == null) { - s = getLocalizedString(locale, "compiler.misc.anonymous.class", (Object) null); - } else if (interfaces(norm).nonEmpty()) { - s = getLocalizedString(locale, "compiler.misc.anonymous.class", - visit(interfaces(norm).head, locale)); - } else { - s = getLocalizedString(locale, "compiler.misc.anonymous.class", - visit(supertype(norm), locale)); - } - return s; - } else if (longform) { - return sym.getQualifiedName().toString(); - } else { - return sym.name.toString(); - } - } - - protected String printMethodArgs(List<Type> args, boolean varArgs, Locale locale) { - if (!varArgs) { - return visit(args, locale); - } else { - StringBuffer buf = new StringBuffer(); - while (args.tail.nonEmpty()) { - buf.append(visit(args.head, locale)); - args = args.tail; - buf.append(','); - } - if (args.head.tag == ARRAY) { - buf.append(visit(((ArrayType) args.head).elemtype, locale)); - buf.append("..."); - } else { - buf.append(visit(args.head, locale)); - } - return buf.toString(); - } - } - - protected String getLocalizedString(Locale locale, String key, Object... args) { - return messages.getLocalizedString(key, args); - } - }; - // </editor-fold> - - // <editor-fold defaultstate="collapsed" desc="printSymbol"> /** - * Visitor for generating a string representation of a given symbol + * Helper method for generating a string representation of a given type * accordingly to a given locale */ public String toString(Symbol t, Locale locale) { - return symbolPrinter.visit(t, locale); + return Printer.createStandardPrinter(messages).visit(t, locale); } - // where - private SymbolPrinter symbolPrinter = new SymbolPrinter(); - - public class SymbolPrinter extends DefaultSymbolVisitor<String, Locale> { - - @Override - public String visitClassSymbol(ClassSymbol sym, Locale locale) { - return sym.name.isEmpty() - ? getLocalizedString(locale, "compiler.misc.anonymous.class", sym.flatname) - : sym.fullname.toString(); - } - - @Override - public String visitMethodSymbol(MethodSymbol s, Locale locale) { - if ((s.flags() & BLOCK) != 0) { - return s.owner.name.toString(); - } else { - String ms = (s.name == names.init) - ? s.owner.name.toString() - : s.name.toString(); - if (s.type != null) { - if (s.type.tag == FORALL) { - ms = "<" + typePrinter.visit(s.type.getTypeArguments(), locale) + ">" + ms; - } - ms += "(" + typePrinter.printMethodArgs( - s.type.getParameterTypes(), - (s.flags() & VARARGS) != 0, - locale) + ")"; - } - return ms; - } - } - - @Override - public String visitOperatorSymbol(OperatorSymbol s, Locale locale) { - return visitMethodSymbol(s, locale); - } - - @Override - public String visitPackageSymbol(PackageSymbol s, Locale locale) { - return s.name.isEmpty() - ? getLocalizedString(locale, "compiler.misc.unnamed.package") - : s.fullname.toString(); - } - - @Override - public String visitSymbol(Symbol s, Locale locale) { - return s.name.toString(); - } - - public String visit(List<Symbol> ts, Locale locale) { - ListBuffer<String> sbuf = lb(); - for (Symbol t : ts) { - sbuf.append(visit(t, locale)); - } - return sbuf.toList().toString(); - } - - protected String getLocalizedString(Locale locale, String key, Object... args) { - return messages.getLocalizedString(key, args); - } - }; - // </editor-fold> // <editor-fold defaultstate="collapsed" desc="toString"> /** @@ -3128,7 +2926,7 @@ public class Types { return t; } // where - private List<Type> freshTypeVariables(List<Type> types) { + public List<Type> freshTypeVariables(List<Type> types) { ListBuffer<Type> result = lb(); for (Type t : types) { if (t.tag == WILDCARD) { @@ -3224,9 +3022,11 @@ public class Types { } private boolean giveWarning(Type from, Type to) { - // To and from are (possibly different) parameterizations - // of the same class or interface - return to.isParameterized() && !containsType(to.allparams(), from.allparams()); + Type subFrom = asSub(from, to.tsym); + return to.isParameterized() && + (!(isUnbounded(to) || + isSubtype(from, to) || + ((subFrom != null) && isSameType(subFrom, to)))); } private List<Type> superClosure(Type t, Type s) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index a7a4012bea8..a920623806b 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index 911b9d7d46e..0f9f8d98c44 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1458,10 +1458,14 @@ public class Check { while (e.scope != null) { if (m.overrides(e.sym, origin, types, false)) checkOverride(tree, m, (MethodSymbol)e.sym, origin); - else if (e.sym.isInheritedIn(origin, types) && !m.isConstructor()) { + else if (e.sym.kind == MTH && + e.sym.isInheritedIn(origin, types) && + (e.sym.flags() & SYNTHETIC) == 0 && + !m.isConstructor()) { Type er1 = m.erasure(types); Type er2 = e.sym.erasure(types); - if (types.isSameType(er1,er2)) { + if (types.isSameTypes(er1.getParameterTypes(), + er2.getParameterTypes())) { log.error(TreeInfo.diagnosticPositionFor(m, tree), "name.clash.same.erasure.no.override", m, m.location(), @@ -1545,10 +1549,10 @@ public class Check { void checkNonCyclic(DiagnosticPosition pos, TypeVar t) { - checkNonCyclic1(pos, t, new HashSet<TypeVar>()); + checkNonCyclic1(pos, t, List.<TypeVar>nil()); } - private void checkNonCyclic1(DiagnosticPosition pos, Type t, Set<TypeVar> seen) { + private void checkNonCyclic1(DiagnosticPosition pos, Type t, List<TypeVar> seen) { final TypeVar tv; if (t.tag == TYPEVAR && (t.tsym.flags() & UNATTRIBUTED) != 0) return; @@ -1558,7 +1562,7 @@ public class Check { log.error(pos, "cyclic.inheritance", t); } else if (t.tag == TYPEVAR) { tv = (TypeVar)t; - seen.add(tv); + seen = seen.prepend(tv); for (Type b : types.getBounds(tv)) checkNonCyclic1(pos, b, seen); } @@ -2088,9 +2092,11 @@ public class Check { if (sym != e.sym && sym.kind == e.sym.kind && sym.name != names.error && - (sym.kind != MTH || types.overrideEquivalent(sym.type, e.sym.type))) { + (sym.kind != MTH || types.hasSameArgs(types.erasure(sym.type), types.erasure(e.sym.type)))) { if ((sym.flags() & VARARGS) != (e.sym.flags() & VARARGS)) varargsDuplicateError(pos, sym, e.sym); + else if (sym.kind == MTH && !types.overrideEquivalent(sym.type, e.sym.type)) + duplicateErasureError(pos, sym, e.sym); else duplicateError(pos, e.sym); return false; @@ -2098,6 +2104,14 @@ public class Check { } return true; } + //where + /** Report duplicate declaration error. + */ + void duplicateErasureError(DiagnosticPosition pos, Symbol sym1, Symbol sym2) { + if (!sym1.type.isErroneous() && !sym2.type.isErroneous()) { + log.error(pos, "name.clash.same.erasure", sym1, sym2); + } + } /** Check that single-type import is not already imported or top-level defined, * but make an exception for two single-type imports which denote the same type. diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java index 93a08fb8cf8..9eb0db6a391 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java index 9e0b2582b91..a299c6f28bb 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java index b2f4981be6a..fe729ee9592 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java @@ -2631,8 +2631,8 @@ public class Lower extends TreeTranslator { if (havePrimitive) { Type unboxedTarget = types.unboxedType(type); if (unboxedTarget.tag != NONE) { - if (!types.isSubtype(tree.type, unboxedTarget)) - tree.type = unboxedTarget; // e.g. Character c = 89; + if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89; + tree.type = unboxedTarget.constType(tree.type.constValue()); return (T)boxPrimitive((JCExpression)tree, type); } else { tree = (T)boxPrimitive((JCExpression)tree); @@ -3012,6 +3012,7 @@ public class Lower extends TreeTranslator { vardefinit).setType(tree.var.type); indexDef.sym = tree.var.sym; JCBlock body = make.Block(0, List.of(indexDef, tree.body)); + body.endpos = TreeInfo.endPos(tree.body); result = translate(make. ForLoop(List.of(init), cond, diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java index 1a141aa5400..ca4908830cc 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -216,7 +216,9 @@ public class Resolve { && isAccessible(env, site) && - sym.isInheritedIn(site.tsym, types); + sym.isInheritedIn(site.tsym, types) + && + notOverriddenIn(site, sym); case PROTECTED: return (env.toplevel.packge == sym.owner.owner // fast special case @@ -231,14 +233,23 @@ public class Resolve { && isAccessible(env, site) && - // `sym' is accessible only if not overridden by - // another symbol which is a member of `site' - // (because, if it is overridden, `sym' is not strictly - // speaking a member of `site'.) - (sym.kind != MTH || sym.isConstructor() || sym.isStatic() || - ((MethodSymbol)sym).implementation(site.tsym, types, true) == sym); + notOverriddenIn(site, sym); default: // this case includes erroneous combinations as well - return isAccessible(env, site); + return isAccessible(env, site) && notOverriddenIn(site, sym); + } + } + //where + /* `sym' is accessible only if not overridden by + * another symbol which is a member of `site' + * (because, if it is overridden, `sym' is not strictly + * speaking a member of `site'.) + */ + private boolean notOverriddenIn(Type site, Symbol sym) { + if (sym.kind != MTH || sym.isConstructor() || sym.isStatic()) + return true; + else { + Symbol s2 = ((MethodSymbol)sym).implementation(site.tsym, types, true); + return (s2 == null || s2 == sym); } } //where @@ -605,7 +616,7 @@ public class Resolve { Symbol mostSpecific(Symbol m1, Symbol m2, Env<AttrContext> env, - Type site, + final Type site, boolean allowBoxing, boolean useVarargs) { switch (m2.kind) { @@ -661,21 +672,33 @@ public class Resolve { m2.erasure(types).getParameterTypes())) return new AmbiguityError(m1, m2); // both abstract, neither overridden; merge throws clause and result type - Symbol result; + Symbol mostSpecific; Type result2 = mt2.getReturnType(); if (mt2.tag == FORALL) result2 = types.subst(result2, ((ForAll)mt2).tvars, ((ForAll)mt1).tvars); if (types.isSubtype(mt1.getReturnType(), result2)) { - result = m1; + mostSpecific = m1; } else if (types.isSubtype(result2, mt1.getReturnType())) { - result = m2; + mostSpecific = m2; } else { // Theoretically, this can't happen, but it is possible // due to error recovery or mixing incompatible class files return new AmbiguityError(m1, m2); } - result = result.clone(result.owner); - result.type = (Type)result.type.clone(); + MethodSymbol result = new MethodSymbol( + mostSpecific.flags(), + mostSpecific.name, + null, + mostSpecific.owner) { + @Override + public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult) { + if (origin == site.tsym) + return this; + else + return super.implementation(origin, types, checkResult); + } + }; + result.type = (Type)mostSpecific.type.clone(); result.type.setThrown(chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes())); return result; diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java index 247b0e183b0..c560ccbc86a 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java @@ -25,8 +25,9 @@ package com.sun.tools.javac.jvm; -import com.sun.tools.javac.code.*; -import com.sun.tools.javac.util.*; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.util.Name; + /** A JVM class file. * @@ -86,6 +87,18 @@ public class ClassFile { public final static int MAX_LOCALS = 0xffff; public final static int MAX_STACK = 0xffff; + public enum Version { + V45_3(45, 3), // base level for all attributes + V49(49, 0), // JDK 1.5: enum, generics, annotations + V50(50, 0), // JDK 1.6: stackmaps + V51(51, 0); // JDK 1.7 + Version(int major, int minor) { + this.major = major; + this.minor = minor; + } + public final int major, minor; + } + /************************************************************************ * String Translation Routines diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 72953f4b5fe..263ca3c0b0a 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -35,8 +35,11 @@ import java.util.Set; import javax.lang.model.SourceVersion; import javax.tools.JavaFileObject; import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; import javax.tools.StandardJavaFileManager; +import static javax.tools.StandardLocation.*; + import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Type.*; @@ -49,9 +52,8 @@ import com.sun.tools.javac.util.List; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; -import com.sun.tools.javac.jvm.ClassFile.NameAndType; -import javax.tools.JavaFileManager.Location; -import static javax.tools.StandardLocation.*; +import static com.sun.tools.javac.jvm.ClassFile.*; +import static com.sun.tools.javac.jvm.ClassFile.Version.*; /** This class provides operations to read a classfile into an internal * representation. The internal representation is anchored in a @@ -64,7 +66,7 @@ import static javax.tools.StandardLocation.*; * This code and its internal interfaces are subject to change or * deletion without notice.</b> */ -public class ClassReader extends ClassFile implements Completer { +public class ClassReader implements Completer { /** The context key for the class reader. */ protected static final Context.Key<ClassReader> classReaderKey = new Context.Key<ClassReader>(); @@ -180,6 +182,11 @@ public class ClassReader extends ClassFile implements Completer { */ int[] poolIdx; + /** The major version number of the class file being read. */ + int majorVersion; + /** The minor version number of the class file being read. */ + int minorVersion; + /** Get the ClassReader instance for this invocation. */ public static ClassReader instance(Context context) { ClassReader instance = context.get(classReaderKey); @@ -249,6 +256,8 @@ public class ClassReader extends ClassFile implements Completer { : null; typevars = new Scope(syms.noSymbol); + + initAttributeReaders(); } /** Add member to class unless it is synthetic. @@ -655,6 +664,7 @@ public class ClassReader extends ClassFile implements Completer { sbp - startSbp)); outer = new ClassType(outer, sigToTypes('>'), t) { boolean completed = false; + @Override public Type getEnclosingType() { if (!completed) { completed = true; @@ -679,6 +689,7 @@ public class ClassReader extends ClassFile implements Completer { } return super.getEnclosingType(); } + @Override public void setEnclosingType(Type outer) { throw new UnsupportedOperationException(); } @@ -822,6 +833,246 @@ public class ClassReader extends ClassFile implements Completer { * Reading Attributes ***********************************************************************/ + protected enum AttributeKind { CLASS, MEMBER }; + protected abstract class AttributeReader { + AttributeReader(Name name, Version version, Set<AttributeKind> kinds) { + this.name = name; + this.version = version; + this.kinds = kinds; + } + + boolean accepts(AttributeKind kind) { + return kinds.contains(kind) && majorVersion >= version.major; + } + + abstract void read(Symbol sym, int attrLen); + + final Name name; + final Version version; + final Set<AttributeKind> kinds; + } + + protected Set<AttributeKind> CLASS_ATTRIBUTE = + EnumSet.of(AttributeKind.CLASS); + protected Set<AttributeKind> MEMBER_ATTRIBUTE = + EnumSet.of(AttributeKind.MEMBER); + protected Set<AttributeKind> CLASS_OR_MEMBER_ATTRIBUTE = + EnumSet.of(AttributeKind.CLASS, AttributeKind.MEMBER); + + protected Map<Name, AttributeReader> attributeReaders = new HashMap<Name, AttributeReader>(); + + protected void initAttributeReaders() { + AttributeReader[] readers = { + // v45.3 attributes + + new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + if (readAllOfClassFile || saveParameterNames) + ((MethodSymbol)sym).code = readCode(sym); + else + bp = bp + attrLen; + } + }, + + new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + Object v = readPool(nextChar()); + // Ignore ConstantValue attribute if field not final. + if ((sym.flags() & FINAL) != 0) + ((VarSymbol) sym).setData(v); + } + }, + + new AttributeReader(names.Deprecated, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + sym.flags_field |= DEPRECATED; + } + }, + + new AttributeReader(names.Exceptions, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + int nexceptions = nextChar(); + List<Type> thrown = List.nil(); + for (int j = 0; j < nexceptions; j++) + thrown = thrown.prepend(readClassSymbol(nextChar()).type); + if (sym.type.getThrownTypes().isEmpty()) + sym.type.asMethodType().thrown = thrown.reverse(); + } + }, + + new AttributeReader(names.InnerClasses, V45_3, CLASS_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + ClassSymbol c = (ClassSymbol) sym; + readInnerClasses(c); + } + }, + + new AttributeReader(names.LocalVariableTable, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + int newbp = bp + attrLen; + if (saveParameterNames) { + // pick up parameter names from the variable table + List<Name> parameterNames = List.nil(); + int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0; + int endParam = firstParam + Code.width(sym.type.getParameterTypes()); + int numEntries = nextChar(); + for (int i=0; i<numEntries; i++) { + int start_pc = nextChar(); + int length = nextChar(); + int nameIndex = nextChar(); + int sigIndex = nextChar(); + int register = nextChar(); + if (start_pc == 0 && + firstParam <= register && + register < endParam) { + int index = firstParam; + for (Type t : sym.type.getParameterTypes()) { + if (index == register) { + parameterNames = parameterNames.prepend(readName(nameIndex)); + break; + } + index += Code.width(t); + } + } + } + parameterNames = parameterNames.reverse(); + ((MethodSymbol)sym).savedParameterNames = parameterNames; + } + bp = newbp; + } + }, + + new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + ClassSymbol c = (ClassSymbol) sym; + Name n = readName(nextChar()); + c.sourcefile = new SourceFileObject(n, c.flatname); + } + }, + + new AttributeReader(names.Synthetic, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + // bridge methods are visible when generics not enabled + if (allowGenerics || (sym.flags_field & BRIDGE) == 0) + sym.flags_field |= SYNTHETIC; + } + }, + + // standard v49 attributes + + new AttributeReader(names.EnclosingMethod, V49, CLASS_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + int newbp = bp + attrLen; + readEnclosingMethodAttr(sym); + bp = newbp; + } + }, + + new AttributeReader(names.Signature, V49, CLASS_OR_MEMBER_ATTRIBUTE) { + @Override + boolean accepts(AttributeKind kind) { + return super.accepts(kind) && allowGenerics; + } + + void read(Symbol sym, int attrLen) { + if (sym.kind == TYP) { + ClassSymbol c = (ClassSymbol) sym; + readingClassAttr = true; + try { + ClassType ct1 = (ClassType)c.type; + assert c == currentOwner; + ct1.typarams_field = readTypeParams(nextChar()); + ct1.supertype_field = sigToType(); + ListBuffer<Type> is = new ListBuffer<Type>(); + while (sigp != siglimit) is.append(sigToType()); + ct1.interfaces_field = is.toList(); + } finally { + readingClassAttr = false; + } + } else { + List<Type> thrown = sym.type.getThrownTypes(); + sym.type = readType(nextChar()); + //- System.err.println(" # " + sym.type); + if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty()) + sym.type.asMethodType().thrown = thrown; + + } + } + }, + + // v49 annotation attributes + + new AttributeReader(names.AnnotationDefault, V49, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + attachAnnotationDefault(sym); + } + }, + + new AttributeReader(names.RuntimeInvisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + attachAnnotations(sym); + } + }, + + new AttributeReader(names.RuntimeInvisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + attachParameterAnnotations(sym); + } + }, + + new AttributeReader(names.RuntimeVisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + attachAnnotations(sym); + } + }, + + new AttributeReader(names.RuntimeVisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + attachParameterAnnotations(sym); + } + }, + + // additional "legacy" v49 attributes, superceded by flags + + new AttributeReader(names.Annotation, V49, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + if (allowAnnotations) + sym.flags_field |= ANNOTATION; + } + }, + + new AttributeReader(names.Bridge, V49, MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + sym.flags_field |= BRIDGE; + if (!allowGenerics) + sym.flags_field &= ~SYNTHETIC; + } + }, + + new AttributeReader(names.Enum, V49, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + sym.flags_field |= ENUM; + } + }, + + new AttributeReader(names.Varargs, V49, CLASS_OR_MEMBER_ATTRIBUTE) { + void read(Symbol sym, int attrLen) { + if (allowVarargs) + sym.flags_field |= VARARGS; + } + } + + // The following attributes for a Code attribute are not currently handled + // StackMapTable + // SourceDebugExtension + // LineNumberTable + // LocalVariableTypeTable + }; + + for (AttributeReader r: readers) + attributeReaders.put(r.name, r); + } + /** Report unrecognized attribute. */ void unrecognized(Name attrName) { @@ -829,99 +1080,7 @@ public class ClassReader extends ClassFile implements Completer { printCCF("ccf.unrecognized.attribute", attrName); } - /** Read member attribute. - */ - void readMemberAttr(Symbol sym, Name attrName, int attrLen) { - //- System.err.println(" z " + sym + ", " + attrName + ", " + attrLen); - if (attrName == names.ConstantValue) { - Object v = readPool(nextChar()); - // Ignore ConstantValue attribute if field not final. - if ((sym.flags() & FINAL) != 0) - ((VarSymbol)sym).setData(v); - } else if (attrName == names.Code) { - if (readAllOfClassFile || saveParameterNames) - ((MethodSymbol)sym).code = readCode(sym); - else - bp = bp + attrLen; - } else if (attrName == names.Exceptions) { - int nexceptions = nextChar(); - List<Type> thrown = List.nil(); - for (int j = 0; j < nexceptions; j++) - thrown = thrown.prepend(readClassSymbol(nextChar()).type); - if (sym.type.getThrownTypes().isEmpty()) - sym.type.asMethodType().thrown = thrown.reverse(); - } else if (attrName == names.Synthetic) { - // bridge methods are visible when generics not enabled - if (allowGenerics || (sym.flags_field & BRIDGE) == 0) - sym.flags_field |= SYNTHETIC; - } else if (attrName == names.Bridge) { - sym.flags_field |= BRIDGE; - if (!allowGenerics) - sym.flags_field &= ~SYNTHETIC; - } else if (attrName == names.Deprecated) { - sym.flags_field |= DEPRECATED; - } else if (attrName == names.Varargs) { - if (allowVarargs) sym.flags_field |= VARARGS; - } else if (attrName == names.Annotation) { - if (allowAnnotations) sym.flags_field |= ANNOTATION; - } else if (attrName == names.Enum) { - sym.flags_field |= ENUM; - } else if (allowGenerics && attrName == names.Signature) { - List<Type> thrown = sym.type.getThrownTypes(); - sym.type = readType(nextChar()); - //- System.err.println(" # " + sym.type); - if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty()) - sym.type.asMethodType().thrown = thrown; - } else if (attrName == names.RuntimeVisibleAnnotations) { - attachAnnotations(sym); - } else if (attrName == names.RuntimeInvisibleAnnotations) { - attachAnnotations(sym); - } else if (attrName == names.RuntimeVisibleParameterAnnotations) { - attachParameterAnnotations(sym); - } else if (attrName == names.RuntimeInvisibleParameterAnnotations) { - attachParameterAnnotations(sym); - } else if (attrName == names.LocalVariableTable) { - int newbp = bp + attrLen; - if (saveParameterNames) { - // pick up parameter names from the variable table - List<Name> parameterNames = List.nil(); - int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0; - int endParam = firstParam + Code.width(sym.type.getParameterTypes()); - int numEntries = nextChar(); - for (int i=0; i<numEntries; i++) { - int start_pc = nextChar(); - int length = nextChar(); - int nameIndex = nextChar(); - int sigIndex = nextChar(); - int register = nextChar(); - if (start_pc == 0 && - firstParam <= register && - register < endParam) { - int index = firstParam; - for (Type t : sym.type.getParameterTypes()) { - if (index == register) { - parameterNames = parameterNames.prepend(readName(nameIndex)); - break; - } - index += Code.width(t); - } - } - } - parameterNames = parameterNames.reverse(); - ((MethodSymbol)sym).savedParameterNames = parameterNames; - } - bp = newbp; - } else if (attrName == names.AnnotationDefault) { - attachAnnotationDefault(sym); - } else if (attrName == names.EnclosingMethod) { - int newbp = bp + attrLen; - readEnclosingMethodAttr(sym); - bp = newbp; - } else { - unrecognized(attrName); - bp = bp + attrLen; - } - } + void readEnclosingMethodAttr(Symbol sym) { // sym is a nested class with an "Enclosing Method" attribute @@ -1029,39 +1188,24 @@ public class ClassReader extends ClassFile implements Completer { /** Read member attributes. */ void readMemberAttrs(Symbol sym) { + readAttrs(sym, AttributeKind.MEMBER); + } + + void readAttrs(Symbol sym, AttributeKind kind) { char ac = nextChar(); for (int i = 0; i < ac; i++) { Name attrName = readName(nextChar()); int attrLen = nextInt(); - readMemberAttr(sym, attrName, attrLen); + AttributeReader r = attributeReaders.get(attrName); + if (r != null && r.accepts(kind)) + r.read(sym, attrLen); + else { + unrecognized(attrName); + bp = bp + attrLen; + } } } - /** Read class attribute. - */ - void readClassAttr(ClassSymbol c, Name attrName, int attrLen) { - if (attrName == names.SourceFile) { - Name n = readName(nextChar()); - c.sourcefile = new SourceFileObject(n, c.flatname); - } else if (attrName == names.InnerClasses) { - readInnerClasses(c); - } else if (allowGenerics && attrName == names.Signature) { - readingClassAttr = true; - try { - ClassType ct1 = (ClassType)c.type; - assert c == currentOwner; - ct1.typarams_field = readTypeParams(nextChar()); - ct1.supertype_field = sigToType(); - ListBuffer<Type> is = new ListBuffer<Type>(); - while (sigp != siglimit) is.append(sigToType()); - ct1.interfaces_field = is.toList(); - } finally { - readingClassAttr = false; - } - } else { - readMemberAttr(c, attrName, attrLen); - } - } private boolean readingClassAttr = false; private List<Type> missingTypeVariables = List.nil(); private List<Type> foundTypeVariables = List.nil(); @@ -1069,12 +1213,7 @@ public class ClassReader extends ClassFile implements Completer { /** Read class attributes. */ void readClassAttrs(ClassSymbol c) { - char ac = nextChar(); - for (int i = 0; i < ac; i++) { - Name attrName = readName(nextChar()); - int attrLen = nextInt(); - readClassAttr(c, attrName, attrLen); - } + readAttrs(c, AttributeKind.CLASS); } /** Read code block. @@ -1219,6 +1358,7 @@ public class ClassReader extends ClassFile implements Completer { this.enumerator = enumerator; } public void accept(Visitor v) { ((ProxyVisitor)v).visitEnumAttributeProxy(this); } + @Override public String toString() { return "/*proxy enum*/" + enumType + "." + enumerator; } @@ -1231,6 +1371,7 @@ public class ClassReader extends ClassFile implements Completer { this.values = values; } public void accept(Visitor v) { ((ProxyVisitor)v).visitArrayAttributeProxy(this); } + @Override public String toString() { return "{" + values + "}"; } @@ -1246,6 +1387,7 @@ public class ClassReader extends ClassFile implements Completer { this.values = values; } public void accept(Visitor v) { ((ProxyVisitor)v).visitCompoundAnnotationProxy(this); } + @Override public String toString() { StringBuffer buf = new StringBuffer(); buf.append("@"); @@ -1414,6 +1556,7 @@ public class ClassReader extends ClassFile implements Completer { final MethodSymbol sym; final Attribute value; final JavaFileObject classFile = currentClassFile; + @Override public String toString() { return " ClassReader store default for " + sym.owner + "." + sym + " is " + value; } @@ -1437,6 +1580,7 @@ public class ClassReader extends ClassFile implements Completer { final Symbol sym; final List<CompoundAnnotationProxy> l; final JavaFileObject classFile; + @Override public String toString() { return " ClassReader annotate " + sym.owner + "." + sym + " with " + l; } @@ -1544,7 +1688,8 @@ public class ClassReader extends ClassFile implements Completer { // prepare type variable table typevars = typevars.dup(currentOwner); - if (ct.getEnclosingType().tag == CLASS) enterTypevars(ct.getEnclosingType()); + if (ct.getEnclosingType().tag == CLASS) + enterTypevars(ct.getEnclosingType()); // read flags, or skip if this is an inner class long flags = adjustClassFlags(nextChar()); @@ -1632,8 +1777,8 @@ public class ClassReader extends ClassFile implements Completer { if (magic != JAVA_MAGIC) throw badClassFile("illegal.start.of.class.file"); - int minorVersion = nextChar(); - int majorVersion = nextChar(); + minorVersion = nextChar(); + majorVersion = nextChar(); int maxMajor = Target.MAX().majorVersion; int maxMinor = Target.MAX().minorVersion; if (majorVersion > maxMajor || @@ -1775,13 +1920,13 @@ public class ClassReader extends ClassFile implements Completer { if (sym.kind == TYP) { ClassSymbol c = (ClassSymbol)sym; c.members_field = new Scope.ErrorScope(c); // make sure it's always defined - boolean suppressFlush = this.suppressFlush; - this.suppressFlush = true; + boolean saveSuppressFlush = suppressFlush; + suppressFlush = true; try { completeOwners(c.owner); completeEnclosing(c); } finally { - this.suppressFlush = suppressFlush; + suppressFlush = saveSuppressFlush; } fillIn(c); } else if (sym.kind == PCK) { @@ -2270,6 +2415,7 @@ public class ClassReader extends ClassFile implements Completer { return URI.create(name.toString()); } + @Override public Reader openReader(boolean ignoreEncodingErrors) throws IOException { throw new UnsupportedOperationException(); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 8130dfc183e..555ef2356bd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -386,6 +386,11 @@ public class JavaCompiler implements ClassReader.SourceCompleter { (options.get("failcomplete") != null) ? names.fromString(options.get("failcomplete")) : null; + + shouldStopPolicy = + (options.get("shouldStopPolicy") != null) + ? CompileState.valueOf(options.get("shouldStopPolicy")) + : null; } /* Switches: @@ -459,14 +464,26 @@ public class JavaCompiler implements ClassReader.SourceCompleter { */ public boolean verboseCompilePolicy; + /** + * Policy of how far to continue processing. null means until first + * error. + */ + public CompileState shouldStopPolicy; + /** A queue of all as yet unattributed classes. */ public Todo todo; + /** Ordered list of compiler phases for each compilation unit. */ protected enum CompileState { - TODO(0), - ATTR(1), - FLOW(2); + PARSE(1), + ENTER(2), + PROCESS(3), + ATTR(4), + FLOW(5), + TRANSTYPES(6), + LOWER(7), + GENERATE(8); CompileState(int value) { this.value = value; } @@ -475,6 +492,9 @@ public class JavaCompiler implements ClassReader.SourceCompleter { } private int value; }; + /** Partial map to record which compiler phases have been executed + * for each compilation unit. Used for ATTR and FLOW phases. + */ protected class CompileStates extends HashMap<Env<AttrContext>,CompileState> { private static final long serialVersionUID = 1812267524140424433L; boolean isDone(Env<AttrContext> env, CompileState cs) { @@ -490,6 +510,13 @@ public class JavaCompiler implements ClassReader.SourceCompleter { */ protected Set<JavaFileObject> inputFiles = new HashSet<JavaFileObject>(); + protected boolean shouldStop(CompileState cs) { + if (shouldStopPolicy == null) + return (errorCount() > 0); + else + return cs.ordinal() > shouldStopPolicy.ordinal(); + } + /** The number of errors reported so far. */ public int errorCount() { @@ -503,18 +530,12 @@ public class JavaCompiler implements ClassReader.SourceCompleter { return log.nerrors; } - protected final <T> Queue<T> stopIfError(Queue<T> queue) { - if (errorCount() == 0) - return queue; - else - return ListBuffer.lb(); + protected final <T> Queue<T> stopIfError(CompileState cs, Queue<T> queue) { + return shouldStop(cs) ? ListBuffer.<T>lb() : queue; } - protected final <T> List<T> stopIfError(List<T> list) { - if (errorCount() == 0) - return list; - else - return List.nil(); + protected final <T> List<T> stopIfError(CompileState cs, List<T> list) { + return shouldStop(cs) ? List.<T>nil() : list; } /** The number of warnings reported so far. @@ -669,7 +690,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { */ JavaFileObject genCode(Env<AttrContext> env, JCClassDecl cdef) throws IOException { try { - if (gen.genClass(env, cdef)) + if (gen.genClass(env, cdef) && (errorCount() == 0)) return writer.writeClass(cdef.sym); } catch (ClassWriter.PoolOverflow ex) { log.error(cdef.pos(), "limit.pool"); @@ -779,8 +800,10 @@ public class JavaCompiler implements ClassReader.SourceCompleter { initProcessAnnotations(processors); // These method calls must be chained to avoid memory leaks - delegateCompiler = processAnnotations(enterTrees(stopIfError(parseFiles(sourceFileObjects))), - classnames); + delegateCompiler = + processAnnotations( + enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))), + classnames); delegateCompiler.compile2(); delegateCompiler.close(); @@ -812,7 +835,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { case BY_FILE: { Queue<Queue<Env<AttrContext>>> q = todo.groupByFile(); - while (!q.isEmpty() && errorCount() == 0) { + while (!q.isEmpty() && !shouldStop(CompileState.ATTR)) { generate(desugar(flow(attribute(q.remove())))); } } @@ -850,7 +873,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { * Parses a list of files. */ public List<JCCompilationUnit> parseFiles(List<JavaFileObject> fileObjects) throws IOException { - if (errorCount() > 0) + if (shouldStop(CompileState.PARSE)) return List.nil(); //parse all files @@ -961,7 +984,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { public JavaCompiler processAnnotations(List<JCCompilationUnit> roots, List<String> classnames) throws IOException { // TODO: see TEMP note in JavacProcessingEnvironment - if (errorCount() != 0) { + if (shouldStop(CompileState.PROCESS)) { // Errors were encountered. If todo is empty, then the // encountered errors were parse errors. Otherwise, the // errors were found during the enter phase which should @@ -1068,7 +1091,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { ListBuffer<Env<AttrContext>> results = lb(); while (!envs.isEmpty()) results.append(attribute(envs.remove())); - return results; + return stopIfError(CompileState.ATTR, results); } /** @@ -1115,7 +1138,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { for (Env<AttrContext> env: envs) { flow(env, results); } - return stopIfError(results); + return stopIfError(CompileState.FLOW, results); } /** @@ -1124,7 +1147,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { public Queue<Env<AttrContext>> flow(Env<AttrContext> env) { ListBuffer<Env<AttrContext>> results = lb(); flow(env, results); - return stopIfError(results); + return stopIfError(CompileState.FLOW, results); } /** @@ -1132,7 +1155,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { */ protected void flow(Env<AttrContext> env, Queue<Env<AttrContext>> results) { try { - if (errorCount() > 0) + if (shouldStop(CompileState.FLOW)) return; if (relax || compileStates.isDone(env, CompileState.FLOW)) { @@ -1141,7 +1164,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { } if (verboseCompilePolicy) - log.printLines(log.noticeWriter, "[flow " + env.enclClass.sym + "]"); + printNote("[flow " + env.enclClass.sym + "]"); JavaFileObject prev = log.useSource( env.enclClass.sym.sourcefile != null ? env.enclClass.sym.sourcefile : @@ -1152,7 +1175,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { flow.analyzeTree(env.tree, localMake); compileStates.put(env, CompileState.FLOW); - if (errorCount() > 0) + if (shouldStop(CompileState.FLOW)) return; results.add(env); @@ -1179,7 +1202,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results = lb(); for (Env<AttrContext> env: envs) desugar(env, results); - return stopIfError(results); + return stopIfError(CompileState.FLOW, results); } /** @@ -1189,7 +1212,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { * The preparation stops as soon as an error is found. */ protected void desugar(final Env<AttrContext> env, Queue<Pair<Env<AttrContext>, JCClassDecl>> results) { - if (errorCount() > 0) + if (shouldStop(CompileState.TRANSTYPES)) return; if (implicitSourcePolicy == ImplicitSourcePolicy.NONE @@ -1204,6 +1227,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { */ class ScanNested extends TreeScanner { Set<Env<AttrContext>> dependencies = new LinkedHashSet<Env<AttrContext>>(); + @Override public void visitClassDef(JCClassDecl node) { Type st = types.supertype(node.sym.type); if (st.tag == TypeTags.CLASS) { @@ -1226,11 +1250,11 @@ public class JavaCompiler implements ClassReader.SourceCompleter { //We need to check for error another time as more classes might //have been attributed and analyzed at this stage - if (errorCount() > 0) + if (shouldStop(CompileState.TRANSTYPES)) return; if (verboseCompilePolicy) - log.printLines(log.noticeWriter, "[desugar " + env.enclClass.sym + "]"); + printNote("[desugar " + env.enclClass.sym + "]"); JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ? env.enclClass.sym.sourcefile : @@ -1244,6 +1268,8 @@ public class JavaCompiler implements ClassReader.SourceCompleter { if (env.tree instanceof JCCompilationUnit) { if (!(stubOutput || sourceOutput || printFlat)) { + if (shouldStop(CompileState.LOWER)) + return; List<JCTree> pdef = lower.translateTopLevelClass(env, env.tree, localMake); if (pdef.head != null) { assert pdef.tail.isEmpty(); @@ -1266,9 +1292,12 @@ public class JavaCompiler implements ClassReader.SourceCompleter { return; } + if (shouldStop(CompileState.TRANSTYPES)) + return; + env.tree = transTypes.translateTopLevelClass(env.tree, localMake); - if (errorCount() != 0) + if (shouldStop(CompileState.LOWER)) return; if (sourceOutput) { @@ -1285,7 +1314,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { //translate out inner classes List<JCTree> cdefs = lower.translateTopLevelClass(env, env.tree, localMake); - if (errorCount() != 0) + if (shouldStop(CompileState.LOWER)) return; //generate code for each class @@ -1310,6 +1339,9 @@ public class JavaCompiler implements ClassReader.SourceCompleter { } public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue, Queue<JavaFileObject> results) { + if (shouldStop(CompileState.GENERATE)) + return; + boolean usePrintSource = (stubOutput || sourceOutput || printFlat); for (Pair<Env<AttrContext>, JCClassDecl> x: queue) { @@ -1317,7 +1349,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { JCClassDecl cdef = x.snd; if (verboseCompilePolicy) { - log.printLines(log.noticeWriter, "[generate " + printNote("[generate " + (usePrintSource ? " source" : "code") + " " + cdef.sym + "]"); } @@ -1371,6 +1403,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { JCClassDecl removeMethodBodies(JCClassDecl cdef) { final boolean isInterface = (cdef.mods.flags & Flags.INTERFACE) != 0; class MethodBodyRemover extends TreeTranslator { + @Override public void visitMethodDef(JCMethodDecl tree) { tree.mods.flags &= ~Flags.SYNCHRONIZED; for (JCVariableDecl vd : tree.params) @@ -1378,11 +1411,13 @@ public class JavaCompiler implements ClassReader.SourceCompleter { tree.body = null; super.visitMethodDef(tree); } + @Override public void visitVarDef(JCVariableDecl tree) { if (tree.init != null && tree.init.type.constValue() == null) tree.init = null; super.visitVarDef(tree); } + @Override public void visitClassDef(JCClassDecl tree) { ListBuffer<JCTree> newdefs = lb(); for (List<JCTree> it = tree.defs; it.tail != null; it = it.tail) { @@ -1469,12 +1504,16 @@ public class JavaCompiler implements ClassReader.SourceCompleter { } } + protected void printNote(String lines) { + Log.printLines(log.noticeWriter, lines); + } + /** Output for "-verbose" option. * @param key The key to look up the correct internationalized string. * @param arg An argument for substitution into the output string. */ protected void printVerbose(String key, Object arg) { - Log.printLines(log.noticeWriter, log.getLocalizedString("verbose." + key, arg)); + Log.printLines(log.noticeWriter, Log.getLocalizedString("verbose." + key, arg)); } /** Print numbers of errors and warnings. @@ -1483,9 +1522,9 @@ public class JavaCompiler implements ClassReader.SourceCompleter { if (count != 0) { String text; if (count == 1) - text = log.getLocalizedString("count." + kind, String.valueOf(count)); + text = Log.getLocalizedString("count." + kind, String.valueOf(count)); else - text = log.getLocalizedString("count." + kind + ".plural", String.valueOf(count)); + text = Log.getLocalizedString("count." + kind + ".plural", String.valueOf(count)); Log.printLines(log.errWriter, text); log.errWriter.flush(); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java index 19f9f6e0e99..0ae7cd1c6b8 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/OptionName.java b/langtools/src/share/classes/com/sun/tools/javac/main/OptionName.java index 3ffbccdbc35..18aedd84adc 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/OptionName.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/OptionName.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ public enum OptionName { G_CUSTOM("-g:"), XLINT("-Xlint"), XLINT_CUSTOM("-Xlint:"), + DIAGS("-XDdiags="), NOWARN("-nowarn"), VERBOSE("-verbose"), DEPRECATION("-deprecation"), diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java b/langtools/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java index 980d6779674..8e0eb888f31 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,6 +145,7 @@ public class RecognizedOptions { TARGET, VERSION, FULLVERSION, + DIAGS, HELP, A, X, @@ -372,6 +373,21 @@ public class RecognizedOptions { return super.process(options, option); } }, + new HiddenOption(DIAGS) { + @Override + public boolean process(Options options, String option) { + Option xd = getOptions(helper, EnumSet.of(XD))[0]; + option = option.substring(option.indexOf('=') + 1); + String diagsOption = option.contains("%") ? + "-XDdiagsFormat=" : + "-XDdiags="; + diagsOption += option; + if (xd.matches(diagsOption)) + return xd.process(options, diagsOption); + else + return false; + } + }, new Option(HELP, "opt.help") { @Override public boolean process(Options options, String option) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index a1bd2da6e55..e3668716283 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java index f6af2af4698..bdf2671bff0 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,6 +111,7 @@ public class JavacRoundEnvironment implements RoundEnvironment { */ public Set<? extends Element> getElementsAnnotatedWith(TypeElement a) { Set<Element> result = Collections.emptySet(); + Types typeUtil = processingEnv.getTypeUtils(); if (a.getKind() != ElementKind.ANNOTATION_TYPE) throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a); @@ -122,7 +123,7 @@ public class JavacRoundEnvironment implements RoundEnvironment { throw new AssertionError("Bad implementation type for " + tm); ElementScanner6<Set<Element>, DeclaredType> scanner = - new AnnotationSetScanner(result); + new AnnotationSetScanner(result, typeUtil); for (Element element : rootElements) result = scanner.scan(element, annotationTypeElement); @@ -135,9 +136,11 @@ public class JavacRoundEnvironment implements RoundEnvironment { ElementScanner6<Set<Element>, DeclaredType> { // Insertion-order preserving set Set<Element> annotatedElements = new LinkedHashSet<Element>(); + Types typeUtil; - AnnotationSetScanner(Set<Element> defaultSet) { + AnnotationSetScanner(Set<Element> defaultSet, Types typeUtil) { super(defaultSet); + this.typeUtil = typeUtil; } @Override @@ -145,7 +148,7 @@ public class JavacRoundEnvironment implements RoundEnvironment { java.util.List<? extends AnnotationMirror> annotationMirrors = processingEnv.getElementUtils().getAllAnnotationMirrors(e); for (AnnotationMirror annotationMirror : annotationMirrors) { - if (annotationMirror.getAnnotationType().equals(p)) + if (typeUtil.isSameType(annotationMirror.getAnnotationType(), p)) annotatedElements.add(e); } e.accept(this, p); diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java b/langtools/src/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java index a9433585fcb..c80613360d5 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,7 +125,7 @@ public class PrintingProcessor extends AbstractProcessor { return this; defaultAction(e, true); - printFormalTypeParameters(e); + printFormalTypeParameters(e, true); switch(kind) { case CONSTRUCTOR: @@ -207,7 +207,7 @@ public class PrintingProcessor extends AbstractProcessor { writer.print(" "); writer.print(e.getSimpleName()); - printFormalTypeParameters(e); + printFormalTypeParameters(e, false); // Print superclass information if informative if (kind == CLASS) { @@ -364,16 +364,9 @@ public class PrintingProcessor extends AbstractProcessor { } } - private void printFormalTypeParameters(ExecutableElement executable) { - printFormalTypeParameters(executable.getTypeParameters(), true); - } - - private void printFormalTypeParameters(TypeElement type) { - printFormalTypeParameters(type.getTypeParameters(), false); - } - - private void printFormalTypeParameters(List<? extends TypeParameterElement> typeParams, + private void printFormalTypeParameters(Parameterizable e, boolean pad) { + List<? extends TypeParameterElement> typeParams = e.getTypeParameters(); if (typeParams.size() > 0) { writer.print("<"); diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index a7e75fa5f1e..ea8f2d245d1 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1,5 +1,5 @@ # -# Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -836,6 +836,9 @@ compiler.misc.anonymous.class=\ compiler.misc.type.captureof=\ capture#{0} of {1} +compiler.misc.type.captureof.1=\ + capture#{0} + compiler.misc.type.none=\ <none> @@ -907,16 +910,16 @@ compiler.err.not.within.bounds.explain=\ compiler.err.prob.found.req=\ {0}\n\ -found : {1}\n\ -required: {2} +required: {2}\n\ +found: {1} compiler.warn.prob.found.req=\ {0}\n\ -found : {1}\n\ -required: {2} +required: {2}\n\ +found: {1} compiler.err.prob.found.req.1=\ {0} {3}\n\ -found : {1}\n\ -required: {2} +required: {2}\n\ +found: {1} ## The following are all possible strings for the first argument ({0}) of the ## above strings. @@ -951,8 +954,8 @@ compiler.misc.assignment.to.extends-bound=\ compiler.err.type.found.req=\ unexpected type\n\ -found : {0}\n\ -required: {1} +required: {1}\n\ +found: {0} ## The following are all possible strings for the first argument ({0}) of the ## above string. @@ -1003,7 +1006,7 @@ compiler.err.non-static.cant.be.ref=\ compiler.err.unexpected.type=\ unexpected type\n\ required: {0}\n\ -found : {1} +found: {1} ## The first argument {0} is a "kindname" (e.g. 'constructor', 'field', etc.) ## The second argument {1} is the non-resolved symbol @@ -1026,17 +1029,17 @@ compiler.err.cant.resolve.args.params=\ ## The sixth argument {5} is the location type compiler.err.cant.resolve.location=\ cannot find symbol\n\ - symbol : {0} {1}\n\ + symbol: {0} {1}\n\ location: {4} {5} compiler.err.cant.resolve.location.args=\ cannot find symbol\n\ - symbol : {0} {1}({3})\n\ + symbol: {0} {1}({3})\n\ location: {4} {5} compiler.err.cant.resolve.location.args.params=\ cannot find symbol\n\ - symbol : {0} <{2}>{1}({3})\n\ + symbol: {0} <{2}>{1}({3})\n\ location: {4} {5} ## The following are all possible string for "kindname". diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties index 4ef8a779c57..62e90966bb5 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties @@ -1,5 +1,5 @@ # -# Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/legacy.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/legacy.properties index 6e7f6bed786..762d94adb25 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/legacy.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/legacy.properties @@ -24,6 +24,7 @@ # com.sun.accessibility.internal.resources = tiger legacy +com.sun.awt = tiger legacy com.sun.beans = tiger legacy com.sun.corba.se.impl.activation = tiger legacy com.sun.corba.se.impl.copyobject = tiger legacy diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java index 1509a2999b6..6dc7d37e7c8 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java b/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java index e930c75d67b..49459fc5f19 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,16 +24,27 @@ */ package com.sun.tools.javac.util; +import java.util.Arrays; import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; +import java.util.Set; import javax.tools.JavaFileObject; import com.sun.tools.javac.api.DiagnosticFormatter; -import com.sun.tools.javac.api.Formattable; +import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.DiagnosticPart; +import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.MultilineLimit; import com.sun.tools.javac.api.DiagnosticFormatter.PositionKind; +import com.sun.tools.javac.api.Formattable; +import com.sun.tools.javac.code.Printer; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Type.CapturedType; import com.sun.tools.javac.file.JavacFileManager; + import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*; -import static com.sun.tools.javac.util.LayoutCharacters.*; /** * This abstract class provides a basic implementation of the functionalities that should be provided @@ -50,35 +61,34 @@ import static com.sun.tools.javac.util.LayoutCharacters.*; public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter<JCDiagnostic> { /** - * JavacMessages object used by this formatter for i18n + * JavacMessages object used by this formatter for i18n. */ protected JavacMessages messages; - protected boolean showSource; /** - * Initialize an AbstractDiagnosticFormatter by setting its JavacMessages object + * Configuration object used by this formatter + */ + private SimpleConfiguration config; + + /** + * Current depth level of the disgnostic being formatted + * (!= 0 for subdiagnostics) + */ + protected int depth = 0; + + /** + * Printer instance to be used for formatting types/symbol + */ + protected Printer printer; + + /** + * Initialize an AbstractDiagnosticFormatter by setting its JavacMessages object. * @param messages */ - protected AbstractDiagnosticFormatter(JavacMessages messages, Options options, boolean showSource) { + protected AbstractDiagnosticFormatter(JavacMessages messages, SimpleConfiguration config) { this.messages = messages; - this.showSource = options.get("showSource") == null ? showSource : - options.get("showSource").equals("true"); - } - - protected AbstractDiagnosticFormatter(JavacMessages messages, boolean showSource) { - this.messages = messages; - this.showSource = showSource; - } - - public String formatMessage(JCDiagnostic d, Locale l) { - //this code should rely on the locale settings but it's not! See RFE 6443132 - StringBuilder buf = new StringBuilder(); - Collection<String> args = formatArguments(d, l); - buf.append(localize(l, d.getCode(), args.toArray())); - if (d.isMultiline()) { - buf.append(formatSubdiagnostics(d, l)); - } - return buf.toString(); + this.config = config; + this.printer = new FormatterPrinter(); } public String formatKind(JCDiagnostic d, Locale l) { @@ -92,12 +102,20 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter } } + @Override + public String format(JCDiagnostic d, Locale locale) { + printer = new FormatterPrinter(); + return formatDiagnostic(d, locale); + } + + abstract String formatDiagnostic(JCDiagnostic d, Locale locale); + public String formatPosition(JCDiagnostic d, PositionKind pk,Locale l) { assert (d.getPosition() != Position.NOPOS); return String.valueOf(getPosition(d, pk)); } - //WHERE - public long getPosition(JCDiagnostic d, PositionKind pk) { + //where + private long getPosition(JCDiagnostic d, PositionKind pk) { switch (pk) { case START: return d.getIntStartPosition(); case END: return d.getIntEndPosition(); @@ -138,17 +156,35 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter * @return string representation of the diagnostic argument */ protected String formatArgument(JCDiagnostic d, Object arg, Locale l) { - if (arg instanceof JCDiagnostic) - return format((JCDiagnostic)arg, l); + if (arg instanceof JCDiagnostic) { + String s = null; + depth++; + try { + s = formatMessage((JCDiagnostic)arg, l); + } + finally { + depth--; + } + return s; + } else if (arg instanceof Iterable<?>) { return formatIterable(d, (Iterable<?>)arg, l); } - else if (arg instanceof JavaFileObject) + else if (arg instanceof Type) { + return printer.visit((Type)arg, l); + } + else if (arg instanceof Symbol) { + return printer.visit((Symbol)arg, l); + } + else if (arg instanceof JavaFileObject) { return JavacFileManager.getJavacBaseFileName((JavaFileObject)arg); - else if (arg instanceof Formattable) + } + else if (arg instanceof Formattable) { return ((Formattable)arg).toString(l, messages); - else + } + else { return String.valueOf(arg); + } } /** @@ -171,45 +207,74 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter } /** - * Format all the subdiagnostics attached to a given diagnostic + * Format all the subdiagnostics attached to a given diagnostic. * * @param d diagnostic whose subdiagnostics are to be formatted * @param l locale object to be used for i18n + * @return list of all string representations of the subdiagnostics + */ + protected List<String> formatSubdiagnostics(JCDiagnostic d, Locale l) { + List<String> subdiagnostics = List.nil(); + int maxDepth = config.getMultilineLimit(MultilineLimit.DEPTH); + if (maxDepth == -1 || depth < maxDepth) { + depth++; + try { + int maxCount = config.getMultilineLimit(MultilineLimit.LENGTH); + int count = 0; + for (JCDiagnostic d2 : d.getSubdiagnostics()) { + if (maxCount == -1 || count < maxCount) { + subdiagnostics = subdiagnostics.append(formatSubdiagnostic(d, d2, l)); + count++; + } + else + break; + } + } + finally { + depth--; + } + } + return subdiagnostics; + } + + /** + * Format a subdiagnostics attached to a given diagnostic. + * + * @param parent multiline diagnostic whose subdiagnostics is to be formatted + * @param sub subdiagnostic to be formatted + * @param l locale object to be used for i18n * @return string representation of the subdiagnostics */ - protected String formatSubdiagnostics(JCDiagnostic d, Locale l) { - StringBuilder buf = new StringBuilder(); - for (JCDiagnostic d2 : d.getSubdiagnostics()) { - buf.append('\n'); - String subdiagMsg = format(d2, l); - buf.append(indent(subdiagMsg, DiagInc)); - } - return buf.toString(); + protected String formatSubdiagnostic(JCDiagnostic parent, JCDiagnostic sub, Locale l) { + return formatMessage(sub, l); } /** Format the faulty source code line and point to the error. * @param d The diagnostic for which the error line should be printed */ - protected String formatSourceLine(JCDiagnostic d) { + protected String formatSourceLine(JCDiagnostic d, int nSpaces) { StringBuilder buf = new StringBuilder(); DiagnosticSource source = d.getDiagnosticSource(); int pos = d.getIntPosition(); - if (d.getIntPosition() != Position.NOPOS) { - String line = (source == null ? null : source.getLine(pos)); - if (line == null) - return ""; - buf.append(line+"\n"); - int col = source.getColumnNumber(pos, false); + if (d.getIntPosition() == Position.NOPOS) + throw new AssertionError(); + String line = (source == null ? null : source.getLine(pos)); + if (line == null) + return ""; + buf.append(indent(line, nSpaces)); + int col = source.getColumnNumber(pos, false); + if (config.isCaretEnabled()) { + buf.append("\n"); for (int i = 0; i < col - 1; i++) { buf.append((line.charAt(i) == '\t') ? "\t" : " "); } - buf.append("^"); - } - return buf.toString(); + buf.append(indent("^", nSpaces)); + } + return buf.toString(); } /** - * Converts a String into a locale-dependent representation accordingly to a given locale + * Converts a String into a locale-dependent representation accordingly to a given locale. * * @param l locale object to be used for i18n * @param key locale-independent key used for looking up in a resource file @@ -221,7 +286,9 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter } public boolean displaySource(JCDiagnostic d) { - return showSource && d.getType() != FRAGMENT; + return config.getVisible().contains(DiagnosticPart.SOURCE) && + d.getType() != FRAGMENT && + d.getIntPosition() != Position.NOPOS; } /** @@ -245,7 +312,7 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter /** * Indent a string by prepending a given amount of empty spaces to each line - * of the string + * of the string. * * @param s the string to be indented * @param nSpaces the amount of spaces that should be prepended to each line @@ -263,4 +330,153 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter } return buf.toString(); } + + public SimpleConfiguration getConfiguration() { + return config; + } + + static public class SimpleConfiguration implements Configuration { + + protected Map<MultilineLimit, Integer> multilineLimits; + protected EnumSet<DiagnosticPart> visibleParts; + protected boolean caretEnabled; + + public SimpleConfiguration(Set<DiagnosticPart> parts) { + multilineLimits = new HashMap<MultilineLimit, Integer>(); + setVisible(parts); + setMultilineLimit(MultilineLimit.DEPTH, -1); + setMultilineLimit(MultilineLimit.LENGTH, -1); + setCaretEnabled(true); + } + + @SuppressWarnings("fallthrough") + public SimpleConfiguration(Options options, Set<DiagnosticPart> parts) { + this(parts); + String showSource = null; + if ((showSource = options.get("showSource")) != null) { + if (showSource.equals("true")) + visibleParts.add(DiagnosticPart.SOURCE); + else if (showSource.equals("false")) + visibleParts.remove(DiagnosticPart.SOURCE); + } + String diagOpts = options.get("diags"); + if (diagOpts != null) {//override -XDshowSource + Collection<String> args = Arrays.asList(diagOpts.split(",")); + if (args.contains("short")) { + visibleParts.remove(DiagnosticPart.DETAILS); + visibleParts.remove(DiagnosticPart.SUBDIAGNOSTICS); + } + if (args.contains("source")) + visibleParts.add(DiagnosticPart.SOURCE); + if (args.contains("-source")) + visibleParts.remove(DiagnosticPart.SOURCE); + } + String multiPolicy = null; + if ((multiPolicy = options.get("multilinePolicy")) != null) { + if (multiPolicy.equals("disabled")) + visibleParts.remove(DiagnosticPart.SUBDIAGNOSTICS); + else if (multiPolicy.startsWith("limit:")) { + String limitString = multiPolicy.substring("limit:".length()); + String[] limits = limitString.split(":"); + try { + switch (limits.length) { + case 2: { + if (!limits[1].equals("*")) + setMultilineLimit(MultilineLimit.DEPTH, Integer.parseInt(limits[1])); + } + case 1: { + if (!limits[0].equals("*")) + setMultilineLimit(MultilineLimit.LENGTH, Integer.parseInt(limits[0])); + } + } + } + catch(NumberFormatException ex) { + setMultilineLimit(MultilineLimit.DEPTH, -1); + setMultilineLimit(MultilineLimit.LENGTH, -1); + } + } + } + String showCaret = null; + if (((showCaret = options.get("showCaret")) != null) && + showCaret.equals("false")) + setCaretEnabled(false); + else + setCaretEnabled(true); + } + + public int getMultilineLimit(MultilineLimit limit) { + return multilineLimits.get(limit); + } + + public EnumSet<DiagnosticPart> getVisible() { + return EnumSet.copyOf(visibleParts); + } + + public void setMultilineLimit(MultilineLimit limit, int value) { + multilineLimits.put(limit, value < -1 ? -1 : value); + } + + + public void setVisible(Set<DiagnosticPart> diagParts) { + visibleParts = EnumSet.copyOf(diagParts); + } + + /** + * Shows a '^' sign under the source line displayed by the formatter + * (if applicable). + * + * @param caretEnabled if true enables caret + */ + public void setCaretEnabled(boolean caretEnabled) { + this.caretEnabled = caretEnabled; + } + + /** + * Tells whether the caret display is active or not. + * + * @param caretEnabled if true the caret is enabled + */ + public boolean isCaretEnabled() { + return caretEnabled; + } + } + + /** + * An enhanced printer for formatting types/symbols used by + * AbstractDiagnosticFormatter. Provides alternate numbering of captured + * types (they are numbered starting from 1 on each new diagnostic, instead + * of relying on the underlying hashcode() method which generates unstable + * output). Also detects cycles in wildcard messages (e.g. if the wildcard + * type referred by a given captured type C contains C itself) which might + * lead to infinite loops. + */ + protected class FormatterPrinter extends Printer { + + List<Type> allCaptured = List.nil(); + List<Type> seenCaptured = List.nil(); + + @Override + protected String localize(Locale locale, String key, Object... args) { + return AbstractDiagnosticFormatter.this.localize(locale, key, args); + } + + @Override + public String visitCapturedType(CapturedType t, Locale locale) { + if (seenCaptured.contains(t)) + return localize(locale, "compiler.misc.type.captureof.1", + allCaptured.indexOf(t) + 1); + else { + try { + seenCaptured = seenCaptured.prepend(t); + allCaptured = allCaptured.append(t); + return localize(locale, "compiler.misc.type.captureof", + allCaptured.indexOf(t) + 1, + visit(t.wildcard, locale)); + } + finally { + seenCaptured = seenCaptured.tail; + } + } + } + } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java b/langtools/src/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java index 02102452cd2..db0b8820a68 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,20 @@ package com.sun.tools.javac.util; +import java.util.Collection; +import java.util.EnumSet; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.regex.Matcher; import javax.tools.JavaFileObject; -import static com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicFormatKind.*; +import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration; +import com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicConfiguration; + import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*; +import static com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicConfiguration.*; +import static com.sun.tools.javac.util.LayoutCharacters.*; /** * A basic formatter for diagnostic messages. @@ -53,7 +60,7 @@ import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*; */ public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter { - protected Map<BasicFormatKind, String> availableFormats; + protected int currentIndentation = 0; /** * Create a basic formatter based on the supplied options. @@ -62,21 +69,8 @@ public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter { * @param msgs JavacMessages object used for i18n */ @SuppressWarnings("fallthrough") - BasicDiagnosticFormatter(Options opts, JavacMessages msgs) { - super(msgs, opts, true); - initAvailableFormats(); - String fmt = opts.get("diags"); - if (fmt != null) { - String[] formats = fmt.split("\\|"); - switch (formats.length) { - case 3: - availableFormats.put(DEFAULT_CLASS_FORMAT, formats[2]); - case 2: - availableFormats.put(DEFAULT_NO_POS_FORMAT, formats[1]); - default: - availableFormats.put(DEFAULT_POS_FORMAT, formats[0]); - } - } + public BasicDiagnosticFormatter(Options options, JavacMessages msgs) { + super(msgs, new BasicConfiguration(options)); } /** @@ -85,18 +79,10 @@ public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter { * @param msgs JavacMessages object used for i18n */ public BasicDiagnosticFormatter(JavacMessages msgs) { - super(msgs, true); - initAvailableFormats(); + super(msgs, new BasicConfiguration()); } - public void initAvailableFormats() { - availableFormats = new HashMap<BasicFormatKind, String>(); - availableFormats.put(DEFAULT_POS_FORMAT, "%f:%l:%_%t%m"); - availableFormats.put(DEFAULT_NO_POS_FORMAT, "%p%m"); - availableFormats.put(DEFAULT_CLASS_FORMAT, "%f:%_%t%m"); - } - - public String format(JCDiagnostic d, Locale l) { + public String formatDiagnostic(JCDiagnostic d, Locale l) { if (l == null) l = messages.getCurrentLocale(); String format = selectFormat(d); @@ -110,10 +96,55 @@ public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter { } buf.append(meta ? formatMeta(c, d, l) : String.valueOf(c)); } - if (displaySource(d)) { - buf.append("\n" + formatSourceLine(d)); + if (depth == 0) + return addSourceLineIfNeeded(d, buf.toString()); + else + return buf.toString(); + } + + public String formatMessage(JCDiagnostic d, Locale l) { + int prevIndentation = currentIndentation; + try { + StringBuilder buf = new StringBuilder(); + Collection<String> args = formatArguments(d, l); + String msg = localize(l, d.getCode(), args.toArray()); + String[] lines = msg.split("\n"); + if (getConfiguration().getVisible().contains(DiagnosticPart.SUMMARY)) { + currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUMMARY); + buf.append(indent(lines[0], currentIndentation)); //summary + } + if (lines.length > 1 && getConfiguration().getVisible().contains(DiagnosticPart.DETAILS)) { + currentIndentation += getConfiguration().getIndentation(DiagnosticPart.DETAILS); + for (int i = 1;i < lines.length; i++) { + buf.append("\n" + indent(lines[i], currentIndentation)); + } + } + if (d.isMultiline() && getConfiguration().getVisible().contains(DiagnosticPart.SUBDIAGNOSTICS)) { + currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUBDIAGNOSTICS); + for (String sub : formatSubdiagnostics(d, l)) { + buf.append("\n" + sub); + } + } + return buf.toString(); + } + finally { + currentIndentation = prevIndentation; + } + } + + protected String addSourceLineIfNeeded(JCDiagnostic d, String msg) { + if (!displaySource(d)) + return msg; + else { + BasicConfiguration conf = getConfiguration(); + int indentSource = conf.getIndentation(DiagnosticPart.SOURCE); + String sourceLine = "\n" + formatSourceLine(d, indentSource); + boolean singleLine = msg.indexOf("\n") == -1; + if (singleLine || getConfiguration().getSourcePosition() == SourcePosition.BOTTOM) + return msg + sourceLine; + else + return msg.replaceFirst("\n", Matcher.quoteReplacement(sourceLine) + "\n"); } - return buf.toString(); } protected String formatMeta(char c, JCDiagnostic d, Locale l) { @@ -164,34 +195,199 @@ public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter { private String selectFormat(JCDiagnostic d) { DiagnosticSource source = d.getDiagnosticSource(); - String format = availableFormats.get(DEFAULT_NO_POS_FORMAT); + String format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT); if (source != null) { if (d.getIntPosition() != Position.NOPOS) { - format = availableFormats.get(DEFAULT_POS_FORMAT); + format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_POS_FORMAT); } else if (source.getFile() != null && source.getFile().getKind() == JavaFileObject.Kind.CLASS) { - format = availableFormats.get(DEFAULT_CLASS_FORMAT); + format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT); } } return format; } - /** - * This enum contains all the kinds of formatting patterns supported - * by a basic diagnostic formatter. - */ - public enum BasicFormatKind { + @Override + public BasicConfiguration getConfiguration() { + return (BasicConfiguration)super.getConfiguration(); + } + + static public class BasicConfiguration extends SimpleConfiguration { + + protected Map<DiagnosticPart, Integer> indentationLevels; + protected Map<BasicFormatKind, String> availableFormats; + protected SourcePosition sourcePosition; + + @SuppressWarnings("fallthrough") + public BasicConfiguration(Options options) { + super(options, EnumSet.of(DiagnosticPart.SUMMARY, + DiagnosticPart.DETAILS, + DiagnosticPart.SUBDIAGNOSTICS, + DiagnosticPart.SOURCE)); + initFormat(); + initIndentation(); + String fmt = options.get("diagsFormat"); + if (fmt != null) { + String[] formats = fmt.split("\\|"); + switch (formats.length) { + case 3: + setFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT, formats[2]); + case 2: + setFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT, formats[1]); + default: + setFormat(BasicFormatKind.DEFAULT_POS_FORMAT, formats[0]); + } + } + String sourcePosition = null; + if ((((sourcePosition = options.get("sourcePosition")) != null)) && + sourcePosition.equals("bottom")) + setSourcePosition(SourcePosition.BOTTOM); + else + setSourcePosition(SourcePosition.AFTER_SUMMARY); + String indent = options.get("diagsIndentation"); + if (indent != null) { + String[] levels = indent.split("\\|"); + try { + switch (levels.length) { + case 5: + setIndentation(DiagnosticPart.JLS, + Integer.parseInt(levels[4])); + case 4: + setIndentation(DiagnosticPart.SUBDIAGNOSTICS, + Integer.parseInt(levels[3])); + case 3: + setIndentation(DiagnosticPart.SOURCE, + Integer.parseInt(levels[2])); + case 2: + setIndentation(DiagnosticPart.DETAILS, + Integer.parseInt(levels[1])); + default: + setIndentation(DiagnosticPart.SUMMARY, + Integer.parseInt(levels[0])); + } + } + catch (NumberFormatException ex) { + initIndentation(); + } + } + } + + public BasicConfiguration() { + super(EnumSet.of(DiagnosticPart.SUMMARY, + DiagnosticPart.DETAILS, + DiagnosticPart.SUBDIAGNOSTICS, + DiagnosticPart.SOURCE)); + initFormat(); + initIndentation(); + } + //where + private void initFormat() { + availableFormats = new HashMap<BasicFormatKind, String>(); + setFormat(BasicFormatKind.DEFAULT_POS_FORMAT, "%f:%l:%_%t%m"); + setFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT, "%p%m"); + setFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT, "%f:%_%t%m"); + } + //where + private void initIndentation() { + indentationLevels = new HashMap<DiagnosticPart, Integer>(); + setIndentation(DiagnosticPart.SUMMARY, 0); + setIndentation(DiagnosticPart.DETAILS, DetailsInc); + setIndentation(DiagnosticPart.SUBDIAGNOSTICS, DiagInc); + setIndentation(DiagnosticPart.SOURCE, 0); + } + /** - * A format string to be used for diagnostics with a given position. - */ - DEFAULT_POS_FORMAT, + * Get the amount of spaces for a given indentation kind + * @param diagPart the diagnostic part for which the indentation is + * to be retrieved + * @return the amount of spaces used for the specified indentation kind + */ + public int getIndentation(DiagnosticPart diagPart) { + return indentationLevels.get(diagPart); + } + /** - * A format string to be used for diagnostics without a given position. - */ - DEFAULT_NO_POS_FORMAT, + * Set the indentation level for various element of a given diagnostic - + * this might lead to more readable diagnostics + * + * @param indentationKind kind of indentation to be set + * @param nSpaces amount of spaces for the specified diagnostic part + */ + public void setIndentation(DiagnosticPart diagPart, int nSpaces) { + indentationLevels.put(diagPart, nSpaces); + } + /** - * A format string to be used for diagnostics regarding classfiles - */ - DEFAULT_CLASS_FORMAT; + * Set the source line positioning used by this formatter + * + * @param sourcePos a positioning value for source line + */ + public void setSourcePosition(SourcePosition sourcePos) { + sourcePosition = sourcePos; + } + + /** + * Get the source line positioning used by this formatter + * + * @return the positioning value used by this formatter + */ + public SourcePosition getSourcePosition() { + return sourcePosition; + } + //where + /** + * A source positioning value controls the position (within a given + * diagnostic message) in which the source line the diagnostic refers to + * should be displayed (if applicable) + */ + public enum SourcePosition { + /** + * Source line is displayed after the diagnostic message + */ + BOTTOM, + /** + * Source line is displayed after the first line of the diagnostic + * message + */ + AFTER_SUMMARY; + } + + /** + * Set a metachar string for a specific format + * + * @param kind the format kind to be set + * @param s the metachar string specifying the format + */ + public void setFormat(BasicFormatKind kind, String s) { + availableFormats.put(kind, s); + } + + /** + * Get a metachar string for a specific format + * + * @param sourcePos a positioning value for source line + */ + public String getFormat(BasicFormatKind kind) { + return availableFormats.get(kind); + } + //where + /** + * This enum contains all the kinds of formatting patterns supported + * by a basic diagnostic formatter. + */ + public enum BasicFormatKind { + /** + * A format string to be used for diagnostics with a given position. + */ + DEFAULT_POS_FORMAT, + /** + * A format string to be used for diagnostics without a given position. + */ + DEFAULT_NO_POS_FORMAT, + /** + * A format string to be used for diagnostics regarding classfiles + */ + DEFAULT_CLASS_FORMAT; + } } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/LayoutCharacters.java b/langtools/src/share/classes/com/sun/tools/javac/util/LayoutCharacters.java index 7e332ebc0f8..dd4f4dd9e03 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/LayoutCharacters.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/LayoutCharacters.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,9 +39,13 @@ public interface LayoutCharacters { */ final static int TabInc = 8; - /** Diagnostic standard indentation + /** Standard indentation for subdiagnostics */ - final static int DiagInc = 2; + final static int DiagInc = 4; + + /** Standard indentation for additional diagnostic lines + */ + final static int DetailsInc = 2; /** Tabulator character. */ diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java index e7359a3c283..d405de58224 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,17 +93,17 @@ public class Log extends AbstractLog { protected DiagnosticListener<? super JavaFileObject> diagListener; /** - * Formatter for diagnostics + * Formatter for diagnostics. */ private DiagnosticFormatter<JCDiagnostic> diagFormatter; /** - * Keys for expected diagnostics + * Keys for expected diagnostics. */ public Set<String> expectDiagKeys; /** - * JavacMessages object used for localization + * JavacMessages object used for localization. */ private JavacMessages messages; @@ -206,6 +206,18 @@ public class Log extends AbstractLog { return source == null ? null : source.getFile(); } + /** Get the current diagnostic formatter. + */ + public DiagnosticFormatter<JCDiagnostic> getDiagnosticFormatter() { + return diagFormatter; + } + + /** Set the current diagnostic formatter. + */ + public void setDiagnosticFormatter(DiagnosticFormatter<JCDiagnostic> diagFormatter) { + this.diagFormatter = diagFormatter; + } + /** Flush the logs */ public void flush() { diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java b/langtools/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java index 433779764b5..7722348e079 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,14 @@ */ package com.sun.tools.javac.util; +import java.util.Collection; +import java.util.EnumSet; import java.util.Locale; +import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.*; import com.sun.tools.javac.api.Formattable; +import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration; + import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*; /** @@ -35,18 +40,21 @@ import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*; * or not the source name and position are set. This formatter provides a standardized, localize-independent * implementation of a diagnostic formatter; as such, this formatter is best suited for testing purposes. */ -public class RawDiagnosticFormatter extends AbstractDiagnosticFormatter { +public final class RawDiagnosticFormatter extends AbstractDiagnosticFormatter { /** * Create a formatter based on the supplied options. * @param msgs */ - public RawDiagnosticFormatter(Options opts) { - super(null, opts, false); + public RawDiagnosticFormatter(Options options) { + super(null, new SimpleConfiguration(options, + EnumSet.of(DiagnosticPart.SUMMARY, + DiagnosticPart.DETAILS, + DiagnosticPart.SUBDIAGNOSTICS))); } //provide common default formats - public String format(JCDiagnostic d, Locale l) { + public String formatDiagnostic(JCDiagnostic d, Locale l) { try { StringBuffer buf = new StringBuffer(); if (d.getPosition() != Position.NOPOS) { @@ -62,7 +70,7 @@ public class RawDiagnosticFormatter extends AbstractDiagnosticFormatter { buf.append(' '); buf.append(formatMessage(d, null)); if (displaySource(d)) - buf.append("\n" + formatSourceLine(d)); + buf.append("\n" + formatSourceLine(d, 0)); return buf.toString(); } catch (Exception e) { @@ -71,6 +79,26 @@ public class RawDiagnosticFormatter extends AbstractDiagnosticFormatter { } } + public String formatMessage(JCDiagnostic d, Locale l) { + StringBuilder buf = new StringBuilder(); + Collection<String> args = formatArguments(d, l); + buf.append(localize(null, d.getCode(), args.toArray())); + if (d.isMultiline() && getConfiguration().getVisible().contains(DiagnosticPart.SUBDIAGNOSTICS)) { + List<String> subDiags = formatSubdiagnostics(d, null); + if (subDiags.nonEmpty()) { + String sep = ""; + buf.append(",{"); + for (String sub : formatSubdiagnostics(d, null)) { + buf.append(sep); + buf.append("(" + sub + ")"); + sep = ","; + } + buf.append('}'); + } + } + return buf.toString(); + } + @Override protected String formatArgument(JCDiagnostic diag, Object arg, Locale l) { String s; @@ -85,23 +113,9 @@ public class RawDiagnosticFormatter extends AbstractDiagnosticFormatter { } @Override - protected String formatSubdiagnostics(JCDiagnostic d, Locale l) { + protected String localize(Locale l, String key, Object... args) { StringBuilder buf = new StringBuilder(); - String sep = ""; - buf.append(",{"); - for (JCDiagnostic d2 : d.getSubdiagnostics()) { - buf.append(sep); - buf.append("(" + format(d2, l) + ")"); - sep = ","; - } - buf.append('}'); - return buf.toString(); - } - - @Override - protected String localize(Locale l, String s, Object... args) { - StringBuffer buf = new StringBuffer(); - buf.append(s); + buf.append(key); String sep = ": "; for (Object o : args) { buf.append(sep); diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java index e3f065650d1..6e5e9ba0229 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/Comment.java b/langtools/src/share/classes/com/sun/tools/javadoc/Comment.java index 6ce71e30600..e0ac8635c5d 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/Comment.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/Comment.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/DocEnv.java b/langtools/src/share/classes/com/sun/tools/javadoc/DocEnv.java index aeb39bf2758..1d7ae15e1ea 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/DocEnv.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/DocEnv.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/DocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/DocImpl.java index 636f9e85211..2985c7d0c7b 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/DocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/DocImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java b/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java index 34397953a58..4bc8902c61d 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/ExecutableMemberDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/ExecutableMemberDocImpl.java index 7647ac03211..85c887876c5 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/ExecutableMemberDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/ExecutableMemberDocImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java index 4da1e1b819b..344ed3b37e8 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocClassReader.java b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocClassReader.java index dbda1435c3b..e9bc1e889b7 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocClassReader.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocClassReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java index 2cb3ab3288d..21e3747dc6f 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/Messager.java b/langtools/src/share/classes/com/sun/tools/javadoc/Messager.java index 4419fc2ea18..74fe605ba48 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/Messager.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/Messager.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java index 97e1b09b66e..990cda4ed1c 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java index e39f0b3e1d4..945eb0d92d0 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/SourcePositionImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/SourcePositionImpl.java index 0e666b83f6d..e445d3746df 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/SourcePositionImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/SourcePositionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/TypeMaker.java b/langtools/src/share/classes/com/sun/tools/javadoc/TypeMaker.java index ec1bb1e8002..be700da7e19 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/TypeMaker.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/TypeMaker.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javah/Gen.java b/langtools/src/share/classes/com/sun/tools/javah/Gen.java index 1f0bb5ebd83..e4b688600d8 100644 --- a/langtools/src/share/classes/com/sun/tools/javah/Gen.java +++ b/langtools/src/share/classes/com/sun/tools/javah/Gen.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java b/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java index 25b7330a0e1..e1dc8bd97a1 100644 --- a/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java +++ b/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java @@ -30,9 +30,12 @@ import com.sun.tools.classfile.Code_attribute; import com.sun.tools.classfile.ConstantPool; import com.sun.tools.classfile.ConstantPoolException; import com.sun.tools.classfile.DescriptorException; +import com.sun.tools.classfile.Instruction; +import com.sun.tools.classfile.Instruction.TypeKind; import com.sun.tools.classfile.Method; +import com.sun.tools.classfile.Opcode; -import static com.sun.tools.classfile.OpCodes.*; +//import static com.sun.tools.classfile.OpCodes.*; /* * Write the contents of a Code attribute. @@ -87,218 +90,92 @@ class CodeWriter extends BasicWriter { } public void writeInstrs(Code_attribute attr) { - try { - for (int pc = 0; pc < attr.code_length;) { - print(" " + pc + ":\t"); - pc += writeInstr(attr, pc); - println(); + for (Instruction instr: attr.getInstructions()) { + try { + writeInstr(instr); + } catch (ArrayIndexOutOfBoundsException e) { + println(report("error at or after byte " + instr.getPC())); + break; } - } catch (Code_attribute.InvalidIndex e) { - println(report(e)); } } - public int writeInstr(Code_attribute attr, int pc) - throws Code_attribute.InvalidIndex { - String lP = ""; - int opcode = attr.getUnsignedByte(pc); - int opcode2; - String mnem; - switch (opcode) { - case opc_nonpriv: - case opc_priv: { - opcode2 = attr.getUnsignedByte(pc + 1); - mnem = opcName((opcode << 8) + opcode2); - if (mnem == null) { - mnem = opcName(opcode) + " " + opcode2; - } - print(mnem); - return 2; - } - case opc_wide: { - opcode2 = attr.getUnsignedByte(pc + 1); - mnem = opcName((opcode << 8) + opcode2); - if (mnem == null) { - print("bytecode " + opcode); - return 1; - } - print(mnem + " " + attr.getUnsignedShort(pc + 2)); - if (opcode2 == opc_iinc) { - print(", " + attr.getShort(pc + 4)); - return 6; - } - return 4; - } - } - mnem = opcName(opcode); - if (mnem == null) { - print("bytecode " + opcode); - return 1; - } - if (opcode > opc_jsr_w) { - print("bytecode " + opcode); - return 1; - } - print(opcName(opcode)); - switch (opcode) { - case opc_aload: - case opc_astore: - case opc_fload: - case opc_fstore: - case opc_iload: - case opc_istore: - case opc_lload: - case opc_lstore: - case opc_dload: - case opc_dstore: - case opc_ret: - print("\t" + attr.getUnsignedByte(pc + 1)); - return 2; - case opc_iinc: - print("\t" + attr.getUnsignedByte(pc + 1) + ", " + attr.getByte(pc + 2)); - return 3; - case opc_tableswitch: - { - int tb = align(pc + 1); - int default_skip = attr.getInt(tb); - int low = attr.getInt(tb + 4); - int high = attr.getInt(tb + 8); - int count = high - low; - print("{ //" + low + " to " + high); - for (int i = 0; i <= count; i++) { - print("\n\t\t" + (i + low) + ": " + lP + (pc + attr.getInt(tb + 12 + 4 * i)) + ";"); - } - print("\n\t\tdefault: " + lP + (default_skip + pc) + " }"); - return tb - pc + 16 + count * 4; - } - case opc_lookupswitch: - { - int tb = align(pc + 1); - int default_skip = attr.getInt(tb); - int npairs = attr.getInt(tb + 4); - print("{ //" + npairs); - for (int i = 1; i <= npairs; i++) { - print("\n\t\t" + attr.getInt(tb + i * 8) + ": " + lP + (pc + attr.getInt(tb + 4 + i * 8)) + ";"); - } - print("\n\t\tdefault: " + lP + (default_skip + pc) + " }"); - return tb - pc + (npairs + 1) * 8; - } - case opc_newarray: - int type = attr.getUnsignedByte(pc + 1); - switch (type) { - case T_BOOLEAN: - print(" boolean"); - break; - case T_BYTE: - print(" byte"); - break; - case T_CHAR: - print(" char"); - break; - case T_SHORT: - print(" short"); - break; - case T_INT: - print(" int"); - break; - case T_LONG: - print(" long"); - break; - case T_FLOAT: - print(" float"); - break; - case T_DOUBLE: - print(" double"); - break; - case T_CLASS: - print(" class"); - break; - default: - print(" BOGUS TYPE:" + type); - } - return 2; - case opc_anewarray: - { - int index = attr.getUnsignedShort(pc + 1); - print("\t#" + index + "; //"); - printConstant(index); - return 3; - } - case opc_sipush: - print("\t" + attr.getShort(pc + 1)); - return 3; - case opc_bipush: - print("\t" + attr.getByte(pc + 1)); - return 2; - case opc_ldc: - { - int index = attr.getUnsignedByte(pc + 1); - print("\t#" + index + "; //"); - printConstant(index); - return 2; - } - case opc_ldc_w: - case opc_ldc2_w: - case opc_instanceof: - case opc_checkcast: - case opc_new: - case opc_putstatic: - case opc_getstatic: - case opc_putfield: - case opc_getfield: - case opc_invokevirtual: - case opc_invokespecial: - case opc_invokestatic: - { - int index = attr.getUnsignedShort(pc + 1); - print("\t#" + index + "; //"); - printConstant(index); - return 3; - } - case opc_invokeinterface: - { - int index = attr.getUnsignedShort(pc + 1); - int nargs = attr.getUnsignedByte(pc + 3); - print("\t#" + index + ", " + nargs + "; //"); - printConstant(index); - return 5; - } - case opc_multianewarray: - { - int index = attr.getUnsignedShort(pc + 1); - int dimensions = attr.getUnsignedByte(pc + 3); - print("\t#" + index + ", " + dimensions + "; //"); - printConstant(index); - return 4; - } - case opc_jsr: - case opc_goto: - case opc_ifeq: - case opc_ifge: - case opc_ifgt: - case opc_ifle: - case opc_iflt: - case opc_ifne: - case opc_if_icmpeq: - case opc_if_icmpne: - case opc_if_icmpge: - case opc_if_icmpgt: - case opc_if_icmple: - case opc_if_icmplt: - case opc_if_acmpeq: - case opc_if_acmpne: - case opc_ifnull: - case opc_ifnonnull: - print("\t" + lP + (pc + attr.getShort(pc + 1))); - return 3; - case opc_jsr_w: - case opc_goto_w: - print("\t" + lP + (pc + attr.getInt(pc + 1))); - return 5; - default: - return 1; - } + public void writeInstr(Instruction instr) { + print(" " + instr.getPC() + ":\t"); + print(instr.getMnemonic()); + instr.accept(instructionPrinter, null); + println(); } + // where + Instruction.KindVisitor<Void,Void> instructionPrinter = + new Instruction.KindVisitor<Void,Void>() { + + public Void visitNoOperands(Instruction instr, Void p) { + return null; + } + + public Void visitArrayType(Instruction instr, TypeKind kind, Void p) { + print(" " + kind.name); + return null; + } + + public Void visitBranch(Instruction instr, int offset, Void p) { + print("\t" + (instr.getPC() + offset)); + return null; + } + + public Void visitConstantPoolRef(Instruction instr, int index, Void p) { + print("\t#" + index + "; //"); + printConstant(index); + return null; + } + + public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Void p) { + print("\t#" + index + ", " + value + "; //"); + printConstant(index); + return null; + } + + public Void visitLocal(Instruction instr, int index, Void p) { + print("\t" + index); + return null; + } + + public Void visitLocalAndValue(Instruction instr, int index, int value, Void p) { + print("\t" + index + ", " + value); + return null; + } + + public Void visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets) { + int pc = instr.getPC(); + print("{ //" + npairs); + for (int i = 0; i < npairs; i++) { + print("\n\t\t" + matches[i] + ": " + (pc + offsets[i]) + ";"); + } + print("\n\t\tdefault: " + (pc + default_) + " }"); + return null; + } + + public Void visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets) { + int pc = instr.getPC(); + print("{ //" + low + " to " + high); + for (int i = 0; i < offsets.length; i++) { + print("\n\t\t" + (low + i) + ": " + (pc + offsets[i]) + ";"); + } + print("\n\t\tdefault: " + (pc + default_) + " }"); + return null; + } + + public Void visitValue(Instruction instr, int value, Void p) { + print("\t" + value); + return null; + } + + public Void visitUnknown(Instruction instr, Void p) { + return null; + } + }; + public void writeExceptionTable(Code_attribute attr) { if (attr.exception_table_langth > 0) { diff --git a/langtools/src/share/classes/com/sun/tools/javap/InternalError.java b/langtools/src/share/classes/com/sun/tools/javap/InternalError.java index cc3903e0f1b..55d4a56bedb 100644 --- a/langtools/src/share/classes/com/sun/tools/javap/InternalError.java +++ b/langtools/src/share/classes/com/sun/tools/javap/InternalError.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/src/share/classes/javax/annotation/processing/Filer.java b/langtools/src/share/classes/javax/annotation/processing/Filer.java index e0da17b5169..7ebdc6fb72a 100644 --- a/langtools/src/share/classes/javax/annotation/processing/Filer.java +++ b/langtools/src/share/classes/javax/annotation/processing/Filer.java @@ -35,9 +35,11 @@ import java.io.IOException; * processor. Files created in this way will be known to the * annotation processing tool implementing this interface, better * enabling the tool to manage them. Source and class files so - * created will be considered for processing by the tool after the - * {@code close} method has been called on the {@code Writer} or - * {@code OutputStream} used to write the contents of the file. + * created will be {@linkplain RoundEnvironment#getRootElements + * considered for processing} by the tool in a subsequent {@linkplain + * RoundEnvironment round of processing} after the {@code close} + * method has been called on the {@code Writer} or {@code + * OutputStream} used to write the contents of the file. * * Three kinds of files are distinguished: source files, class files, * and auxiliary resource files. diff --git a/langtools/src/share/classes/javax/lang/model/element/ExecutableElement.java b/langtools/src/share/classes/javax/lang/model/element/ExecutableElement.java index 180f23b4271..427373fd4d9 100644 --- a/langtools/src/share/classes/javax/lang/model/element/ExecutableElement.java +++ b/langtools/src/share/classes/javax/lang/model/element/ExecutableElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import javax.lang.model.type.*; * @see ExecutableType * @since 1.6 */ -public interface ExecutableElement extends Element { +public interface ExecutableElement extends Element, Parameterizable { /** * Returns the formal type parameters of this executable * in declaration order. diff --git a/langtools/src/share/classes/javax/lang/model/element/PackageElement.java b/langtools/src/share/classes/javax/lang/model/element/PackageElement.java index 56df80ab118..e6b74e2f295 100644 --- a/langtools/src/share/classes/javax/lang/model/element/PackageElement.java +++ b/langtools/src/share/classes/javax/lang/model/element/PackageElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package javax.lang.model.element; - /** * Represents a package program element. Provides access to information * about the package and its members. @@ -36,8 +35,7 @@ package javax.lang.model.element; * @see javax.lang.model.util.Elements#getPackageOf * @since 1.6 */ - -public interface PackageElement extends Element { +public interface PackageElement extends Element, QualifiedNameable { /** * Returns the fully qualified name of this package. diff --git a/langtools/src/share/classes/javax/lang/model/element/Parameterizable.java b/langtools/src/share/classes/javax/lang/model/element/Parameterizable.java new file mode 100644 index 00000000000..cc428b208ea --- /dev/null +++ b/langtools/src/share/classes/javax/lang/model/element/Parameterizable.java @@ -0,0 +1,45 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.lang.model.element; + +import java.util.List; + +/** + * A mixin interface for an element that has type parameters. + * + * @author Joseph D. Darcy + * @since 1.7 + */ +public interface Parameterizable extends Element { + /** + * Returns the formal type parameters of the type element in + * declaration order. + * + * @return the formal type parameters, or an empty list + * if there are none + */ + List<? extends TypeParameterElement> getTypeParameters(); +} diff --git a/langtools/src/share/classes/javax/lang/model/element/QualifiedNameable.java b/langtools/src/share/classes/javax/lang/model/element/QualifiedNameable.java new file mode 100644 index 00000000000..a6096bf302b --- /dev/null +++ b/langtools/src/share/classes/javax/lang/model/element/QualifiedNameable.java @@ -0,0 +1,41 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.lang.model.element; + +/** + * A mixin interface for an element that has a qualified name. + * + * @author Joseph D. Darcy + * @since 1.7 + */ +public interface QualifiedNameable extends Element { + /** + * Returns the fully qualified name of an element. + * + * @return the fully qualified name of an element + */ + Name getQualifiedName(); +} diff --git a/langtools/src/share/classes/javax/lang/model/element/TypeElement.java b/langtools/src/share/classes/javax/lang/model/element/TypeElement.java index 235a25285f2..808ac778c23 100644 --- a/langtools/src/share/classes/javax/lang/model/element/TypeElement.java +++ b/langtools/src/share/classes/javax/lang/model/element/TypeElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ import javax.lang.model.util.*; * @see DeclaredType * @since 1.6 */ -public interface TypeElement extends Element { +public interface TypeElement extends Element, Parameterizable, QualifiedNameable { /** * Returns the <i>nesting kind</i> of this type element. diff --git a/langtools/src/share/classes/sun/tools/javap/JavapPrinter.java b/langtools/src/share/classes/sun/tools/javap/JavapPrinter.java index af5978aec26..5f693e7fb24 100644 --- a/langtools/src/share/classes/sun/tools/javap/JavapPrinter.java +++ b/langtools/src/share/classes/sun/tools/javap/JavapPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/com/sun/javadoc/AuthorDD/AuthorDD.java b/langtools/test/com/sun/javadoc/AuthorDD/AuthorDD.java index 68d4f9ce596..0c5d56e811f 100644 --- a/langtools/test/com/sun/javadoc/AuthorDD/AuthorDD.java +++ b/langtools/test/com/sun/javadoc/AuthorDD/AuthorDD.java @@ -91,7 +91,7 @@ public class AuthorDD // Test multiple @author tags: - { "<DT><STRONG>Author:</STRONG></DT>"+NL+" <DD>Doug Kramer, Jamie, Neal</DD>"+NL, + { "<DT><STRONG>Author:</STRONG></DT>"+NL+" <DD>Doug Kramer, Jamie, Neal</DD>", BUGID + FS + "p1" + FS + "C1.html" }, }; diff --git a/langtools/test/com/sun/javadoc/testClassCrossReferences/TestClassCrossReferences.java b/langtools/test/com/sun/javadoc/testClassCrossReferences/TestClassCrossReferences.java index ced91ed79c1..51a488322a2 100644 --- a/langtools/test/com/sun/javadoc/testClassCrossReferences/TestClassCrossReferences.java +++ b/langtools/test/com/sun/javadoc/testClassCrossReferences/TestClassCrossReferences.java @@ -48,7 +48,7 @@ public class TestClassCrossReferences extends JavadocTester { "<A HREF=\"http://java.sun.com/j2se/1.4/docs/api/java/math/BigInteger.html?is-external=true#gcd(java.math.BigInteger)\" " + "title=\"class or interface in java.math\"><CODE>Link to external member gcd</CODE></A>"}, {BUG_ID + FS + "C.html", - "<STRONG>Overrides:</STRONG><DD><CODE>toString</CODE> in class <CODE>java.lang.Object</CODE>"} + "<STRONG>Overrides:</STRONG></DT><DD><CODE>toString</CODE> in class <CODE>java.lang.Object</CODE>"} }; private static final String[][] NEGATED_TEST = NO_TEST; private static final String[] ARGS = diff --git a/langtools/test/com/sun/javadoc/testConstructorIndent/TestConstructorIndent.java b/langtools/test/com/sun/javadoc/testConstructorIndent/TestConstructorIndent.java index cd892a4e31d..ed27a7b4bac 100644 --- a/langtools/test/com/sun/javadoc/testConstructorIndent/TestConstructorIndent.java +++ b/langtools/test/com/sun/javadoc/testConstructorIndent/TestConstructorIndent.java @@ -45,9 +45,10 @@ public class TestConstructorIndent extends JavadocTester { //Input for string search tests. private static final String[][] TEST = { - {BUG_ID + FS + "C.html", "<DL>"+NL+"<DD>This is just a simple constructor."+ NL + - "<P>"+NL+"<DL>"+NL+"<DT><STRONG>Parameters:</STRONG><DD><CODE>i</CODE> - a param.</DL>"+NL + - "</DL>" + {BUG_ID + FS + "C.html", "<DL>" + NL + "<DD>This is just a simple constructor." + NL + + "<P>" + NL + "</DD>" + NL + "<DD><DL>" + NL + "<DT><STRONG>Parameters:</STRONG>" + + "</DT><DD><CODE>i</CODE> - a param.</DD></DL>" + NL + + "</DD>" + NL + "</DL>" } }; private static final String[][] NEGATED_TEST = NO_TEST; diff --git a/langtools/test/com/sun/javadoc/testDeprecatedDocs/TestDeprecatedDocs.java b/langtools/test/com/sun/javadoc/testDeprecatedDocs/TestDeprecatedDocs.java index ab11813e95e..ef36c8c03bf 100644 --- a/langtools/test/com/sun/javadoc/testDeprecatedDocs/TestDeprecatedDocs.java +++ b/langtools/test/com/sun/javadoc/testDeprecatedDocs/TestDeprecatedDocs.java @@ -78,13 +78,12 @@ public class TestDeprecatedDocs extends JavadocTester { {TARGET_FILE2, "<STRONG>Deprecated.</STRONG>" + NL + "<P>" + NL + - "<DL>" + NL + - "<DT><PRE><FONT SIZE=\"-1\">@Deprecated" + NL + + "<PRE><FONT SIZE=\"-1\">@Deprecated" + NL + "</FONT>public class <STRONG>DeprecatedClassByAnnotation</STRONG>"}, {TARGET_FILE2, "public int <STRONG>field</STRONG></PRE>" + NL + "<DL>" + NL + - "<DD><STRONG>Deprecated.</STRONG> <DL>"}, + "<DD><STRONG>Deprecated.</STRONG> </DD></DL>"}, {TARGET_FILE2, "<FONT SIZE=\"-1\">@Deprecated" + NL + "</FONT>public <STRONG>DeprecatedClassByAnnotation</STRONG>()</PRE>" + NL + diff --git a/langtools/test/com/sun/javadoc/testExternalOverridenMethod/TestExternalOverridenMethod.java b/langtools/test/com/sun/javadoc/testExternalOverridenMethod/TestExternalOverridenMethod.java index 4308ccfe27f..204b1a9772e 100644 --- a/langtools/test/com/sun/javadoc/testExternalOverridenMethod/TestExternalOverridenMethod.java +++ b/langtools/test/com/sun/javadoc/testExternalOverridenMethod/TestExternalOverridenMethod.java @@ -39,13 +39,13 @@ public class TestExternalOverridenMethod extends JavadocTester { private static final String BUG_ID = "4857717"; private static final String[][] TEST = { {BUG_ID + FS + "pkg" + FS + "XReader.html", - "<STRONG>Overrides:</STRONG><DD><CODE><A HREF=\"" + + "<STRONG>Overrides:</STRONG></DT><DD><CODE><A HREF=\"" + "http://java.sun.com/j2se/1.4.1/docs/api/java/io/FilterReader.html?is-external=true#read()\"" + " title=\"class or interface in java.io\">read</A></CODE> in class " + "<CODE><A HREF=\"http://java.sun.com/j2se/1.4.1/docs/api/java/io/FilterReader.html?is-external=true\"" + " title=\"class or interface in java.io\">FilterReader</A>"}, {BUG_ID + FS + "pkg" + FS + "XReader.html", - "<STRONG>Specified by:</STRONG><DD><CODE><A HREF=\"" + + "<STRONG>Specified by:</STRONG></DT><DD><CODE><A HREF=\"" + "http://java.sun.com/j2se/1.4.1/docs/api/java/io/DataInput.html?is-external=true#readInt()\"" + " title=\"class or interface in java.io\">readInt</A></CODE> in interface " + "<CODE><A HREF=\"http://java.sun.com/j2se/1.4.1/docs/api/java/io/DataInput.html?is-external=true\"" + diff --git a/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java b/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java index 1ed62c535db..eb82d715b91 100644 --- a/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java +++ b/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java @@ -47,14 +47,16 @@ public class TestHeadings extends JavadocTester { private static final String[][] TEST = { //Package summary {BUG_ID + FS + "pkg1" + FS + "package-summary.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\"><FONT SIZE=\"+2\">" + NL + - "<STRONG>Class Summary</STRONG></FONT></TH>" + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Class</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" }, // Class documentation {BUG_ID + FS + "pkg1" + FS + "C1.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\"><FONT SIZE=\"+2\">" + NL + - "<STRONG>Field Summary</STRONG></FONT></TH>" + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Field and Description</TH>" }, {BUG_ID + FS + "pkg1" + FS + "C1.html", "<TH ALIGN=\"left\"><STRONG>Methods inherited from class " + "java.lang.Object</STRONG></TH>" @@ -62,29 +64,32 @@ public class TestHeadings extends JavadocTester { // Class use documentation {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\"><FONT SIZE=\"+2\">" + NL + - "Packages that use <A HREF=\"../../pkg1/C1.html\" " + "title=\"class in pkg1\">C1</A></FONT></TH>" + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Package</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Description</TH>" }, {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", "<TH ALIGN=\"left\" COLSPAN=\"2\"><FONT SIZE=\"+2\">" + NL + "Uses of <A HREF=\"../../pkg1/C1.html\" " + "title=\"class in pkg1\">C1</A> in " + "<A HREF=\"../../pkg2/package-summary.html\">pkg2</A></FONT></TH>" }, {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Fields in " + "<A HREF=\"../../pkg2/package-summary.html\">pkg2</A> " + "declared as <A HREF=\"../../pkg1/C1.html\" " + "title=\"class in pkg1\">C1</A></FONT></TH>" + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Field and Description</TH>" }, // Deprecated {BUG_ID + FS + "deprecated-list.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\"><FONT SIZE=\"+2\">" + NL + - "<STRONG>Deprecated Methods</STRONG></FONT></TH>" + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Method and Description</TH>" }, // Constant values {BUG_ID + FS + "constant-values.html", - "<TH ALIGN=\"left\" COLSPAN=\"3\">pkg1.<A HREF=\"pkg1/C1.html\" " + "title=\"class in pkg1\">C1</A></TH>" - }, - {BUG_ID + FS + "constant-values.html", - "<TH ALIGN=\"left\" COLSPAN=\"3\">pkg1.<A HREF=\"pkg1/C1.html\" " + "title=\"class in pkg1\">C1</A></TH>" + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Constant Field</TH>" + NL + + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>Value</TH>" }, // Serialized Form diff --git a/langtools/test/com/sun/javadoc/testHref/TestHref.java b/langtools/test/com/sun/javadoc/testHref/TestHref.java index 609c66d89bd..aed2a46842e 100644 --- a/langtools/test/com/sun/javadoc/testHref/TestHref.java +++ b/langtools/test/com/sun/javadoc/testHref/TestHref.java @@ -67,7 +67,7 @@ public class TestHref extends JavadocTester { }, //@see test. {BUG_ID + FS + "pkg" + FS + "C2.html", - "See Also:</STRONG><DD><A HREF=\"../pkg/C1.html#method(int, int, java.util.ArrayList)\">" + "See Also:</STRONG></DT><DD><A HREF=\"../pkg/C1.html#method(int, int, java.util.ArrayList)\">" }, //Header does not link to the page itself. diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java new file mode 100644 index 00000000000..652de517cb5 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java @@ -0,0 +1,378 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6786690 6820360 + * @summary This test verifies the nesting of definition list tags. + * @author Bhavesh Patel + * @library ../lib/ + * @build JavadocTester + * @build TestHtmlDefinitionListTag + * @run main TestHtmlDefinitionListTag + */ + +public class TestHtmlDefinitionListTag extends JavadocTester { + + private static final String BUG_ID = "6786690-6820360"; + + // Test common to all runs of javadoc. The class signature should print + // properly enclosed definition list tags and the Annotation Type + // Optional Element should print properly nested definition list tags + // for default value. + private static final String[][] TEST_ALL = { + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<PRE>public class " + + "<STRONG>C1</STRONG>" + NL + "extends " + + "java.lang.Object" + NL + "implements " + + "java.io.Serializable</PRE>"}, + {BUG_ID + FS + "pkg1" + FS + "C4.html", "<DL>" + NL + "<DD><DL>" + NL + + "<DT><STRONG>Default:</STRONG></DT><DD>true</DD>" + NL + + "</DL>" + NL + "</DD>" + NL + "</DL>"}}; + + // Test for normal run of javadoc in which various ClassDocs and + // serialized form should have properly nested definition list tags + // enclosing comments, tags and deprecated information. + private static final String[][] TEST_CMNT_DEPR = { + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "<DL>" + NL + + "<DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>JDK1.0</DD></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + + "<DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>JDK1.0</DD>" + NL + "<DT><STRONG>See Also:</STRONG></DT><DD>" + + "<A HREF=\"../pkg1/C2.html\" title=\"class in pkg1\">" + + "<CODE>C2</CODE></A>, " + NL + + "<A HREF=\"../serialized-form.html#pkg1.C1\">" + + "Serialized Form</A></DD></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> <I>As of JDK version" + + " 1.5, replaced by" + NL + + " <A HREF=\"../pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I></DD>" + + "<DD>This field indicates whether the C1 is undecorated." + NL + + "<P>" + NL + "</DD>" + NL + "<DD><DL>" + NL + "<DT><STRONG>" + + "Since:</STRONG></DT>" + NL + " <DD>1.4</DD>" + NL + "<DT>" + + "<STRONG>See Also:</STRONG></DT><DD>" + + "<A HREF=\"../pkg1/C1.html#setUndecorated(boolean)\"><CODE>" + + "setUndecorated(boolean)</CODE></A></DD></DL>" + NL +"</DD>" + NL + + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + + "<DD>Constructor." + NL + "<P>" + NL + "</DD>" + NL + + "<DD><DL>" + NL + "<DT><STRONG>Parameters:</STRONG></DT><DD>" + + "<CODE>title</CODE> - the title</DD><DD><CODE>test</CODE>" + + " - boolean value</DD>" + NL + "<DT><STRONG>Throws:</STRONG></DT>" + NL + + "<DD><CODE>java.lang.IllegalArgumentException</CODE>" + + " - if the <code>owner</code>'s" + NL + " <code>GraphicsConfiguration" + + "</code> is not from a screen device</DD>" + NL +"<DD><CODE>" + + "HeadlessException</CODE></DD></DL>" + NL + "</DD>" + NL + + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + + "<DD>Method comments." + NL + "<P>" + NL + + "</DD>" + NL + "<DD><DL>" + NL + "<DT><STRONG>Parameters:" + + "</STRONG></DT><DD><CODE>undecorated</CODE> - <code>true</code>" + + " if no decorations are" + NL + " to be enabled;" + NL + + " <code>false</code> if decorations are to be enabled." + + "</DD><DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>1.4</DD>" + NL + "<DT><STRONG>See Also:</STRONG></DT>" + + "<DD><A HREF=\"../pkg1/C1.html#readObject()\"><CODE>" + + "readObject()</CODE></A></DD></DL>" + NL + "</DD>" + NL + + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + "<DD><DL>" + NL + + "<DT><STRONG>Throws:</STRONG></DT>" + NL + "<DD><CODE>" + + "java.io.IOException</CODE></DD><DT><STRONG>See Also:" + + "</STRONG></DT><DD>" + + "<A HREF=\"../pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.ModalExclusionType.html", "<DL>" + NL + + "<DD>No modal exclusion." + NL + "<P>" + NL +"</DD>" + NL + + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C2.html", "<DL>" + NL + "<DD>Constructor." + NL + + "<P>" + NL +"</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C2.html", "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> <I>As of JDK version 1.5, replaced " + + "by" + NL + " <A HREF=\"../pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I>" + NL + "<P>" + NL + + "</DD><DD>Set visible." + NL + "<P>" + NL + "</DD>" +NL + + "<DD><DL>" + NL + "<DT><STRONG>Parameters:</STRONG></DT><DD>" + + "<CODE>set</CODE> - boolean</DD><DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>1.4</DD></DL>" + NL + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C3.html", "<DL>" + NL + "<DD>Comment." + NL + + "<P>" + NL + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + "<DD><DL>" + NL + + "<DT><STRONG>Throws:</STRONG></DT>" + NL + "<DD><CODE>" + + "java.io.IOException</CODE></DD><DT><STRONG>See Also:</STRONG>" + + "</DT><DD><A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>C1.setUndecorated(boolean)</CODE></A></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> <I>As of JDK version " + + "1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I></DD>" + + "<DD>This field indicates whether the C1 is undecorated." + NL + + "<P>" + NL + "</DD>" + NL + "<DD> </DD>" + NL + + "<DD><DL>" + NL + "<DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>1.4</DD>" + NL + "<DT><STRONG>See Also:</STRONG>" + + "</DT><DD><A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>C1.setUndecorated(boolean)</CODE></A></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> <I>As of JDK version" + + " 1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I>" + NL + "<P>" + NL + + "</DD><DD>Reads the object stream." + NL + "<P>" + NL + + "</DD>" + NL + "<DD><DL>" + NL + "<DT><STRONG>Throws:" + + "</STRONG></DT>" + NL + "<DD><CODE><code>" + + "IOException</code></CODE></DD>" + NL + + "<DD><CODE>java.io.IOException</CODE></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> </DD><DD>" + + "The name for this class." + NL + "<P>" + NL + "</DD>" + NL + + "<DD> </DD>" + NL + "</DL>"}}; + + // Test with -nocomment option. The ClassDocs and serialized form should + // have properly nested definition list tags enclosing deprecated + // information and should not display definition lists for comments + // and tags. + private static final String[][] TEST_NOCMNT = { + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> <I>As of JDK version 1.5, replaced by" + NL + + " <A HREF=\"../pkg1/C1.html#setUndecorated(boolean)\"><CODE>" + + "setUndecorated(boolean)</CODE></A>.</I></DD></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C2.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> <I>As of JDK version" + + " 1.5, replaced by" + NL + + " <A HREF=\"../pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I>" + NL + "<P>" + NL + + "</DD></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C5.html", "<PRE>" + NL + + "protected <STRONG>C5</STRONG>()</PRE>" + NL + "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> </DD></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C5.html", "<PRE>" + NL + + "public void <STRONG>printInfo</STRONG>()</PRE>" + NL + "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> </DD></DL>"}, + {BUG_ID + FS + "serialized-form.html", "<PRE>" + NL + "boolean <STRONG>" + + "undecorated</STRONG></PRE>" + NL + "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> <I>As of JDK version 1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\"><CODE>" + + "setUndecorated(boolean)</CODE></A>.</I></DD></DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> <I>As of JDK version" + + " 1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I>" + NL + "<P>" + NL + + "</DD></DL>"}, + {BUG_ID + FS + "serialized-form.html", "<PRE>" + NL + "int <STRONG>" + + "publicKey</STRONG></PRE>" + NL + "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> </DD></DL>"}}; + + // Test with -nodeprecated option. The ClassDocs should have properly nested + // definition list tags enclosing comments and tags. The ClassDocs should not + // display definition list for deprecated information. The serialized form + // should display properly nested definition list tags for comments, tags + // and deprecated information. + private static final String[][] TEST_NODEPR = { + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "<DL>" + NL + + "<DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>JDK1.0</DD></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + + "<DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>JDK1.0</DD>" + NL + "<DT><STRONG>See Also:</STRONG></DT><DD>" + + "<A HREF=\"../pkg1/C2.html\" title=\"class in pkg1\">" + + "<CODE>C2</CODE></A>, " + NL + + "<A HREF=\"../serialized-form.html#pkg1.C1\">" + + "Serialized Form</A></DD></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + + "<DD>Constructor." + NL + "<P>" + NL + "</DD>" + NL + + "<DD><DL>" + NL + "<DT><STRONG>Parameters:</STRONG></DT><DD>" + + "<CODE>title</CODE> - the title</DD><DD><CODE>test</CODE>" + + " - boolean value</DD>" + NL + "<DT><STRONG>Throws:</STRONG></DT>" + NL + + "<DD><CODE>java.lang.IllegalArgumentException</CODE>" + + " - if the <code>owner</code>'s" + NL + " <code>GraphicsConfiguration" + + "</code> is not from a screen device</DD>" + NL +"<DD><CODE>" + + "HeadlessException</CODE></DD></DL>" + NL + "</DD>" + NL + + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + + "<DD>Method comments." + NL + "<P>" + NL + + "</DD>" + NL + "<DD><DL>" + NL + "<DT><STRONG>Parameters:" + + "</STRONG></DT><DD><CODE>undecorated</CODE> - <code>true</code>" + + " if no decorations are" + NL + " to be enabled;" + NL + + " <code>false</code> if decorations are to be enabled." + + "</DD><DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>1.4</DD>" + NL + "<DT><STRONG>See Also:</STRONG></DT>" + + "<DD><A HREF=\"../pkg1/C1.html#readObject()\"><CODE>" + + "readObject()</CODE></A></DD></DL>" + NL + "</DD>" + NL + + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + "<DD><DL>" + NL + + "<DT><STRONG>Throws:</STRONG></DT>" + NL + "<DD><CODE>" + + "java.io.IOException</CODE></DD><DT><STRONG>See Also:" + + "</STRONG></DT><DD>" + + "<A HREF=\"../pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.ModalExclusionType.html", "<DL>" + NL + + "<DD>No modal exclusion." + NL + "<P>" + NL +"</DD>" + NL + + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C2.html", "<DL>" + NL + "<DD>Constructor." + NL + + "<P>" + NL +"</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C3.html", "<DL>" + NL + "<DD>Comment." + NL + + "<P>" + NL + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + "<DD><DL>" + NL + + "<DT><STRONG>Throws:</STRONG></DT>" + NL + "<DD><CODE>" + + "java.io.IOException</CODE></DD><DT><STRONG>See Also:</STRONG>" + + "</DT><DD><A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>C1.setUndecorated(boolean)</CODE></A></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> <I>As of JDK version " + + "1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I></DD>" + + "<DD>This field indicates whether the C1 is undecorated." + NL + + "<P>" + NL + "</DD>" + NL + "<DD> </DD>" + NL + + "<DD><DL>" + NL + "<DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>1.4</DD>" + NL + "<DT><STRONG>See Also:</STRONG>" + + "</DT><DD><A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>C1.setUndecorated(boolean)</CODE></A></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> <I>As of JDK version" + + " 1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I>" + NL + "<P>" + NL + + "</DD><DD>Reads the object stream." + NL + "<P>" + NL + + "</DD>" + NL + "<DD><DL>" + NL + "<DT><STRONG>Throws:" + + "</STRONG></DT>" + NL + "<DD><CODE><code>" + + "IOException</code></CODE></DD>" + NL + + "<DD><CODE>java.io.IOException</CODE></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> </DD><DD>" + + "The name for this class." + NL + "<P>" + NL + "</DD>" + NL + + "<DD> </DD>" + NL + "</DL>"}}; + + // Test with -nocomment and -nodeprecated options. The ClassDocs whould + // not display definition lists for any member details. The serialized + // form should display properly nested definition list tags for + // deprecated information only. + private static final String[][] TEST_NOCMNT_NODEPR = { + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<PRE>" + NL + "public void " + + "<STRONG>readObject</STRONG>()" + NL + " throws" + + " java.io.IOException</PRE>" + NL + "<HR>"}, + {BUG_ID + FS + "pkg1" + FS + "C2.html", "<PRE>" +NL + "public <STRONG>" + + "C2</STRONG>()</PRE>" + NL + "<HR>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.ModalExclusionType.html", "<PRE>" + NL + + "public static final " + + "<A HREF=\"../pkg1/C1.ModalExclusionType.html\" " + + "title=\"enum in pkg1\">C1.ModalExclusionType</A> <STRONG>" + + "APPLICATION_EXCLUDE</STRONG></PRE>" + NL + "<HR>"}, + {BUG_ID + FS + "serialized-form.html", "<PRE>" + NL + "boolean <STRONG>" + + "undecorated</STRONG></PRE>" + NL + "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> <I>As of JDK version 1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\"><CODE>" + + "setUndecorated(boolean)</CODE></A>.</I></DD></DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> <I>As of JDK version" + + " 1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I>" + NL + "<P>" + NL + + "</DD></DL>"}, + {BUG_ID + FS + "serialized-form.html", "<PRE>" + NL + "int <STRONG>" + + "publicKey</STRONG></PRE>" + NL + "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> </DD></DL>"}}; + + // Test for valid HTML generation which should not comprise of empty + // definition list tags. + private static final String[][] NEGATED_TEST = { + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "<DL></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "<DL>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<DL>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.ModalExclusionType.html", "<DL></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.ModalExclusionType.html", "<DL>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C2.html", "<DL></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C2.html", "<DL>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C2.ModalType.html", "<DL></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C2.ModalType.html", "<DL>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C3.html", "<DL></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C3.html", "<DL>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C4.html", "<DL></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C4.html", "<DL>" + NL + "</DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C5.html", "<DL></DL>"}, + {BUG_ID + FS + "pkg1" + FS + "C5.html", "<DL>" + NL + "</DL>"}, + {BUG_ID + FS + "overview-tree.html", "<DL></DL>"}, + {BUG_ID + FS + "overview-tree.html", "<DL>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL></DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + "</DL>"}}; + + private static final String[] ARGS1 = + new String[] { + "-d", BUG_ID, "-sourcepath", SRC_DIR, "pkg1"}; + + private static final String[] ARGS2 = + new String[] { + "-d", BUG_ID, "-nocomment", "-sourcepath", SRC_DIR, "pkg1"}; + + private static final String[] ARGS3 = + new String[] { + "-d", BUG_ID, "-nodeprecated", "-sourcepath", SRC_DIR, "pkg1"}; + + private static final String[] ARGS4 = + new String[] { + "-d", BUG_ID, "-nocomment", "-nodeprecated", "-sourcepath", SRC_DIR, "pkg1"}; + + /** + * The entry point of the test. + * @param args the array of command line arguments. + */ + public static void main(String[] args) { + TestHtmlDefinitionListTag tester = new TestHtmlDefinitionListTag(); + run(tester, ARGS1, TEST_ALL, NEGATED_TEST); + run(tester, ARGS1, TEST_CMNT_DEPR, NEGATED_TEST); + run(tester, ARGS2, TEST_ALL, NEGATED_TEST); + run(tester, ARGS2, TEST_NOCMNT, TEST_CMNT_DEPR); + run(tester, ARGS3, TEST_ALL, NEGATED_TEST); + run(tester, ARGS3, TEST_NODEPR, TEST_NOCMNT_NODEPR); + run(tester, ARGS4, TEST_ALL, NEGATED_TEST); + run(tester, ARGS4, TEST_NOCMNT_NODEPR, TEST_CMNT_DEPR); + tester.printSummary(); + } + + /** + * {@inheritDoc} + */ + public String getBugId() { + return BUG_ID; + } + + /** + * {@inheritDoc} + */ + public String getBugName() { + return getClass().getName(); + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C1.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C1.java new file mode 100644 index 00000000000..a3dbc13e629 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C1.java @@ -0,0 +1,108 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.io.IOException; +import java.io.Serializable; + +/** + * A class comment for testing. + * + * @author Bhavesh Patel + * @see C2 + * @since JDK1.0 + */ + +public class C1 implements Serializable { + + /** + * This field indicates whether the C1 is undecorated. + * + * @see #setUndecorated(boolean) + * @since 1.4 + * @serial + * @deprecated As of JDK version 1.5, replaced by + * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. + */ + @Deprecated + public boolean undecorated = false; + + private String title; + + /** + * This enum specifies the possible modal exclusion types. + * + * @since 1.6 + */ + public static enum ModalExclusionType { + /** + * No modal exclusion. + */ + NO_EXCLUDE, + /** + * <code>APPLICATION_EXCLUDE</code> indicates that a top-level window + * won't be blocked by any application-modal dialogs. Also, it isn't + * blocked by document-modal dialogs from outside of its child hierarchy. + */ + APPLICATION_EXCLUDE + }; + + /** + * Constructor. + * + * @param title the title + * @param test boolean value + * @exception IllegalArgumentException if the <code>owner</code>'s + * <code>GraphicsConfiguration</code> is not from a screen device + * @exception HeadlessException + */ + public C1(String title, boolean test) { + + } + + public C1(String title) { + + } + + /** + * Method comments. + * @param undecorated <code>true</code> if no decorations are + * to be enabled; + * <code>false</code> if decorations are to be enabled. + * @see #readObject() + * @since 1.4 + */ + public void setUndecorated(boolean undecorated) { + /* Make sure we don't run in the middle of peer creation.*/ + } + + /** + * @see #setUndecorated(boolean) + */ + public void readObject() throws IOException { + + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C2.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C2.java new file mode 100644 index 00000000000..b0e098d1e63 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C2.java @@ -0,0 +1,86 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.io.ObjectInputStream; +import java.io.IOException; +import java.io.Serializable; + +/** + * A class comment for testing. + * + * @author Bhavesh Patel + * @see C1 + * @since JDK1.0 + */ + +public class C2 implements Serializable { + + /** + * This field indicates title. + */ + String title; + + public static enum ModalType { + NO_EXCLUDE + }; + + /** + * Constructor. + * + */ + public C2() { + + } + + public C2(String title) { + + } + + /** + * Set visible. + * + * @param set boolean + * @since 1.4 + * @deprecated As of JDK version 1.5, replaced by + * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. + */ + @Deprecated + public void setVisible(boolean set) { + } + + /** + * Reads the object stream. + * + * @param s ObjectInputStream + * @throws <code>IOException</code> + * @deprecated As of JDK version 1.5, replaced by + * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. + */ + @Deprecated + public void readObject(ObjectInputStream s) throws IOException { + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C3.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C3.java new file mode 100644 index 00000000000..cf48cf1cb98 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C3.java @@ -0,0 +1,42 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.lang.annotation.*; + +/** + * Test Annotation class. + * + * @author Bhavesh Patel + * @since 1.5 + */ +@Retention(RetentionPolicy.SOURCE) +public @interface C3 { + /** + * Comment. + */ + String[] value(); +} diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C4.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C4.java new file mode 100644 index 00000000000..0a1fb611c28 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C4.java @@ -0,0 +1,39 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.lang.annotation.*; + +/* + * The @Inherited annotation has no effect when applied to an interface. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface C4 { + boolean value() default true; +} diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C5.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C5.java new file mode 100644 index 00000000000..00ccb7383af --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/C5.java @@ -0,0 +1,65 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.io.Serializable; + +/** + * Test for Serializable + * + * @author Bhavesh Patel + * @deprecated This class is no longer used. + */ +@Deprecated +public abstract class C5 implements Serializable { + + /** + * The name for this class. + * + * @serial + */ + private String name; + + /** + * @serial + */ + private int publicKey; + + /** + * Constructor for serialization only. + */ + protected C5() { + + } + + /** + * Prints general information. + * + */ + public void printInfo() { + + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java new file mode 100644 index 00000000000..201ea4b6199 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Test package 1. + * + * @since JDK1.0 + */ +package pkg1; diff --git a/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java b/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java index 3bb26e83992..c1445255c42 100644 --- a/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java +++ b/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java @@ -38,14 +38,15 @@ public class TestHtmlStrongTag extends JavadocTester { private static final String BUG_ID = "6786028"; private static final String[][] TEST1 = { - {BUG_ID + FS + "pkg1" + FS + "C1.html", "<STRONG>Method Summary</STRONG>"}, - {BUG_ID + FS + "pkg1" + FS + "C1.html", "<STRONG>See Also:</STRONG>"}, - {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "<STRONG>Class Summary</STRONG>"}}; + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<STRONG>See Also:</STRONG>"}}; private static final String[][] NEGATED_TEST1 = { - {BUG_ID + FS + "pkg1" + FS + "C1.html", "<B>"}}; + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<STRONG>Method Summary</STRONG>"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", "<B>"}, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "<STRONG>Class Summary</STRONG>"}}; private static final String[][] TEST2 = { + {BUG_ID + FS + "pkg2" + FS + "C2.html", "<B>Comments:</B>"}}; + private static final String[][] NEGATED_TEST2 = { {BUG_ID + FS + "pkg2" + FS + "C2.html", "<STRONG>Method Summary</STRONG>"}, - {BUG_ID + FS + "pkg2" + FS + "C2.html", "<B>Comments:</B>"}, {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "<STRONG>Class Summary</STRONG>"}}; private static final String[] ARGS1 = @@ -62,7 +63,7 @@ public class TestHtmlStrongTag extends JavadocTester { public static void main(String[] args) { TestHtmlStrongTag tester = new TestHtmlStrongTag(); run(tester, ARGS1, TEST1, NEGATED_TEST1); - run(tester, ARGS2, TEST2, NO_TEST); + run(tester, ARGS2, TEST2, NEGATED_TEST2); tester.printSummary(); } diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java new file mode 100644 index 00000000000..f08ff5783d1 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java @@ -0,0 +1,478 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6786688 + * @summary HTML tables should have table summary, caption and table headers. + * @author Bhavesh Patel + * @library ../lib/ + * @build JavadocTester + * @build TestHtmlTableTags + * @run main TestHtmlTableTags + */ + +public class TestHtmlTableTags extends JavadocTester { + + //Test information. + private static final String BUG_ID = "6786688"; + + //Javadoc arguments. + private static final String[] ARGS = new String[] { + "-d", BUG_ID, "-sourcepath", SRC_DIR, "-use", "pkg1", "pkg2" + }; + + //Input for string tests for HTML table tags. + private static final String[][] TABLE_TAGS_TEST = { + /* + * Test for validating summary for HTML tables + */ + + //Package summary + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Class Summary table, " + + "listing classes, and an explanation\">" + }, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Interface Summary table, " + + "listing interfaces, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Enum Summary table, " + + "listing enums, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Annotation Types Summary table, " + + "listing annotation types, and an explanation\">" + }, + // Class documentation + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Field Summary table, " + + "listing fields, and an explanation\">" + }, + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Method Summary table, " + + "listing methods, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Nested Class Summary table, " + + "listing nested classes, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Constructor Summary table, " + + "listing constructors, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.ModalExclusionType.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Enum Constant Summary table, " + + "listing enum constants, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "C3.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Required Element Summary table, " + + "listing required elements, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "C4.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Optional Element Summary table, " + + "listing optional elements, and an explanation\">" + }, + // Class use documentation + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "I1.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing packages, and an explanation\">" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing fields, and an explanation\">" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing methods, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing fields, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing methods, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing packages, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing methods, and an explanation\">" + }, + // Package use documentation + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing packages, and an explanation\">" + }, + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing classes, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing packages, and an explanation\">" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Use table, " + + "listing classes, and an explanation\">" + }, + // Deprecated + {BUG_ID + FS + "deprecated-list.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Deprecated Fields table, " + + "listing deprecated fields, and an explanation\">" + }, + {BUG_ID + FS + "deprecated-list.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Deprecated Methods table, " + + "listing deprecated methods, and an explanation\">" + }, + // Constant values + {BUG_ID + FS + "constant-values.html", + "<TABLE BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\" " + + "SUMMARY=\"Constant Field Values table, listing " + + "constant fields, and values\">" + }, + // Overview Summary + {BUG_ID + FS + "overview-summary.html", + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" " + + "CELLSPACING=\"0\" SUMMARY=\"Packages table, " + + "listing packages, and an explanation\">" + }, + + /* + * Test for validating caption for HTML tables + */ + + //Package summary + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Class Summary</CAPTION>" + }, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Interface Summary</CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Enum Summary</CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Annotation Types Summary</CAPTION>" + }, + // Class documentation + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Field Summary</CAPTION>" + }, + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Method Summary</CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Nested Class Summary</CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Constructor Summary</CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.ModalExclusionType.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Enum Constant Summary</CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "C3.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Required Element Summary</CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "C4.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Optional Element Summary</CAPTION>" + }, + // Class use documentation + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "I1.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Packages that use <A HREF=\"../../pkg1/I1.html\" " + + "title=\"interface in pkg1\">I1</A></CAPTION>" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Fields in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> " + + "declared as <A HREF=\"../../pkg1/C1.html\" title=\"class in pkg1\">" + + "C1</A></CAPTION>" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> " + + "with parameters of type <A HREF=\"../../pkg1/C1.html\" " + + "title=\"class in pkg1\">C1</A></CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Fields in <A HREF=\"../../pkg1/package-summary.html\">pkg1</A> " + + "declared as <A HREF=\"../../pkg2/C2.html\" title=\"class in pkg2\">" + + "C2</A></CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg1/package-summary.html\">pkg1</A> " + + "with parameters of type <A HREF=\"../../pkg2/C2.html\" " + + "title=\"class in pkg2\">C2</A></CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> " + + "that return <A HREF=\"../../pkg2/C2.ModalExclusionType.html\" " + + "title=\"enum in pkg2\">C2.ModalExclusionType</A></CAPTION>" + }, + // Package use documentation + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Packages that use <A HREF=\"../pkg1/package-summary.html\">" + + "pkg1</A></CAPTION>" + }, + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Classes in <A HREF=\"../pkg1/package-summary.html\">pkg1</A> " + + "used by <A HREF=\"../pkg1/package-summary.html\">pkg1</A></CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Packages that use <A HREF=\"../pkg2/package-summary.html\">" + + "pkg2</A></CAPTION>" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Classes in <A HREF=\"../pkg2/package-summary.html\">pkg2</A> " + + "used by <A HREF=\"../pkg1/package-summary.html\">pkg1</A></CAPTION>" + }, + // Deprecated + {BUG_ID + FS + "deprecated-list.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Deprecated Fields</CAPTION>" + }, + {BUG_ID + FS + "deprecated-list.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Deprecated Methods</CAPTION>" + }, + // Constant values + {BUG_ID + FS + "constant-values.html", + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "pkg1.<A HREF=\"pkg1/C1.html\" title=\"class in pkg1\">C1</A></CAPTION>" + }, + // Overview Summary + {BUG_ID + FS + "overview-summary.html", + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Packages</CAPTION>" + }, + + /* + * Test for validating headers for HTML tables + */ + + //Package summary + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Class</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" + }, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Interface</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Enum</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Annotation Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Description</TH>" + }, + // Class documentation + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Field and Description</TH>" + }, + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Method and Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Class and Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Constructor and Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.ModalExclusionType.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Enum Constant and Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "C3.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Required Element and Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "C4.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Optional Element and Description</TH>" + }, + // Class use documentation + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "I1.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Package</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Field and Description</TH>" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Method and Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Field and Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Method and Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Package</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Method and Description</TH>" + }, + // Package use documentation + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Package</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" + }, + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Class and Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Package</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Class and Description</TH>" + }, + // Deprecated + {BUG_ID + FS + "deprecated-list.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Field and Description</TH>" + }, + {BUG_ID + FS + "deprecated-list.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Method and Description</TH>" + }, + // Constant values + {BUG_ID + FS + "constant-values.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Modifier and Type</TH>" + NL + "<TH CLASS=\"TableHeader\"" + + " SCOPE=\"col\" NOWRAP>Constant Field</TH>" + NL + + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>Value</TH>" + }, + // Overview Summary + {BUG_ID + FS + "overview-summary.html", + "<TH CLASS=\"TableHeader\" SCOPE=\"col\" NOWRAP>" + + "Package</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" + } + }; + private static final String[][] NEGATED_TEST = NO_TEST; + + /** + * The entry point of the test. + * @param args the array of command line arguments. + */ + public static void main(String[] args) { + TestHtmlTableTags tester = new TestHtmlTableTags(); + run(tester, ARGS, TABLE_TAGS_TEST, NEGATED_TEST); + tester.printSummary(); + } + + /** + * {@inheritDoc} + */ + public String getBugId() { + return BUG_ID; + } + + /** + * {@inheritDoc} + */ + public String getBugName() { + return getClass().getName(); + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java new file mode 100644 index 00000000000..5f38d4f1f29 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java @@ -0,0 +1,81 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import pkg2.*; + +/** + * A test class. + * + * @author Bhavesh Patel + */ +public class C1 implements I1 { + + /** + * Test field for class. + */ + public C2 field; + + /** + * Constant value. + */ + public static final String CONSTANT1 = "C1"; + + /** + * A test constructor. + */ + C1() { + } + + /** + * Method thats does some processing. + * + * @param param some parameter that is passed. + * @return a sample object. + */ + public C2 method(C2 param) { + return param; + } + + /** + * Method that is implemented. + * + * @param a some random value. + * @param b some random value. + */ + public void method1(int a, int b) { + } + + /** + * Another inherited method. + * @param c some value. + */ + public void method2(int c) { + } + + /** + * @deprecated don't use this anymore. + */ + public void deprecatedMethod() {} +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java new file mode 100644 index 00000000000..509417825ac --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java @@ -0,0 +1,48 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +/** + * A sample interface used to test table tags. + * + * @author Bhavesh Patel + */ +public interface I1 { + + /** + * A test method. + * + * @param a blah. + * @param b blah. + */ + void method1(int a, int b); + + /** + * Another test method. + * + * @param c blah. + */ + void method2(int c); + +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java new file mode 100644 index 00000000000..024483be5a7 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java @@ -0,0 +1,27 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Test package 1 used to test table tags. + */ +package pkg1; diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java new file mode 100644 index 00000000000..07992e2bad1 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java @@ -0,0 +1,73 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg2; + +import pkg1.*; + +/** + * Another test class. + * + * @author Bhavesh Patel + */ +public class C2 { + + /** + * A test field. + */ + public C1 field; + + /** + * @deprecated don't use this field anymore. + */ + public C1 dep_field; + + /** + * A sample enum. + */ + public static enum ModalExclusionType { + /** + * Test comment. + */ + NO_EXCLUDE, + /** + * Another comment. + */ + APPLICATION_EXCLUDE + }; + + /** + * A string constant. + */ + public static final String CONSTANT1 = "C2"; + + /** + * A sample method. + * + * @param param some parameter. + * @return a test object. + */ + public C1 method(C1 param) { + return param; + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java new file mode 100644 index 00000000000..e410266b6a5 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java @@ -0,0 +1,40 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg2; + +import java.lang.annotation.*; + +/** + * Test Annotation class. + * + * @author Bhavesh Patel + */ +public @interface C3 { + /** + * Comment. + */ + String[] value(); +} diff --git a/jdk/src/share/classes/sun/misc/JavaIODeleteOnExitAccess.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java similarity index 85% rename from jdk/src/share/classes/sun/misc/JavaIODeleteOnExitAccess.java rename to langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java index 54aef8b428a..7eec427be53 100644 --- a/jdk/src/share/classes/sun/misc/JavaIODeleteOnExitAccess.java +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,13 @@ * have any questions. */ -package sun.misc; +package pkg2; -public interface JavaIODeleteOnExitAccess extends Runnable { - public void run(); +import java.lang.annotation.*; + +/* + * A sample interface. + */ +public @interface C4 { + boolean value() default true; } diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java new file mode 100644 index 00000000000..a1523b14326 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java @@ -0,0 +1,27 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Test package 2 used to test table tags. + */ +package pkg2; diff --git a/langtools/test/com/sun/javadoc/testIndex/TestIndex.java b/langtools/test/com/sun/javadoc/testIndex/TestIndex.java index 0594d3d9371..52b61a06278 100644 --- a/langtools/test/com/sun/javadoc/testIndex/TestIndex.java +++ b/langtools/test/com/sun/javadoc/testIndex/TestIndex.java @@ -73,10 +73,10 @@ public class TestIndex extends JavadocTester { {BUG_ID + FS + "index-all.html", "<DT><A HREF=\"./pkg/C.html#Java\"><STRONG>Java</STRONG></A> - " + NL + "Static variable in class pkg.<A HREF=\"./pkg/C.html\" title=\"class in pkg\">C</A>" + NL + - "<DD> " + NL + + "</DT><DD> </DD>" + NL + NL + "<DT><A HREF=\"./pkg/C.html#JDK\"><STRONG>JDK</STRONG></A> - " + NL + "Static variable in class pkg.<A HREF=\"./pkg/C.html\" title=\"class in pkg\">C</A>" + NL + - "<DD> "}, + "</DT><DD> </DD>"}, }; private static final String[][] NEGATED_TEST = NO_TEST; diff --git a/langtools/test/com/sun/javadoc/testInterface/TestInterface.java b/langtools/test/com/sun/javadoc/testInterface/TestInterface.java index 0dd3ebb9003..d5e33d72073 100644 --- a/langtools/test/com/sun/javadoc/testInterface/TestInterface.java +++ b/langtools/test/com/sun/javadoc/testInterface/TestInterface.java @@ -55,7 +55,7 @@ public class TestInterface extends JavadocTester { // Make sure known implementing class list is correct and omits type parameters. {BUG_ID + FS + "pkg" + FS + "Interface.html", - "<DT><STRONG>All Known Implementing Classes:</STRONG> " + + "<DT><STRONG>All Known Implementing Classes:</STRONG></DT> " + "<DD><A HREF=\"../pkg/Child.html\" " + "title=\"class in pkg\">Child</A>, " + "<A HREF=\"../pkg/Parent.html\" title=\"class in pkg\">" + @@ -63,7 +63,9 @@ public class TestInterface extends JavadocTester { // Make sure "All Implemented Interfaces": has substituted type parameters {BUG_ID + FS + "pkg" + FS + "Child.html", - "<STRONG>All Implemented Interfaces:</STRONG> <DD><A HREF=\"../pkg/Interface.html\" title=\"interface in pkg\">Interface</A><T>" + "<STRONG>All Implemented Interfaces:</STRONG></DT> <DD>" + + "<A HREF=\"../pkg/Interface.html\" title=\"interface in pkg\">" + + "Interface</A><T>" }, //Make sure Class Tree has substituted type parameters. {BUG_ID + FS + "pkg" + FS + "Child.html", @@ -75,15 +77,15 @@ public class TestInterface extends JavadocTester { }, //Make sure "Direct Know Subclasses" omits type parameters {BUG_ID + FS + "pkg" + FS + "Parent.html", - "<STRONG>Direct Known Subclasses:</STRONG> <DD><A HREF=\"../pkg/Child.html\" title=\"class in pkg\">Child</A>" + "<STRONG>Direct Known Subclasses:</STRONG></DT> <DD><A HREF=\"../pkg/Child.html\" title=\"class in pkg\">Child</A>" }, //Make sure "Specified By" has substituted type parameters. {BUG_ID + FS + "pkg" + FS + "Child.html", - "<STRONG>Specified by:</STRONG><DD><CODE><A HREF=\"../pkg/Interface.html#method()\">method</A></CODE> in interface <CODE><A HREF=\"../pkg/Interface.html\" title=\"interface in pkg\">Interface</A><<A HREF=\"../pkg/Child.html\" title=\"type parameter in Child\">T</A>></CODE>" + "<STRONG>Specified by:</STRONG></DT><DD><CODE><A HREF=\"../pkg/Interface.html#method()\">method</A></CODE> in interface <CODE><A HREF=\"../pkg/Interface.html\" title=\"interface in pkg\">Interface</A><<A HREF=\"../pkg/Child.html\" title=\"type parameter in Child\">T</A>></CODE>" }, //Make sure "Overrides" has substituted type parameters. {BUG_ID + FS + "pkg" + FS + "Child.html", - "<STRONG>Overrides:</STRONG><DD><CODE><A HREF=\"../pkg/Parent.html#method()\">method</A></CODE> in class <CODE><A HREF=\"../pkg/Parent.html\" title=\"class in pkg\">Parent</A><<A HREF=\"../pkg/Child.html\" title=\"type parameter in Child\">T</A>></CODE>" + "<STRONG>Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg/Parent.html#method()\">method</A></CODE> in class <CODE><A HREF=\"../pkg/Parent.html\" title=\"class in pkg\">Parent</A><<A HREF=\"../pkg/Child.html\" title=\"type parameter in Child\">T</A>></CODE>" }, }; private static final String[][] NEGATED_TEST = { diff --git a/langtools/test/com/sun/javadoc/testLinkOption/TestLinkOption.java b/langtools/test/com/sun/javadoc/testLinkOption/TestLinkOption.java index 1a2156ee03c..37b4949a513 100644 --- a/langtools/test/com/sun/javadoc/testLinkOption/TestLinkOption.java +++ b/langtools/test/com/sun/javadoc/testLinkOption/TestLinkOption.java @@ -63,7 +63,8 @@ public class TestLinkOption extends JavadocTester { "title=\"class or interface in java.lang\">Object</A> p3)" }, {BUG_ID + "-1" + FS + "java" + FS + "lang" + FS + "StringBuilderChild.html", - "public abstract class <STRONG>StringBuilderChild</STRONG><DT>extends <A HREF=\"http://java.sun.com/j2se/1.4/docs/api/java/lang/Object.html?is-external=true\" title=\"class or interface in java.lang\">Object</A>" + "public abstract class <STRONG>StringBuilderChild</STRONG>" + NL + + "extends <A HREF=\"http://java.sun.com/j2se/1.4/docs/api/java/lang/Object.html?is-external=true\" title=\"class or interface in java.lang\">Object</A>" }, }; diff --git a/langtools/test/com/sun/javadoc/testLinkTaglet/TestLinkTaglet.java b/langtools/test/com/sun/javadoc/testLinkTaglet/TestLinkTaglet.java index 1eb2c998639..6983423f832 100644 --- a/langtools/test/com/sun/javadoc/testLinkTaglet/TestLinkTaglet.java +++ b/langtools/test/com/sun/javadoc/testLinkTaglet/TestLinkTaglet.java @@ -59,7 +59,7 @@ public class TestLinkTaglet extends JavadocTester { " Link to another inner class: <A HREF=\"../pkg/C.InnerC2.html\" title=\"class in pkg\"><CODE>C.InnerC2</CODE></A>" }, {BUG_ID + FS + "pkg" + FS + "C.InnerC2.html", - "Enclosing class:</STRONG><DD><A HREF=\"../pkg/C.html\" title=\"class in pkg\">C</A>" + "Enclosing class:</STRONG></DT><DD><A HREF=\"../pkg/C.html\" title=\"class in pkg\">C</A>" }, }; private static final String[][] NEGATED_TEST = { diff --git a/langtools/test/com/sun/javadoc/testMemberInheritence/TestMemberInheritence.java b/langtools/test/com/sun/javadoc/testMemberInheritence/TestMemberInheritence.java index 15b9e343267..12da5956f0e 100644 --- a/langtools/test/com/sun/javadoc/testMemberInheritence/TestMemberInheritence.java +++ b/langtools/test/com/sun/javadoc/testMemberInheritence/TestMemberInheritence.java @@ -74,7 +74,7 @@ public class TestMemberInheritence extends JavadocTester { // Test overriding/implementing methods with generic parameters. {BUG_ID + FS + "pkg" + FS + "BaseClass.html", - "<DT><STRONG>Specified by:</STRONG><DD><CODE><A HREF=\"../pkg/BaseInterface.html#getAnnotation(java.lang.Class)\">getAnnotation</A></CODE> in interface <CODE><A HREF=\"../pkg/BaseInterface.html\" title=\"interface in pkg\">BaseInterface</A></CODE></DL>"}, + "<DT><STRONG>Specified by:</STRONG></DT><DD><CODE><A HREF=\"../pkg/BaseInterface.html#getAnnotation(java.lang.Class)\">getAnnotation</A></CODE> in interface <CODE><A HREF=\"../pkg/BaseInterface.html\" title=\"interface in pkg\">BaseInterface</A></CODE></DD>"+NL+"</DL>"}, // Test diamond inheritence member summary (6256068) {BUG_ID + FS + "diamond" + FS + "Z.html", diff --git a/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java b/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java index 1bc573d3950..5a5fb82b399 100644 --- a/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java +++ b/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java @@ -54,11 +54,12 @@ public class TestNewLanguageFeatures extends JavadocTester { {BUG_ID + FS + "pkg" + FS + "Coin.html", "Enum Coin</H2>"}, //Make sure enum signature is correct. {BUG_ID + FS + "pkg" + FS + "Coin.html", "public enum "+ - "<STRONG>Coin</STRONG><DT>extends java.lang.Enum<" + + "<STRONG>Coin</STRONG>" + NL + "extends java.lang.Enum<" + "<A HREF=\"../pkg/Coin.html\" title=\"enum in pkg\">Coin</A>>" }, //Check for enum constant section - {BUG_ID + FS + "pkg" + FS + "Coin.html", "<STRONG>Enum Constant Summary</STRONG>"}, + {BUG_ID + FS + "pkg" + FS + "Coin.html", "<CAPTION CLASS=\"TableCaption\">" + NL + + "Enum Constant Summary</CAPTION>"}, //Detail for enum constant {BUG_ID + FS + "pkg" + FS + "Coin.html", "<STRONG><A HREF=\"../pkg/Coin.html#Dime\">Dime</A></STRONG>"}, @@ -79,20 +80,20 @@ public class TestNewLanguageFeatures extends JavadocTester { "Class TypeParameters<E></H2>"}, //Check class type parameters section. {BUG_ID + FS + "pkg" + FS + "TypeParameters.html", - "<DT><STRONG>Type Parameters:</STRONG><DD><CODE>E</CODE> - " + + "<DT><STRONG>Type Parameters:</STRONG></DT><DD><CODE>E</CODE> - " + "the type parameter for this class."}, //Type parameters in @see/@link {BUG_ID + FS + "pkg" + FS + "TypeParameters.html", - "<DT><STRONG>See Also:</STRONG><DD><A HREF=\"../pkg/TypeParameters.html\" " + - "title=\"class in pkg\"><CODE>TypeParameters</CODE></A></DL>"}, + "<DT><STRONG>See Also:</STRONG></DT><DD><A HREF=\"../pkg/TypeParameters.html\" " + + "title=\"class in pkg\"><CODE>TypeParameters</CODE></A></DD></DL>"}, //Method that uses class type parameter. {BUG_ID + FS + "pkg" + FS + "TypeParameters.html", "(<A HREF=\"../pkg/TypeParameters.html\" title=\"type " + "parameter in TypeParameters\">E</A> param)"}, //Method type parameter section. {BUG_ID + FS + "pkg" + FS + "TypeParameters.html", - "<STRONG>Type Parameters:</STRONG><DD><CODE>T</CODE> - This is the first " + - "type parameter.<DD><CODE>V</CODE> - This is the second type " + + "<STRONG>Type Parameters:</STRONG></DT><DD><CODE>T</CODE> - This is the first " + + "type parameter.</DD><DD><CODE>V</CODE> - This is the second type " + "parameter."}, //Signature of method with type parameters {BUG_ID + FS + "pkg" + FS + "TypeParameters.html", @@ -117,17 +118,17 @@ public class TestNewLanguageFeatures extends JavadocTester { //Signature of subclass that has type parameters. {BUG_ID + FS + "pkg" + FS + "TypeParameterSubClass.html", "public class <STRONG>TypeParameterSubClass<T extends java.lang.String>" + - "</STRONG><DT>extends <A HREF=\"../pkg/TypeParameterSuperClass.html\" " + + "</STRONG>" + NL + "extends <A HREF=\"../pkg/TypeParameterSuperClass.html\" " + "title=\"class in pkg\">TypeParameterSuperClass</A><T>"}, //Interface generic parameter substitution //Signature of subclass that has type parameters. {BUG_ID + FS + "pkg" + FS + "TypeParameters.html", - "<STRONG>All Implemented Interfaces:</STRONG> <DD><A HREF=\"../pkg/SubInterface.html\" title=\"interface in pkg\">SubInterface</A><E>, <A HREF=\"../pkg/SuperInterface.html\" title=\"interface in pkg\">SuperInterface</A><E></DD>"}, + "<STRONG>All Implemented Interfaces:</STRONG></DT> <DD><A HREF=\"../pkg/SubInterface.html\" title=\"interface in pkg\">SubInterface</A><E>, <A HREF=\"../pkg/SuperInterface.html\" title=\"interface in pkg\">SuperInterface</A><E></DD>"}, {BUG_ID + FS + "pkg" + FS + "SuperInterface.html", - "<STRONG>All Known Subinterfaces:</STRONG> <DD><A HREF=\"../pkg/SubInterface.html\" title=\"interface in pkg\">SubInterface</A><V></DD>"}, + "<STRONG>All Known Subinterfaces:</STRONG></DT> <DD><A HREF=\"../pkg/SubInterface.html\" title=\"interface in pkg\">SubInterface</A><V></DD>"}, {BUG_ID + FS + "pkg" + FS + "SubInterface.html", - "<STRONG>All Superinterfaces:</STRONG> <DD><A HREF=\"../pkg/SuperInterface.html\" title=\"interface in pkg\">SuperInterface</A><V></DD>"}, + "<STRONG>All Superinterfaces:</STRONG></DT> <DD><A HREF=\"../pkg/SuperInterface.html\" title=\"interface in pkg\">SuperInterface</A><V></DD>"}, //================================= // VAR ARG TESTING @@ -158,15 +159,17 @@ public class TestNewLanguageFeatures extends JavadocTester { "public @interface <STRONG>AnnotationType</STRONG>"}, //Make sure member summary headings are correct. {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", - "<STRONG>Required Element Summary</STRONG>"}, + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Required Element Summary</CAPTION>"}, {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", - "<STRONG>Optional Element Summary</STRONG>"}, + "<CAPTION CLASS=\"TableCaption\">" + NL + + "Optional Element Summary</CAPTION>"}, //Make sure element detail heading is correct {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", "Element Detail"}, //Make sure default annotation type value is printed when necessary. {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", - "<STRONG>Default:</STRONG><DD>\"unknown\"</DD>"}, + "<STRONG>Default:</STRONG></DT><DD>\"unknown\"</DD>"}, //================================= // ANNOTATION TYPE USAGE TESTING @@ -182,7 +185,8 @@ public class TestNewLanguageFeatures extends JavadocTester { "<FONT SIZE=\"-1\">" + "<A HREF=\"../pkg/AnnotationType.html\" title=\"annotation in pkg\">@AnnotationType</A>(<A HREF=\"../pkg/AnnotationType.html#optional()\">optional</A>=\"Class Annotation\","+NL + " <A HREF=\"../pkg/AnnotationType.html#required()\">required</A>=1994)"+NL + - "</FONT>public class <STRONG>AnnotationTypeUsage</STRONG><DT>extends java.lang.Object</DL>"}, + "</FONT>public class <STRONG>AnnotationTypeUsage</STRONG>" + NL + + "extends java.lang.Object"}, //FIELD {BUG_ID + FS + "pkg" + FS + "AnnotationTypeUsage.html", @@ -270,8 +274,7 @@ public class TestNewLanguageFeatures extends JavadocTester { {BUG_ID + FS + "pkg1" + FS + "B.html", "<PRE><FONT SIZE=\"-1\"><A HREF=\"../pkg1/A.html\" title=\"annotation in pkg1\">@A</A>"}, {BUG_ID + FS + "pkg1" + FS + "B.html", - "</FONT>public interface <STRONG>B</STRONG></DL>" + NL + - "</PRE>"}, + "</FONT>public interface <STRONG>B</STRONG></PRE>"}, //============================================================== @@ -286,39 +289,57 @@ public class TestNewLanguageFeatures extends JavadocTester { //ClassUseTest1: <T extends Foo & Foo2> {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/Foo.html\" title=\"class in pkg2\">Foo</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/Foo.html\" " + + "title=\"class in pkg2\">Foo</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", "<TD><CODE><STRONG><A HREF=\"../../pkg2/ClassUseTest1.html\" title=\"class in pkg2\">ClassUseTest1<T extends Foo & Foo2></A></STRONG></CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/Foo.html\" title=\"class in pkg2\">Foo</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/Foo.html\" " + + "title=\"class in pkg2\">Foo</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", "<TD><CODE><STRONG>ClassUseTest1.</STRONG><STRONG><A HREF=\"../../pkg2/ClassUseTest1.html#method(T)\">method</A></STRONG>(T t)</CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Fields in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/Foo.html\" title=\"class in pkg2\">Foo</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Fields in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/Foo.html\" " + + "title=\"class in pkg2\">Foo</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", "<A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A><<A HREF=\"../../pkg2/Foo.html\" title=\"class in pkg2\">Foo</A>></CODE></FONT></TD>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Fields in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> declared as <A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Fields in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> declared as <A HREF=\"../../pkg2/ParamTest.html\" " + + "title=\"class in pkg2\">ParamTest</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "<A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A><<A HREF=\"../../pkg2/Foo.html\" title=\"class in pkg2\">Foo</A>></CODE></FONT></TD>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/Foo2.html\" title=\"interface in pkg2\">Foo2</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/Foo2.html\" " + + "title=\"interface in pkg2\">Foo2</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", "<TD><CODE><STRONG><A HREF=\"../../pkg2/ClassUseTest1.html\" title=\"class in pkg2\">ClassUseTest1<T extends Foo & Foo2></A></STRONG></CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/Foo2.html\" title=\"interface in pkg2\">Foo2</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/Foo2.html\" " + + "title=\"interface in pkg2\">Foo2</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", "<TD><CODE><STRONG>ClassUseTest1.</STRONG><STRONG><A HREF=\"../../pkg2/ClassUseTest1.html#method(T)\">method</A></STRONG>(T t)</CODE>" @@ -326,44 +347,66 @@ public class TestNewLanguageFeatures extends JavadocTester { //ClassUseTest2: <T extends ParamTest<Foo3>> {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/ParamTest.html\" " + + "title=\"class in pkg2\">ParamTest</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "<TD><CODE><STRONG><A HREF=\"../../pkg2/ClassUseTest2.html\" title=\"class in pkg2\">ClassUseTest2<T extends ParamTest<<A HREF=\"../../pkg2/Foo3.html\" title=\"class in pkg2\">Foo3</A>>></A></STRONG></CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/ParamTest.html\" " + + "title=\"class in pkg2\">ParamTest</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "<TD><CODE><STRONG>ClassUseTest2.</STRONG><STRONG><A HREF=\"../../pkg2/ClassUseTest2.html#method(T)\">method</A></STRONG>(T t)</CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Fields in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> declared as <A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Fields in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> declared as <A HREF=\"../../pkg2/ParamTest.html\" " + + "title=\"class in pkg2\">ParamTest</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "<A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A><<A HREF=\"../../pkg2/Foo.html\" title=\"class in pkg2\">Foo</A>></CODE></FONT></TD>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/ParamTest.html\" " + + "title=\"class in pkg2\">ParamTest</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "<T extends <A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A><<A HREF=\"../../pkg2/Foo3.html\" title=\"class in pkg2\">Foo3</A>>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/Foo3.html\" title=\"class in pkg2\">Foo3</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/Foo3.html\" " + + "title=\"class in pkg2\">Foo3</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", "<TD><CODE><STRONG><A HREF=\"../../pkg2/ClassUseTest2.html\" title=\"class in pkg2\">ClassUseTest2<T extends ParamTest<<A HREF=\"../../pkg2/Foo3.html\" title=\"class in pkg2\">Foo3</A>>></A></STRONG></CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/Foo3.html\" title=\"class in pkg2\">Foo3</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/Foo3.html\" " + + "title=\"class in pkg2\">Foo3</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", "<TD><CODE><STRONG>ClassUseTest2.</STRONG><STRONG><A HREF=\"../../pkg2/ClassUseTest2.html#method(T)\">method</A></STRONG>(T t)</CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> that return types with arguments of type <A HREF=\"../../pkg2/Foo3.html\" title=\"class in pkg2\">Foo3</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> that return types with arguments of type " + + "<A HREF=\"../../pkg2/Foo3.html\" title=\"class in pkg2\">" + + "Foo3</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", "<T extends <A HREF=\"../../pkg2/ParamTest.html\" title=\"class in pkg2\">ParamTest</A><<A HREF=\"../../pkg2/Foo3.html\" title=\"class in pkg2\">Foo3</A>>>" @@ -371,38 +414,61 @@ public class TestNewLanguageFeatures extends JavadocTester { //ClassUseTest3: <T extends ParamTest2<List<? extends Foo4>>> {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/ParamTest2.html\" title=\"class in pkg2\">ParamTest2</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type " + + "<A HREF=\"../../pkg2/ParamTest2.html\" title=\"class in pkg2\">" + + "ParamTest2</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", "<TD><CODE><STRONG><A HREF=\"../../pkg2/ClassUseTest3.html\" title=\"class in pkg2\">ClassUseTest3<T extends ParamTest2<java.util.List<? extends Foo4>>></A></STRONG></CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/ParamTest2.html\" title=\"class in pkg2\">ParamTest2</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type " + + "<A HREF=\"../../pkg2/ParamTest2.html\" title=\"class in pkg2\">" + + "ParamTest2</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", "<TD><CODE><STRONG>ClassUseTest3.</STRONG><STRONG><A HREF=\"../../pkg2/ClassUseTest3.html#method(T)\">method</A></STRONG>(T t)</CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/ParamTest2.html\" title=\"class in pkg2\">ParamTest2</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type " + + "<A HREF=\"../../pkg2/ParamTest2.html\" title=\"class in pkg2\">" + + "ParamTest2</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", "<T extends <A HREF=\"../../pkg2/ParamTest2.html\" title=\"class in pkg2\">ParamTest2</A><java.util.List<? extends <A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">Foo4</A>>>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">Foo4</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Classes in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type " + + "<A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">" + + "Foo4</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", "<TD><CODE><STRONG><A HREF=\"../../pkg2/ClassUseTest3.html\" title=\"class in pkg2\">ClassUseTest3<T extends ParamTest2<java.util.List<? extends Foo4>>></A></STRONG></CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type parameters of type <A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">Foo4</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type parameters of type <A HREF=\"../../pkg2/Foo4.html\" " + + "title=\"class in pkg2\">Foo4</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", "<TD><CODE><STRONG>ClassUseTest3.</STRONG><STRONG><A HREF=\"../../pkg2/ClassUseTest3.html#method(T)\">method</A></STRONG>(T t)</CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> that return types with arguments of type <A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">Foo4</A></FONT></TH>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Methods in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> that return types with arguments of type " + + "<A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">" + + "Foo4</A></CAPTION>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", "<T extends <A HREF=\"../../pkg2/ParamTest2.html\" title=\"class in pkg2\">ParamTest2</A><java.util.List<? extends <A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">Foo4</A>>>>" @@ -410,81 +476,147 @@ public class TestNewLanguageFeatures extends JavadocTester { //Type parameters in constructor and method args {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Method parameters in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type arguments of type <A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">Foo4</A></FONT></TH>" + NL + - "</TR>" + NL + - "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + - "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + - "<CODE> void</CODE></FONT></TD>" + NL + - "<TD><CODE><STRONG>ClassUseTest3.</STRONG><STRONG><A HREF=\"../../pkg2/ClassUseTest3.html#method(java.util.Set)\">method</A></STRONG>(java.util.Set<<A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">Foo4</A>> p)</CODE>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Method parameters in <A HREF=\"../../pkg2/package-summary.html\">pkg2" + + "</A> with type arguments of type <A HREF=\"../../pkg2/Foo4.html\" " + + "title=\"class in pkg2\">Foo4</A></CAPTION>" + NL + + "<TR>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Modifier and Type" + + "</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Method and Description</TH>" + NL + + "</TR>" + NL + + "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + + "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + + "<CODE> void</CODE></FONT></TD>" + NL + + "<TD><CODE><STRONG>ClassUseTest3.</STRONG><STRONG>" + + "<A HREF=\"../../pkg2/ClassUseTest3.html#method(java.util.Set)\">" + + "method</A></STRONG>(java.util.Set<<A HREF=\"../../pkg2/Foo4.html\" " + + "title=\"class in pkg2\">Foo4</A>> p)</CODE>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "<TH ALIGN=\"left\" COLSPAN=\"2\">Constructor parameters in <A HREF=\"../../pkg2/package-summary.html\">pkg2</A> with type arguments of type <A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">Foo4</A></FONT></TH>" + NL + - "</TR>" + NL + - "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + - "<TD><CODE><STRONG><A HREF=\"../../pkg2/ClassUseTest3.html#ClassUseTest3(java.util.Set)\">ClassUseTest3</A></STRONG>(java.util.Set<<A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">Foo4</A>> p)</CODE>" + "<CAPTION CLASS=\"TableSubCaption\">" + NL + + "Constructor parameters in <A HREF=\"../../pkg2/package-summary.html\">" + + "pkg2</A> with type arguments of type <A HREF=\"../../pkg2/Foo4.html\" " + + "title=\"class in pkg2\">Foo4</A></CAPTION>" + NL + + "<TR>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Constructor and Description" + + "</TH>" + NL + "</TR>" + NL + + "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + + "<TD><CODE><STRONG><A HREF=\"../../pkg2/ClassUseTest3.html#ClassUseTest3" + + "(java.util.Set)\">ClassUseTest3</A></STRONG>(java.util.Set<" + + "<A HREF=\"../../pkg2/Foo4.html\" title=\"class in pkg2\">" + + "Foo4</A>> p)</CODE>" }, //================================= // Annotatation Type Usage //================================= {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "<FONT SIZE=\"+2\">" + NL + - "Packages with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" title=\"annotation in pkg\">AnnotationType</A></FONT></TH>" + NL + - "</TR>" + NL + - "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + - "<TD><A HREF=\"../../pkg/package-summary.html\"><STRONG>pkg</STRONG></A></TD>" + "Packages with annotations of type " + + "<A HREF=\"../../pkg/AnnotationType.html\" " + + "title=\"annotation in pkg\">AnnotationType</A></CAPTION>" + NL + + "<TR>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Package" + + "</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Description</TH>" + NL + "</TR>" + NL + + "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + + "<TD><A HREF=\"../../pkg/package-summary.html\"><STRONG>pkg" + + "</STRONG></A></TD>" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Classes in <A HREF=\"../../pkg/package-summary.html\">pkg</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" title=\"annotation in pkg\">AnnotationType</A></FONT></TH>" + NL + - "</TR>" + NL + - "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + - "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + - "<CODE> class</CODE></FONT></TD>" + NL + - "<TD><CODE><STRONG><A HREF=\"../../pkg/AnnotationTypeUsage.html\" title=\"class in pkg\">AnnotationTypeUsage</A></STRONG></CODE>" + "Classes in <A HREF=\"../../pkg/package-summary.html\">pkg" + + "</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" " + + "title=\"annotation in pkg\">AnnotationType</A></CAPTION>" + NL + + "<TR>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Modifier and Type" + + "</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Class and Description</TH>" + NL + + "</TR>" + NL + + "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + + "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + + "<CODE> class</CODE></FONT></TD>" + NL + + "<TD><CODE><STRONG><A HREF=\"../../pkg/AnnotationTypeUsage.html\" " + + "title=\"class in pkg\">AnnotationTypeUsage</A></STRONG></CODE>" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Fields in <A HREF=\"../../pkg/package-summary.html\">pkg</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" title=\"annotation in pkg\">AnnotationType</A></FONT></TH>" + NL + - "</TR>" + NL + - "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + - "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + - "<CODE> int</CODE></FONT></TD>" + NL + - "<TD><CODE><STRONG>AnnotationTypeUsage.</STRONG><STRONG><A HREF=\"../../pkg/AnnotationTypeUsage.html#field\">field</A></STRONG></CODE>" + "Fields in <A HREF=\"../../pkg/package-summary.html\">pkg" + + "</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" " + + "title=\"annotation in pkg\">AnnotationType</A></CAPTION>" + NL + + "<TR>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Modifier and Type" + + "</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Field and Description</TH>" + NL + + "</TR>" + NL + + "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + + "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + + "<CODE> int</CODE></FONT></TD>" + NL + + "<TD><CODE><STRONG>AnnotationTypeUsage.</STRONG><STRONG>" + + "<A HREF=\"../../pkg/AnnotationTypeUsage.html#field\">field" + + "</A></STRONG></CODE>" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Methods in <A HREF=\"../../pkg/package-summary.html\">pkg</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" title=\"annotation in pkg\">AnnotationType</A></FONT></TH>" + NL + - "</TR>" + NL + - "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + - "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + - "<CODE> void</CODE></FONT></TD>" + NL + - "<TD><CODE><STRONG>AnnotationTypeUsage.</STRONG><STRONG><A HREF=\"../../pkg/AnnotationTypeUsage.html#method()\">method</A></STRONG>()</CODE>" + "Methods in <A HREF=\"../../pkg/package-summary.html\">pkg" + + "</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" " + + "title=\"annotation in pkg\">AnnotationType</A></CAPTION>" + NL + + "<TR>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Modifier and Type" + + "</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Method and Description</TH>" + NL + + "</TR>" + NL + + "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + + "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + + "<CODE> void</CODE></FONT></TD>" + NL + + "<TD><CODE><STRONG>AnnotationTypeUsage.</STRONG><STRONG>" + + "<A HREF=\"../../pkg/AnnotationTypeUsage.html#method()\">" + + "method</A></STRONG>()</CODE>" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Method parameters in <A HREF=\"../../pkg/package-summary.html\">pkg</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" title=\"annotation in pkg\">AnnotationType</A></FONT></TH>" + NL + - "</TR>" + NL + - "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + - "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + - "<CODE> void</CODE></FONT></TD>" + NL + - "<TD><CODE><STRONG>AnnotationTypeUsage.</STRONG><STRONG><A HREF=\"../../pkg/AnnotationTypeUsage.html#methodWithParams(int, int)\">methodWithParams</A></STRONG>(int documented," + NL + - " int undocmented)</CODE>" + "Method parameters in <A HREF=\"../../pkg/package-summary.html\">pkg" + + "</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" " + + "title=\"annotation in pkg\">AnnotationType</A></CAPTION>" + NL + + "<TR>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Modifier and Type" + + "</TH>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Method and Description</TH>" + NL + + "</TR>" + NL + + "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + + "<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><FONT SIZE=\"-1\">" + NL + + "<CODE> void</CODE></FONT></TD>" + NL + + "<TD><CODE><STRONG>AnnotationTypeUsage.</STRONG><STRONG>" + + "<A HREF=\"../../pkg/AnnotationTypeUsage.html#methodWithParams" + + "(int, int)\">methodWithParams</A></STRONG>(int documented," + NL + + " int undocmented)</CODE>" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Constructors in <A HREF=\"../../pkg/package-summary.html\">pkg</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" title=\"annotation in pkg\">AnnotationType</A></FONT></TH>" + NL + - "</TR>" + NL + - "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + - "<TD><CODE><STRONG><A HREF=\"../../pkg/AnnotationTypeUsage.html#AnnotationTypeUsage()\">AnnotationTypeUsage</A></STRONG>()</CODE>" + "Constructors in <A HREF=\"../../pkg/package-summary.html\">pkg" + + "</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" " + + "title=\"annotation in pkg\">AnnotationType</A></CAPTION>" + NL + + "<TR>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Constructor and Description" + + "</TH>" + NL + "</TR>" + NL + + "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + + "<TD><CODE><STRONG><A HREF=\"../../pkg/" + + "AnnotationTypeUsage.html#AnnotationTypeUsage()\">" + + "AnnotationTypeUsage</A></STRONG>()</CODE>" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Constructor parameters in <A HREF=\"../../pkg/package-summary.html\">pkg</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" title=\"annotation in pkg\">AnnotationType</A></FONT></TH>" + NL + - "</TR>" + NL + - "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + - "<TD><CODE><STRONG><A HREF=\"../../pkg/AnnotationTypeUsage.html#AnnotationTypeUsage(int, int)\">AnnotationTypeUsage</A></STRONG>(int documented," + NL + - " int undocmented)</CODE>" + "Constructor parameters in <A HREF=\"../../pkg/package-summary.html\">pkg" + + "</A> with annotations of type <A HREF=\"../../pkg/AnnotationType.html\" " + + "title=\"annotation in pkg\">AnnotationType</A></CAPTION>" + NL + + "<TR>" + NL + "<TH CLASS=\"TableHeader\" SCOPE=\"col\"" + + " NOWRAP>Constructor and Description" + + "</TH>" + NL + "</TR>" + NL + + "<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">" + NL + + "<TD><CODE><STRONG><A HREF=\"../../pkg/" + + "AnnotationTypeUsage.html#AnnotationTypeUsage(int, int)\">" + + "AnnotationTypeUsage</A></STRONG>(int documented," + NL + + " int undocmented)</CODE>" }, //================================= @@ -525,7 +657,7 @@ public class TestNewLanguageFeatures extends JavadocTester { "<FONT SIZE=\"-1\">" + NL + "<A HREF=\"../pkg/AnnotationTypeUndocumented.html\" title=\"annotation in pkg\">@AnnotationTypeUndocumented</A>(<A HREF=\"../pkg/AnnotationType.html#optional\">optional</A>=\"Class Annotation\"," + NL + " <A HREF=\"../pkg/AnnotationType.html#required\">required</A>=1994)" + NL + - "</FONT>public class <STRONG>AnnotationTypeUsage</STRONG><DT>extends java.lang.Object</DL>"}, + "</FONT>public class <STRONG>AnnotationTypeUsage</STRONG></DT><DT>extends java.lang.Object</DT></DL>"}, //FIELD {BUG_ID + FS + "pkg" + FS + "AnnotationTypeUsage.html", diff --git a/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethods.java b/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethods.java index 7c11f4bd70b..fa4e717eff8 100644 --- a/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethods.java +++ b/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethods.java @@ -40,11 +40,11 @@ public class TestOverridenPrivateMethods extends JavadocTester { private static final String[][] TEST = { //The public method should be overriden {BUG_ID + FS + "pkg1" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, //The public method in different package should be overriden {BUG_ID + FS + "pkg2" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"} + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"} }; private static final String[][] NEGATED_TEST = { @@ -52,20 +52,20 @@ public class TestOverridenPrivateMethods extends JavadocTester { //The package private method should be overriden since the base and sub class are in the same //package. However, the link should not show up because the package private methods are not documented. {BUG_ID + FS + "pkg1" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"}, //The private method in should not be overriden {BUG_ID + FS + "pkg1" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, //The private method in different package should not be overriden {BUG_ID + FS + "pkg2" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, //The package private method should not be overriden since the base and sub class are in //different packages. {BUG_ID + FS + "pkg2" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"} + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"} }; private static final String[] ARGS = diff --git a/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethodsWithPackageFlag.java b/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethodsWithPackageFlag.java index ddd4f50b1e8..bf9bc75decc 100644 --- a/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethodsWithPackageFlag.java +++ b/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethodsWithPackageFlag.java @@ -40,32 +40,32 @@ public class TestOverridenPrivateMethodsWithPackageFlag extends JavadocTester { private static final String[][] TEST = { //The public method should be overriden {BUG_ID + FS + "pkg1" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, //The public method in different package should be overriden {BUG_ID + FS + "pkg2" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, //The package private method should be overriden since the base and sub class are in the same //package. {BUG_ID + FS + "pkg1" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"} + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"} }; private static final String[][] NEGATED_TEST = { //The private method in should not be overriden {BUG_ID + FS + "pkg1" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, //The private method in different package should not be overriden {BUG_ID + FS + "pkg2" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, //The package private method should not be overriden since the base and sub class are in //different packages. {BUG_ID + FS + "pkg2" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"}, }; private static final String[] ARGS = diff --git a/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethodsWithPrivateFlag.java b/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethodsWithPrivateFlag.java index 4b338c0328c..6e8caea095d 100644 --- a/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethodsWithPrivateFlag.java +++ b/langtools/test/com/sun/javadoc/testOverridenMethods/TestOverridenPrivateMethodsWithPrivateFlag.java @@ -40,32 +40,32 @@ public class TestOverridenPrivateMethodsWithPrivateFlag extends JavadocTester { private static final String[][] TEST = { //The public method should be overriden {BUG_ID + FS + "pkg1" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, //The package private method should be overriden since the base and sub class are in the same //package. {BUG_ID + FS + "pkg1" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"}, //The public method in different package should be overriden {BUG_ID + FS + "pkg2" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#publicMethod"}, }; private static final String[][] NEGATED_TEST = { //The private method in should not be overriden {BUG_ID + FS + "pkg1" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, //The private method in different package should not be overriden {BUG_ID + FS + "pkg2" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#privateMethod"}, //The package private method should not be overriden since the base and sub class are in //different packages. {BUG_ID + FS + "pkg2" + FS + "SubClass.html", - "Overrides:</STRONG><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"} + "Overrides:</STRONG></DT><DD><CODE><A HREF=\"../pkg1/BaseClass.html#packagePrivateMethod"} }; diff --git a/langtools/test/com/sun/javadoc/testParamTaglet/TestParamTaglet.java b/langtools/test/com/sun/javadoc/testParamTaglet/TestParamTaglet.java index ec802b8d40a..c04cff0a7bb 100644 --- a/langtools/test/com/sun/javadoc/testParamTaglet/TestParamTaglet.java +++ b/langtools/test/com/sun/javadoc/testParamTaglet/TestParamTaglet.java @@ -48,12 +48,12 @@ public class TestParamTaglet extends JavadocTester { private static final String[][] TEST = { //Regular param tags. {BUG_ID + FS + "pkg" + FS + "C.html", - "<STRONG>Parameters:</STRONG><DD><CODE>param1</CODE> - testing 1 2 3." + + "<STRONG>Parameters:</STRONG></DT><DD><CODE>param1</CODE> - testing 1 2 3.</DD>" + "<DD><CODE>param2</CODE> - testing 1 2 3." }, //Param tags that don't match with any real parameters. {BUG_ID + FS + "pkg" + FS + "C.html", - "<STRONG>Parameters:</STRONG><DD><CODE><I>p1</I></CODE> - testing 1 2 3." + + "<STRONG>Parameters:</STRONG></DT><DD><CODE><I>p1</I></CODE> - testing 1 2 3.</DD>" + "<DD><CODE><I>p2</I></CODE> - testing 1 2 3." }, //{@inherit} doc misuse does not cause doclet to throw exception. diff --git a/langtools/test/com/sun/javadoc/testPrivateClasses/TestPrivateClasses.java b/langtools/test/com/sun/javadoc/testPrivateClasses/TestPrivateClasses.java index f7f5bda38a9..69ba4a11ce3 100644 --- a/langtools/test/com/sun/javadoc/testPrivateClasses/TestPrivateClasses.java +++ b/langtools/test/com/sun/javadoc/testPrivateClasses/TestPrivateClasses.java @@ -96,11 +96,11 @@ public class TestPrivateClasses extends JavadocTester { //Make sure implemented interfaces from private superclass are inherited {BUG_ID + "-1" + FS + "pkg" + FS + "PublicInterface.html", - "<STRONG>All Known Implementing Classes:</STRONG> <DD><A HREF=\"../pkg/PublicChild.html\" " + + "<STRONG>All Known Implementing Classes:</STRONG></DT> <DD><A HREF=\"../pkg/PublicChild.html\" " + "title=\"class in pkg\">PublicChild</A>"}, {BUG_ID + "-1" + FS + "pkg" + FS + "PublicChild.html", - "<STRONG>All Implemented Interfaces:</STRONG> <DD><A HREF=\"../pkg/PublicInterface.html\" " + + "<STRONG>All Implemented Interfaces:</STRONG></DT> <DD><A HREF=\"../pkg/PublicInterface.html\" " + "title=\"interface in pkg\">PublicInterface</A>"}, //Generic interface method test. @@ -174,18 +174,18 @@ public class TestPrivateClasses extends JavadocTester { }, // Should document that a method overrides method from private class. {BUG_ID + "-2" + FS + "pkg" + FS + "PublicChild.html", - "<STRONG>Overrides:</STRONG><DD><CODE>" + + "<STRONG>Overrides:</STRONG></DT><DD><CODE>" + "<A HREF=\"../pkg/PrivateParent.html#methodOverridenFromParent(char[], int, T, V, java.util.List)\">" + "methodOverridenFromParent</A></CODE> in class <CODE>" + "<A HREF=\"../pkg/PrivateParent.html\" title=\"class in pkg\">" + - "PrivateParent</A></CODE></DL>"}, + "PrivateParent</A></CODE></DD>" + NL + "</DL>"}, // Should document that a method is specified by private interface. {BUG_ID + "-2" + FS + "pkg" + FS + "PublicChild.html", - "<STRONG>Specified by:</STRONG><DD><CODE>" + + "<STRONG>Specified by:</STRONG></DT><DD><CODE>" + "<A HREF=\"../pkg/PrivateInterface.html#methodInterface(int)\">" + "methodInterface</A></CODE> in interface <CODE>" + "<A HREF=\"../pkg/PrivateInterface.html\" title=\"interface in pkg\">" + - "PrivateInterface</A></CODE></DL>" + NL + "</DD>"}, + "PrivateInterface</A></CODE></DD>" + NL + "</DL>" + NL + "</DD>"}, // Method inheritence from non-public superinterface. {BUG_ID + "-2" + FS + "pkg" + FS + "PublicInterface.html", "Methods inherited from interface " + @@ -209,12 +209,12 @@ public class TestPrivateClasses extends JavadocTester { //Make sure implemented interfaces from private superclass are inherited {BUG_ID + "-2" + FS + "pkg" + FS + "PublicInterface.html", - "<STRONG>All Known Implementing Classes:</STRONG> <DD><A HREF=\"../pkg/PrivateParent.html\" " + + "<STRONG>All Known Implementing Classes:</STRONG></DT> <DD><A HREF=\"../pkg/PrivateParent.html\" " + "title=\"class in pkg\">PrivateParent</A>, " + "<A HREF=\"../pkg/PublicChild.html\" title=\"class in pkg\">PublicChild</A>"}, {BUG_ID + "-2" + FS + "pkg" + FS + "PublicChild.html", - "<STRONG>All Implemented Interfaces:</STRONG> <DD><A HREF=\"../pkg/PrivateInterface.html\" " + + "<STRONG>All Implemented Interfaces:</STRONG></DT> <DD><A HREF=\"../pkg/PrivateInterface.html\" " + "title=\"interface in pkg\">PrivateInterface</A>, " + "<A HREF=\"../pkg/PublicInterface.html\" title=\"interface in pkg\">" + "PublicInterface</A>"}, @@ -226,7 +226,7 @@ public class TestPrivateClasses extends JavadocTester { "<CODE><A HREF=\"../pkg2/I.html#hello(T)\">I</A></CODE></STRONG>"}, {BUG_ID + "-2" + FS + "pkg2" + FS + "C.html", - "<STRONG>Specified by:</STRONG><DD><CODE><A HREF=\"../pkg2/I.html#hello(T)\">" + + "<STRONG>Specified by:</STRONG></DT><DD><CODE><A HREF=\"../pkg2/I.html#hello(T)\">" + "hello</A></CODE> in interface <CODE><A HREF=\"../pkg2/I.html\" " + "title=\"interface in pkg2\">I</A>"}, }; diff --git a/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java new file mode 100644 index 00000000000..4c5d39bba1e --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java @@ -0,0 +1,151 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802694 + * @summary This test verifies deprecation info in serialized-form.html. + * @author Bhavesh Patel + * @library ../lib/ + * @build JavadocTester + * @build TestSerializedFormDeprecationInfo + * @run main TestSerializedFormDeprecationInfo + */ + +public class TestSerializedFormDeprecationInfo extends JavadocTester { + + private static final String BUG_ID = "6802694"; + + // Test for normal run of javadoc. The serialized-form.html should + // display the inline comments, tags and deprecation information if any. + private static final String[][] TEST_CMNT_DEPR = { + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + "<DD><DL>" + NL + + "<DT><STRONG>Throws:</STRONG></DT>" + NL + "<DD><CODE>" + + "java.io.IOException</CODE></DD><DT><STRONG>See Also:</STRONG>" + + "</DT><DD><A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>C1.setUndecorated(boolean)</CODE></A></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> <I>As of JDK version " + + "1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I></DD>" + + "<DD>This field indicates whether the C1 is undecorated." + NL + + "<P>" + NL + "</DD>" + NL + "<DD> </DD>" + NL + + "<DD><DL>" + NL + "<DT><STRONG>Since:</STRONG></DT>" + NL + + " <DD>1.4</DD>" + NL + "<DT><STRONG>See Also:</STRONG>" + + "</DT><DD><A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>C1.setUndecorated(boolean)</CODE></A></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> <I>As of JDK version" + + " 1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I>" + NL + "<P>" + NL + + "</DD><DD>Reads the object stream." + NL + "<P>" + NL + + "</DD>" + NL + "<DD><DL>" + NL + "<DT><STRONG>Throws:" + + "</STRONG></DT>" + NL + "<DD><CODE><code>" + + "IOException</code></CODE></DD>" + NL + + "<DD><CODE>java.io.IOException</CODE></DD></DL>" + NL + + "</DD>" + NL + "</DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + + "<DD><STRONG>Deprecated.</STRONG> </DD><DD>" + + "The name for this class." + NL + "<P>" + NL + "</DD>" + NL + + "<DD> </DD>" + NL + "</DL>"}}; + + // Test with -nocomment option. The serialized-form.html should + // not display the inline comments and tags but should display deprecation + // information if any. + private static final String[][] TEST_NOCMNT = { + {BUG_ID + FS + "serialized-form.html", "<PRE>" + NL + "boolean <STRONG>" + + "undecorated</STRONG></PRE>" + NL + "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> <I>As of JDK version 1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\"><CODE>" + + "setUndecorated(boolean)</CODE></A>.</I></DD></DL>"}, + {BUG_ID + FS + "serialized-form.html", "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> <I>As of JDK version" + + " 1.5, replaced by" + NL + + " <A HREF=\"pkg1/C1.html#setUndecorated(boolean)\">" + + "<CODE>setUndecorated(boolean)</CODE></A>.</I>" + NL + "<P>" + NL + + "</DD></DL>"}, + {BUG_ID + FS + "serialized-form.html", "<PRE>" + NL + "int <STRONG>" + + "publicKey</STRONG></PRE>" + NL + "<DL>" + NL + "<DD><STRONG>" + + "Deprecated.</STRONG> </DD></DL>"}}; + + // Test with -nodeprecated option. The serialized-form.html should + // ignore the -nodeprecated tag and display the deprecation info. This + // test is similar to the normal run of javadoc in which inline comment, tags + // and deprecation information will be displayed. + private static final String[][] TEST_NODEPR = TEST_CMNT_DEPR; + + // Test with -nodeprecated and -nocomment options. The serialized-form.html should + // ignore the -nodeprecated tag and display the deprecation info but should not + // display the inline comments and tags. This test is similar to the test with + // -nocomment option. + private static final String[][] TEST_NOCMNT_NODEPR = TEST_NOCMNT; + + private static final String[] ARGS1 = + new String[] { + "-d", BUG_ID, "-sourcepath", SRC_DIR, "pkg1"}; + + private static final String[] ARGS2 = + new String[] { + "-d", BUG_ID, "-nocomment", "-sourcepath", SRC_DIR, "pkg1"}; + + private static final String[] ARGS3 = + new String[] { + "-d", BUG_ID, "-nodeprecated", "-sourcepath", SRC_DIR, "pkg1"}; + + private static final String[] ARGS4 = + new String[] { + "-d", BUG_ID, "-nocomment", "-nodeprecated", "-sourcepath", SRC_DIR, "pkg1"}; + + /** + * The entry point of the test. + * @param args the array of command line arguments. + */ + public static void main(String[] args) { + TestSerializedFormDeprecationInfo tester = new TestSerializedFormDeprecationInfo(); + run(tester, ARGS1, TEST_CMNT_DEPR, TEST_NOCMNT); + run(tester, ARGS2, TEST_NOCMNT, TEST_CMNT_DEPR); + run(tester, ARGS3, TEST_NODEPR, TEST_NOCMNT_NODEPR); + run(tester, ARGS4, TEST_NOCMNT_NODEPR, TEST_NODEPR); + tester.printSummary(); + } + + /** + * {@inheritDoc} + */ + public String getBugId() { + return BUG_ID; + } + + /** + * {@inheritDoc} + */ + public String getBugName() { + return getClass().getName(); + } +} diff --git a/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C1.java b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C1.java new file mode 100644 index 00000000000..a3dbc13e629 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C1.java @@ -0,0 +1,108 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.io.IOException; +import java.io.Serializable; + +/** + * A class comment for testing. + * + * @author Bhavesh Patel + * @see C2 + * @since JDK1.0 + */ + +public class C1 implements Serializable { + + /** + * This field indicates whether the C1 is undecorated. + * + * @see #setUndecorated(boolean) + * @since 1.4 + * @serial + * @deprecated As of JDK version 1.5, replaced by + * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. + */ + @Deprecated + public boolean undecorated = false; + + private String title; + + /** + * This enum specifies the possible modal exclusion types. + * + * @since 1.6 + */ + public static enum ModalExclusionType { + /** + * No modal exclusion. + */ + NO_EXCLUDE, + /** + * <code>APPLICATION_EXCLUDE</code> indicates that a top-level window + * won't be blocked by any application-modal dialogs. Also, it isn't + * blocked by document-modal dialogs from outside of its child hierarchy. + */ + APPLICATION_EXCLUDE + }; + + /** + * Constructor. + * + * @param title the title + * @param test boolean value + * @exception IllegalArgumentException if the <code>owner</code>'s + * <code>GraphicsConfiguration</code> is not from a screen device + * @exception HeadlessException + */ + public C1(String title, boolean test) { + + } + + public C1(String title) { + + } + + /** + * Method comments. + * @param undecorated <code>true</code> if no decorations are + * to be enabled; + * <code>false</code> if decorations are to be enabled. + * @see #readObject() + * @since 1.4 + */ + public void setUndecorated(boolean undecorated) { + /* Make sure we don't run in the middle of peer creation.*/ + } + + /** + * @see #setUndecorated(boolean) + */ + public void readObject() throws IOException { + + } +} diff --git a/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C2.java b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C2.java new file mode 100644 index 00000000000..b0e098d1e63 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C2.java @@ -0,0 +1,86 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.io.ObjectInputStream; +import java.io.IOException; +import java.io.Serializable; + +/** + * A class comment for testing. + * + * @author Bhavesh Patel + * @see C1 + * @since JDK1.0 + */ + +public class C2 implements Serializable { + + /** + * This field indicates title. + */ + String title; + + public static enum ModalType { + NO_EXCLUDE + }; + + /** + * Constructor. + * + */ + public C2() { + + } + + public C2(String title) { + + } + + /** + * Set visible. + * + * @param set boolean + * @since 1.4 + * @deprecated As of JDK version 1.5, replaced by + * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. + */ + @Deprecated + public void setVisible(boolean set) { + } + + /** + * Reads the object stream. + * + * @param s ObjectInputStream + * @throws <code>IOException</code> + * @deprecated As of JDK version 1.5, replaced by + * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. + */ + @Deprecated + public void readObject(ObjectInputStream s) throws IOException { + } +} diff --git a/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C3.java b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C3.java new file mode 100644 index 00000000000..918a674a0f6 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C3.java @@ -0,0 +1,65 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.io.Serializable; + +/** + * Test for Serializable + * + * @author Bhavesh Patel + * @deprecated This class is no longer used. + */ +@Deprecated +public abstract class C3 implements Serializable { + + /** + * The name for this class. + * + * @serial + */ + private String name; + + /** + * @serial + */ + private int publicKey; + + /** + * Constructor for serialization only. + */ + protected C3() { + + } + + /** + * Prints general information. + * + */ + public void printInfo() { + + } +} diff --git a/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java b/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java index 36cd089c32f..49aafe21ffc 100644 --- a/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java +++ b/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java @@ -46,7 +46,8 @@ public class TestSummaryHeading extends JavadocTester { //Input for string search tests. private static final String[][] TEST = { - {BUG_ID + FS + "C.html", "<STRONG>Method Summary</STRONG>"} + {BUG_ID + FS + "C.html", "<CAPTION CLASS=\"TableCaption\">" + NL + + "Method Summary</CAPTION>"} }; private static final String[][] NEGATED_TEST = NO_TEST; diff --git a/langtools/test/com/sun/javadoc/testThrowsTag/TestThrowsTag.java b/langtools/test/com/sun/javadoc/testThrowsTag/TestThrowsTag.java index bfae9a0e918..c8e99da5198 100644 --- a/langtools/test/com/sun/javadoc/testThrowsTag/TestThrowsTag.java +++ b/langtools/test/com/sun/javadoc/testThrowsTag/TestThrowsTag.java @@ -46,14 +46,14 @@ public class TestThrowsTag extends JavadocTester { //Input for string search tests. private static final String[][] TEST = { {BUG_ID + FS + "pkg" + FS + "C.html", - "<DD><CODE><A HREF=\"../pkg/T1.html\" title=\"class in pkg\">T1</A></CODE> - the first throws tag." + NL + - "<DD><CODE><A HREF=\"../pkg/T2.html\" title=\"class in pkg\">T2</A></CODE> - the second throws tag." + NL + - "<DD><CODE><A HREF=\"../pkg/T3.html\" title=\"class in pkg\">T3</A></CODE> - the third throws tag." + NL + - "<DD><CODE><A HREF=\"../pkg/T4.html\" title=\"class in pkg\">T4</A></CODE> - the fourth throws tag." + NL + - "<DD><CODE><A HREF=\"../pkg/T5.html\" title=\"class in pkg\">T5</A></CODE> - the first inherited throws tag." + NL + - "<DD><CODE><A HREF=\"../pkg/T6.html\" title=\"class in pkg\">T6</A></CODE> - the second inherited throws tag." + NL + - "<DD><CODE><A HREF=\"../pkg/T7.html\" title=\"class in pkg\">T7</A></CODE> - the third inherited throws tag." + NL + - "<DD><CODE><A HREF=\"../pkg/T8.html\" title=\"class in pkg\">T8</A></CODE> - the fourth inherited throws tag." + "<DD><CODE><A HREF=\"../pkg/T1.html\" title=\"class in pkg\">T1</A></CODE> - the first throws tag.</DD>" + NL + + "<DD><CODE><A HREF=\"../pkg/T2.html\" title=\"class in pkg\">T2</A></CODE> - the second throws tag.</DD>" + NL + + "<DD><CODE><A HREF=\"../pkg/T3.html\" title=\"class in pkg\">T3</A></CODE> - the third throws tag.</DD>" + NL + + "<DD><CODE><A HREF=\"../pkg/T4.html\" title=\"class in pkg\">T4</A></CODE> - the fourth throws tag.</DD>" + NL + + "<DD><CODE><A HREF=\"../pkg/T5.html\" title=\"class in pkg\">T5</A></CODE> - the first inherited throws tag.</DD>" + NL + + "<DD><CODE><A HREF=\"../pkg/T6.html\" title=\"class in pkg\">T6</A></CODE> - the second inherited throws tag.</DD>" + NL + + "<DD><CODE><A HREF=\"../pkg/T7.html\" title=\"class in pkg\">T7</A></CODE> - the third inherited throws tag.</DD>" + NL + + "<DD><CODE><A HREF=\"../pkg/T8.html\" title=\"class in pkg\">T8</A></CODE> - the fourth inherited throws tag.</DD>" }, }; private static final String[][] NEGATED_TEST = NO_TEST; diff --git a/langtools/test/tools/javac/6304921/T6304921.out b/langtools/test/tools/javac/6304921/T6304921.out index d69e1bd9aba..7a18b056006 100644 --- a/langtools/test/tools/javac/6304921/T6304921.out +++ b/langtools/test/tools/javac/6304921/T6304921.out @@ -1,18 +1,18 @@ T6304921.java:671/671/680: warning: [rawtypes] found raw type: java.util.ArrayList -missing type parameters for generic class java.util.ArrayList<E> List<Integer> list = new ArrayList(); ^ + missing type parameters for generic class java.util.ArrayList<E> T6304921.java:667/667/682: warning: [unchecked] unchecked conversion -found : java.util.ArrayList -required: java.util.List<java.lang.Integer> List<Integer> list = new ArrayList(); ^ + required: java.util.List<java.lang.Integer> + found: java.util.ArrayList error: warnings found and -Werror specified T6304921.java:727/733/737: cannot find symbol -symbol : variable orr -location: class java.lang.System System.orr.println("abc"); // name not found ^ + symbol: variable orr + location: class java.lang.System T6304921.java:812/816/822: operator + cannot be applied to int,boolean return 123 + true; // bad binary expression ^ diff --git a/langtools/test/tools/javac/6668794/badClass/Test.java b/langtools/test/tools/javac/6668794/badClass/Test.java index 40e514f89a5..d111c581ee8 100644 --- a/langtools/test/tools/javac/6668794/badClass/Test.java +++ b/langtools/test/tools/javac/6668794/badClass/Test.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,8 +54,8 @@ public class Test { throw new Error("no diagnostics generated"); String expected = "B.java:6:6: compiler.err.cant.access: p.A, " + - "(- compiler.misc.bad.class.file.header: A.class, " + - "(- compiler.misc.class.file.wrong.class: q.A))"; + "(compiler.misc.bad.class.file.header: A.class, " + + "(compiler.misc.class.file.wrong.class: q.A))"; if (!out[0].equals(expected)) { System.err.println("expected: " + expected); diff --git a/langtools/test/tools/javac/6668794/badSource/Test.out b/langtools/test/tools/javac/6668794/badSource/Test.out index e9fbdf99bda..94e1416d7a7 100644 --- a/langtools/test/tools/javac/6668794/badSource/Test.out +++ b/langtools/test/tools/javac/6668794/badSource/Test.out @@ -1 +1 @@ -Test.java:10:6: compiler.err.cant.access: p.A, (- compiler.misc.bad.source.file.header: A.java, (- compiler.misc.file.doesnt.contain.class: p.A)) +Test.java:10:6: compiler.err.cant.access: p.A, (compiler.misc.bad.source.file.header: A.java, (compiler.misc.file.doesnt.contain.class: p.A)) diff --git a/langtools/test/tools/javac/6758789/T6758789b.out b/langtools/test/tools/javac/6758789/T6758789b.out index eae65eb4422..af29552ca25 100644 --- a/langtools/test/tools/javac/6758789/T6758789b.out +++ b/langtools/test/tools/javac/6758789/T6758789b.out @@ -1,4 +1,4 @@ -T6758789b.java:39:11: compiler.warn.prob.found.req: (- compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo<X> +T6758789b.java:39:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo<X> T6758789b.java:39:10: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, T6758789a.Foo<X>, T6758789a.Foo, kindname.class, T6758789a - compiler.err.warnings.and.werror 1 error diff --git a/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java b/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java new file mode 100644 index 00000000000..6ede4dce723 --- /dev/null +++ b/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java @@ -0,0 +1,499 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6769027 + * @summary Source line should be displayed immediately after the first diagnostic line + * @author Maurizio Cimadamore + * @run main/othervm T6769027 + */ +import java.net.URI; +import java.util.regex.Matcher; +import javax.tools.*; +import com.sun.tools.javac.util.*; + +public class T6769027 { + + enum OutputKind { + RAW("rawDiagnostics","rawDiagnostics"), + BASIC("",""); + + String key; + String value; + + void init(Options opts) { + opts.put(key, value); + } + + OutputKind(String key, String value) { + this.key = key; + this.value = value; + } + } + + enum CaretKind { + DEFAULT("", ""), + SHOW("showCaret","true"), + HIDE("showCaret","false"); + + String key; + String value; + + void init(Options opts) { + opts.put(key, value); + } + + CaretKind(String key, String value) { + this.key = key; + this.value = value; + } + + boolean isEnabled() { + return this == DEFAULT || this == SHOW; + } + } + + enum SourceLineKind { + DEFAULT("", ""), + AFTER_SUMMARY("sourcePosition", "top"), + BOTTOM("sourcePosition", "bottom"); + + String key; + String value; + + void init(Options opts) { + opts.put(key, value); + } + + SourceLineKind(String key, String value) { + this.key = key; + this.value = value; + } + + boolean isAfterSummary() { + return this == DEFAULT || this == AFTER_SUMMARY; + } + } + + enum XDiagsSource { + DEFAULT(""), + SOURCE("source"), + NO_SOURCE("-source"); + + String flag; + + void init(Options opts) { + if (this != DEFAULT) { + String flags = opts.get("diags"); + flags = flags == null ? flag : flags + "," + flag; + opts.put("diags", flags); + } + } + + XDiagsSource(String flag) { + this.flag = flag; + } + + String getOutput(CaretKind caretKind, IndentKind indent, OutputKind outKind) { + String spaces = (outKind == OutputKind.BASIC) ? indent.string : ""; + return "\n" + spaces + "This is a source line" + + (caretKind.isEnabled() ? "\n" + spaces + " ^" : ""); + } + } + + enum XDiagsCompact { + DEFAULT(""), + COMPACT("short"), + NO_COMPACT("-short"); + + String flag; + + void init(Options opts) { + if (this != DEFAULT) { + String flags = opts.get("diags"); + flags = flags == null ? flag : flags + "," + flag; + opts.put("diags", flags); + } + } + + XDiagsCompact(String flag) { + this.flag = flag; + } + } + + enum ErrorKind { + SINGLE("single", + "compiler.err.single: Hello!", + "KXThis is a test error message Hello!"), + DOUBLE("double", + "compiler.err.double: Hello!", + "KXThis is a test error message.\n" + + "KXYThis is another line of the above error message Hello!"); + + String key; + String rawOutput; + String nonRawOutput; + + String key() { + return key; + } + + ErrorKind(String key, String rawOutput, String nonRawOutput) { + this.key = key; + this.rawOutput = rawOutput; + this.nonRawOutput = nonRawOutput; + } + + String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent) { + return outKind == OutputKind.RAW ? + rawOutput : + nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", ""); + } + + String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent, String indent) { + return outKind == OutputKind.RAW ? + rawOutput : + nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", indent); + } + } + + enum MultilineKind { + NONE(0), + DOUBLE(1), + NESTED(2), + DOUBLE_NESTED(3); + + static String[][] rawTemplates = { + {"", ",{(E),(E)}", ",{(E,{(E)})}", ",{(E,{(E)}),(E,{(E)})}"}, //ENABLED + {"", "", "", "",""}, //DISABLED + {"", ",{(E)}", ",{(E,{(E)})}", ",{(E,{(E)})}"}, //LIMIT_LENGTH + {"", ",{(E),(E)}", ",{(E)}", ",{(E),(E)}"}, //LIMIT_DEPTH + {"", ",{(E)}", ",{(E)}", ",{(E)}"}}; //LIMIT_BOTH + + static String[][] basicTemplates = { + {"", "\nE\nE", "\nE\nQ", "\nE\nQ\nE\nQ"}, //ENABLED + {"", "", "", "",""}, //DISABLED + {"", "\nE", "\nE\nQ", "\nE\nQ"}, //LIMIT_LENGTH + {"", "\nE\nE", "\nE", "\nE\nE"}, //LIMIT_DEPTH + {"", "\nE", "\nE", "\nE"}}; //LIMIT_BOTH + + + int index; + + MultilineKind (int index) { + this.index = index; + } + + boolean isDouble() { + return this == DOUBLE || this == DOUBLE_NESTED; + } + + boolean isNested() { + return this == NESTED || this == DOUBLE_NESTED; + } + + String getOutput(OutputKind outKind, ErrorKind errKind, MultilinePolicy policy, + IndentKind summaryIndent, IndentKind detailsIndent, IndentKind multiIndent) { + String constIndent = (errKind == ErrorKind.DOUBLE) ? + summaryIndent.string + detailsIndent.string : + summaryIndent.string; + constIndent += multiIndent.string; + + String errMsg1 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent); + String errMsg2 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent + constIndent); + + errMsg1 = errMsg1.replaceAll("compiler.err", "compiler.misc"); + errMsg1 = errMsg1.replaceAll("error message", "subdiagnostic"); + errMsg2 = errMsg2.replaceAll("compiler.err", "compiler.misc"); + errMsg2 = errMsg2.replaceAll("error message", "subdiagnostic"); + + String template = outKind == OutputKind.RAW ? + rawTemplates[policy.index][index] : + basicTemplates[policy.index][index]; + + template = template.replaceAll("E", errMsg1); + return template.replaceAll("Q", errMsg2); + } + } + + enum MultilinePolicy { + ENABLED(0, "multilinePolicy", "enabled"), + DISABLED(1, "multilinePolicy", "disabled"), + LIMIT_LENGTH(2, "multilinePolicy", "limit:1:*"), + LIMIT_DEPTH(3, "multilinePolicy", "limit:*:1"), + LIMIT_BOTH(4, "multilinePolicy", "limit:1:1"); + + String name; + String value; + int index; + + MultilinePolicy(int index, String name, String value) { + this.name = name; + this.value = value; + this.index = index; + } + + void init(Options options) { + options.put(name, value); + } + } + + enum PositionKind { + NOPOS(Position.NOPOS, "- ", "error: "), + POS(5, "/Test.java:1:6: ", "myfo:/Test.java:1: "); + + int pos; + String rawOutput; + String nonRawOutput; + + PositionKind(int pos, String rawOutput, String nonRawOutput) { + this.pos = pos; + this.rawOutput = rawOutput; + this.nonRawOutput = nonRawOutput; + } + + JCDiagnostic.DiagnosticPosition pos() { + return new JCDiagnostic.SimpleDiagnosticPosition(pos); + } + + String getOutput(OutputKind outputKind) { + return outputKind == OutputKind.RAW ? + rawOutput : + nonRawOutput; + } + } + + static class MyFileObject extends SimpleJavaFileObject { + private String text; + public MyFileObject(String text) { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + this.text = text; + } + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return text; + } + } + + enum IndentKind { + NONE(""), + CUSTOM(" "); + + String string; + + IndentKind(String indent) { + string = indent; + } + } + + class MyLog extends Log { + MyLog(Context ctx) { + super(ctx); + } + + @Override + protected java.io.PrintWriter getWriterForDiagnosticType(JCDiagnostic.DiagnosticType dt) { + return new java.io.PrintWriter(System.out); + } + + @Override + protected boolean shouldReport(JavaFileObject jfo, int pos) { + return true; + } + } + + int nerrors = 0; + + void exec(OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind, + MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource, + XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind, + IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent, + IndentKind subdiagsIndent) { + Context ctx = new Context(); + Options options = Options.instance(ctx); + outputKind.init(options); + multiPolicy.init(options); + xdiagsSource.init(options); + xdiagsCompact.init(options); + caretKind.init(options); + sourceLineKind.init(options); + String indentString = ""; + indentString = (summaryIndent == IndentKind.CUSTOM) ? "3" : "0"; + indentString += (detailsIndent == IndentKind.CUSTOM) ? "|3" : "|0"; + indentString += (sourceIndent == IndentKind.CUSTOM) ? "|3" : "|0"; + indentString += (subdiagsIndent == IndentKind.CUSTOM) ? "|3" : "|0"; + options.put("diagsIndentation", indentString); + MyLog log = new MyLog(ctx); + JavacMessages messages = JavacMessages.instance(ctx); + messages.add("tester"); + JCDiagnostic.Factory diags = JCDiagnostic.Factory.instance(ctx); + log.useSource(new MyFileObject("This is a source line")); + JCDiagnostic d = diags.error(log.currentSource(), + posKind.pos(), + errorKind.key(), "Hello!"); + if (multiKind != MultilineKind.NONE) { + JCDiagnostic sub = diags.fragment(errorKind.key(), "Hello!"); + if (multiKind.isNested()) + sub = new JCDiagnostic.MultilineDiagnostic(sub, List.of(sub)); + List<JCDiagnostic> subdiags = multiKind.isDouble() ? + List.of(sub, sub) : + List.of(sub); + d = new JCDiagnostic.MultilineDiagnostic(d, subdiags); + } + String diag = log.getDiagnosticFormatter().format(d, messages.getCurrentLocale()); + checkOutput(diag, + outputKind, + errorKind, + multiKind, + multiPolicy, + posKind, + xdiagsSource, + xdiagsCompact, + caretKind, + sourceLineKind, + summaryIndent, + detailsIndent, + sourceIndent, + subdiagsIndent); + } + + void test() { + for (OutputKind outputKind : OutputKind.values()) { + for (ErrorKind errKind : ErrorKind.values()) { + for (MultilineKind multiKind : MultilineKind.values()) { + for (MultilinePolicy multiPolicy : MultilinePolicy.values()) { + for (PositionKind posKind : PositionKind.values()) { + for (XDiagsSource xdiagsSource : XDiagsSource.values()) { + for (XDiagsCompact xdiagsCompact : XDiagsCompact.values()) { + for (CaretKind caretKind : CaretKind.values()) { + for (SourceLineKind sourceLineKind : SourceLineKind.values()) { + for (IndentKind summaryIndent : IndentKind.values()) { + for (IndentKind detailsIndent : IndentKind.values()) { + for (IndentKind sourceIndent : IndentKind.values()) { + for (IndentKind subdiagsIndent : IndentKind.values()) { + exec(outputKind, + errKind, + multiKind, + multiPolicy, + posKind, + xdiagsSource, + xdiagsCompact, + caretKind, + sourceLineKind, + summaryIndent, + detailsIndent, + sourceIndent, + subdiagsIndent); + } + } + } + } + } + } + } + } + } + } + } + } + } + if (nerrors != 0) + throw new AssertionError(nerrors + " errors found"); + } + + void printInfo(String msg, OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind, + MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource, + XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind, + IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent, + IndentKind subdiagsIndent, String errorLine) { + String sep = "*********************************************************"; + String desc = "raw=" + outputKind + " pos=" + posKind + " key=" + errorKind.key() + + " multiline=" + multiKind +" multiPolicy=" + multiPolicy.value + + " diags= " + java.util.Arrays.asList(xdiagsSource.flag, xdiagsCompact.flag) + + " caret=" + caretKind + " sourcePosition=" + sourceLineKind + + " summaryIndent=" + summaryIndent + " detailsIndent=" + detailsIndent + + " sourceIndent=" + sourceIndent + " subdiagsIndent=" + subdiagsIndent; + System.out.println(sep); + System.out.println(desc); + System.out.println(sep); + System.out.println(msg); + System.out.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine); + } + + void checkOutput(String msg, OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind, + MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource, + XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind, + IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent, + IndentKind subdiagsIndent) { + boolean shouldPrintSource = posKind == PositionKind.POS && + xdiagsSource != XDiagsSource.NO_SOURCE && + (xdiagsSource == XDiagsSource.SOURCE || + outputKind == OutputKind.BASIC); + String errorLine = posKind.getOutput(outputKind) + + errorKind.getOutput(outputKind, summaryIndent, detailsIndent); + if (xdiagsCompact != XDiagsCompact.COMPACT) + errorLine += multiKind.getOutput(outputKind, errorKind, multiPolicy, summaryIndent, detailsIndent, subdiagsIndent); + String[] lines = errorLine.split("\n"); + if (xdiagsCompact == XDiagsCompact.COMPACT) { + errorLine = lines[0]; + lines = new String[] {errorLine}; + } + if (shouldPrintSource) { + if (sourceLineKind.isAfterSummary()) { + String sep = "\n"; + if (lines.length == 1) { + errorLine += "\n"; + sep = ""; + } + errorLine = errorLine.replaceFirst("\n", + Matcher.quoteReplacement(xdiagsSource.getOutput(caretKind, sourceIndent, outputKind) + sep)); + } + else + errorLine += xdiagsSource.getOutput(caretKind, sourceIndent, outputKind); + } + + if (!msg.equals(errorLine)) { + printInfo(msg, + outputKind, + errorKind, + multiKind, + multiPolicy, + posKind, + xdiagsSource, + xdiagsCompact, + caretKind, + sourceLineKind, + summaryIndent, + detailsIndent, + sourceIndent, + subdiagsIndent, + errorLine); + nerrors++; + } + } + + public static void main(String... args) throws Exception { + new T6769027().test(); + } +} diff --git a/langtools/test/tools/javac/Diagnostics/6769027/tester.properties b/langtools/test/tools/javac/Diagnostics/6769027/tester.properties new file mode 100644 index 00000000000..666a52eb198 --- /dev/null +++ b/langtools/test/tools/javac/Diagnostics/6769027/tester.properties @@ -0,0 +1,13 @@ +compiler.err.single=\ + This is a test error message {0} + +compiler.err.double=\ + This is a test error message.\n\ + This is another line of the above error message {0} + +compiler.misc.single=\ + This is a test subdiagnostic {0} + +compiler.misc.double=\ + This is a test subdiagnostic.\n\ + This is another line of the above subdiagnostic {0} diff --git a/langtools/test/tools/javac/Diagnostics/6799605/T6799605.java b/langtools/test/tools/javac/Diagnostics/6799605/T6799605.java new file mode 100644 index 00000000000..bcd7e842865 --- /dev/null +++ b/langtools/test/tools/javac/Diagnostics/6799605/T6799605.java @@ -0,0 +1,43 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6799605 + * @summary Basic/Raw formatters should use type/symbol printer instead of toString() + * @author mcimadamore + * @compile/fail/ref=T6799605.out -XDrawDiagnostics T6799605.java + */ + +class T6799605<X> { + + <T extends T6799605<T>> void m(T6799605<T> x1) {} + <T> void m(T6799605<T> x1, T6799605<T> x2) {} + <T> void m(T6799605<T> x1, T6799605<T> x2, T6799605<T> x3) {} + + void test(T6799605<?> t) { + m(t); + m(t, t); + m(t, t, t); + } +} diff --git a/langtools/test/tools/javac/Diagnostics/6799605/T6799605.out b/langtools/test/tools/javac/Diagnostics/6799605/T6799605.out new file mode 100644 index 00000000000..9179e6a8d97 --- /dev/null +++ b/langtools/test/tools/javac/Diagnostics/6799605/T6799605.out @@ -0,0 +1,4 @@ +T6799605.java:39:9: compiler.err.cant.resolve.location.args: kindname.method, m, , T6799605<compiler.misc.type.captureof: 1, ?>, kindname.class, T6799605<X> +T6799605.java:40:9: compiler.err.cant.resolve.location.args: kindname.method, m, , T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>, kindname.class, T6799605<X> +T6799605.java:41:9: compiler.err.cant.resolve.location.args: kindname.method, m, , T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>,T6799605<compiler.misc.type.captureof: 3, ?>, kindname.class, T6799605<X> +3 errors diff --git a/langtools/test/tools/javac/ExtendArray.out b/langtools/test/tools/javac/ExtendArray.out index 86878431daa..ad5d8877c71 100644 --- a/langtools/test/tools/javac/ExtendArray.out +++ b/langtools/test/tools/javac/ExtendArray.out @@ -1,6 +1,6 @@ ExtendArray.java:11: unexpected type -found : java.lang.Object[] -required: class public class ExtendArray extends Object[] {} ^ + required: class + found: java.lang.Object[] 1 error diff --git a/langtools/test/tools/javac/NestedInnerClassNames.out b/langtools/test/tools/javac/NestedInnerClassNames.out index bee489e56ce..b4f171b834c 100644 --- a/langtools/test/tools/javac/NestedInnerClassNames.out +++ b/langtools/test/tools/javac/NestedInnerClassNames.out @@ -1,15 +1,15 @@ -NestedInnerClassNames.java:16:5: compiler.err.already.defined: NestedInnerClassNames, unnamed package +NestedInnerClassNames.java:16:5: compiler.err.already.defined: NestedInnerClassNames, compiler.misc.unnamed.package NestedInnerClassNames.java:23:9: compiler.err.already.defined: NestedInnerClassNames.foo, NestedInnerClassNames -NestedInnerClassNames.java:34:9: compiler.err.already.defined: NestedInnerClassNames, unnamed package +NestedInnerClassNames.java:34:9: compiler.err.already.defined: NestedInnerClassNames, compiler.misc.unnamed.package NestedInnerClassNames.java:45:9: compiler.err.already.defined: NestedInnerClassNames.baz, NestedInnerClassNames NestedInnerClassNames.java:46:13: compiler.err.already.defined: NestedInnerClassNames.baz.baz, NestedInnerClassNames.baz NestedInnerClassNames.java:59:9: compiler.err.already.defined: NestedInnerClassNames.foo$bar, NestedInnerClassNames NestedInnerClassNames.java:76:13: compiler.err.already.defined: NestedInnerClassNames.$bar, NestedInnerClassNames NestedInnerClassNames.java:90:13: compiler.err.already.defined: NestedInnerClassNames.bar$bar.bar, NestedInnerClassNames.bar$bar NestedInnerClassNames.java:109:5: compiler.err.duplicate.class: NestedInnerClassNames.foo.foo -NestedInnerClassNames.java:19:9: compiler.err.already.defined: NestedInnerClassNames, unnamed package +NestedInnerClassNames.java:19:9: compiler.err.already.defined: NestedInnerClassNames, compiler.misc.unnamed.package NestedInnerClassNames.java:28:13: compiler.err.already.defined: foo, m2() -NestedInnerClassNames.java:40:13: compiler.err.already.defined: NestedInnerClassNames, unnamed package +NestedInnerClassNames.java:40:13: compiler.err.already.defined: NestedInnerClassNames, compiler.misc.unnamed.package NestedInnerClassNames.java:52:13: compiler.err.already.defined: baz, m4() NestedInnerClassNames.java:53:17: compiler.err.already.defined: baz.baz, baz NestedInnerClassNames.java:67:13: compiler.err.already.defined: foo$bar, m5() diff --git a/langtools/test/tools/javac/OverrideChecks/6400189/T6400189a.java b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189a.java new file mode 100644 index 00000000000..a1808b81f94 --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189a.java @@ -0,0 +1,38 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6400189 + * @summary raw types and inference + * @author mcimadamore + * @compile/fail/ref=T6400189a.out T6400189a.java -Xlint:unchecked -XDrawDiagnostics + */ + +import java.lang.reflect.Constructor; +import java.lang.annotation.Documented; + +class T6400189a { + Constructor c = null; + Documented d = c.getAnnotation(Documented.class); +} diff --git a/langtools/test/tools/javac/OverrideChecks/6400189/T6400189a.out b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189a.out new file mode 100644 index 00000000000..39938023fa3 --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189a.out @@ -0,0 +1,4 @@ +T6400189a.java:37:35: compiler.warn.unchecked.call.mbr.of.raw.type: <T>getAnnotation(java.lang.Class<T>), java.lang.reflect.Constructor +T6400189a.java:37:35: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.annotation.Annotation, java.lang.annotation.Documented +1 error +1 warning diff --git a/langtools/test/tools/javac/OverrideChecks/6400189/T6400189b.java b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189b.java new file mode 100644 index 00000000000..c7a6993d565 --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189b.java @@ -0,0 +1,49 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6400189 + * @summary raw types and inference + * @author mcimadamore + * @compile/fail/ref=T6400189b.out T6400189b.java -Xlint:unchecked -XDrawDiagnostics + */ + +class T6400189b<T> { + + static class A { + <T> T m(T6400189b<T> x) { + return null; + } + } + + static class B<T> extends A { + <T> T m(T6400189b<T> x) { + return null; + } + } + + void test(B b) { + Integer i = b.m(new T6400189b<Integer>()); + } +} diff --git a/langtools/test/tools/javac/OverrideChecks/6400189/T6400189b.out b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189b.out new file mode 100644 index 00000000000..8d7711a117e --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189b.out @@ -0,0 +1,4 @@ +T6400189b.java:47:24: compiler.warn.unchecked.call.mbr.of.raw.type: <T>m(T6400189b<T>), T6400189b.B +T6400189b.java:47:24: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Object, java.lang.Integer +1 error +1 warning diff --git a/langtools/test/tools/javac/OverrideChecks/6400189/T6400189c.java b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189c.java new file mode 100644 index 00000000000..5d95c10c490 --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189c.java @@ -0,0 +1,45 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6400189 + * @summary raw types and inference + * @author mcimadamore + * @compile T6400189c.java + */ + +class T6400189c<T> { + + static class A { + <T> T m(T6400189c<T> x) { + return null; + } + } + + static class B<T> extends A {} + + void test(B b) { + Integer i = b.m(new T6400189c<Integer>()); + } +} diff --git a/langtools/test/tools/javac/OverrideChecks/6400189/T6400189d.java b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189d.java new file mode 100644 index 00000000000..12ab97f693b --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189d.java @@ -0,0 +1,53 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6400189 + * @summary raw types and inference + * @author mcimadamore + * @compile T6400189d.java + */ + +import java.util.Iterator; + +class T6400189c<T> { + + interface A<X> extends Iterable<X> { + Iterator<X> iterator(); + } + + interface A2<Y> extends A<Y> { + Iterator<Y> iterator(); + } + + static abstract class B<Z> implements A<Z> { + public abstract Iterator<Z> iterator(); + } + + static abstract class C<W> extends B<W> implements A2<W> { + Iterator<W> test() { + return iterator(); + } + } +} diff --git a/langtools/test/tools/javac/T5048776b.out b/langtools/test/tools/javac/T5048776b.out index 5eb9b79ef59..ab9688edb01 100644 --- a/langtools/test/tools/javac/T5048776b.out +++ b/langtools/test/tools/javac/T5048776b.out @@ -1,3 +1,3 @@ -T5048776.java:12:10: compiler.warn.override.varargs.missing: (- compiler.misc.varargs.override: foo(java.lang.Object...), A1a, foo(java.lang.Object[]), A1) -T5048776.java:20:10: compiler.warn.override.varargs.extra: (- compiler.misc.varargs.override: foo(java.lang.Object[]), A2a, foo(java.lang.Object...), A2) +T5048776.java:12:10: compiler.warn.override.varargs.missing: (compiler.misc.varargs.override: foo(java.lang.Object...), A1a, foo(java.lang.Object[]), A1) +T5048776.java:20:10: compiler.warn.override.varargs.extra: (compiler.misc.varargs.override: foo(java.lang.Object[]), A2a, foo(java.lang.Object...), A2) 2 warnings diff --git a/langtools/test/tools/javac/T6214885a.out b/langtools/test/tools/javac/T6214885a.out index f09fff67b0e..8ca1aaced2d 100644 --- a/langtools/test/tools/javac/T6214885a.out +++ b/langtools/test/tools/javac/T6214885a.out @@ -1,6 +1,6 @@ T6214885.java:11 cannot find symbol -symbol : variable x -location: class T6214885 x = 1; ^ + symbol: variable x + location: class T6214885 1 error diff --git a/langtools/test/tools/javac/T6214885b.out b/langtools/test/tools/javac/T6214885b.out index 1ee86363a12..4dc30190da0 100644 --- a/langtools/test/tools/javac/T6214885b.out +++ b/langtools/test/tools/javac/T6214885b.out @@ -1,6 +1,6 @@ T6214885.java:11:9 cannot find symbol -symbol : variable x -location: class T6214885 x = 1; ^ + symbol: variable x + location: class T6214885 1 error diff --git a/langtools/test/tools/javac/T6230128.out b/langtools/test/tools/javac/T6230128.out index d6a08595385..32863533ef1 100644 --- a/langtools/test/tools/javac/T6230128.out +++ b/langtools/test/tools/javac/T6230128.out @@ -1,2 +1,2 @@ -T6230128.java:11:10: compiler.err.override.weaker.access: (- compiler.misc.cant.override: foo(java.lang.Object...), A1a, foo(java.lang.Object[]), A1), public +T6230128.java:11:10: compiler.err.override.weaker.access: (compiler.misc.cant.override: foo(java.lang.Object...), A1a, foo(java.lang.Object[]), A1), public 1 error diff --git a/langtools/test/tools/javac/T6241723.out b/langtools/test/tools/javac/T6241723.out index 2391e4394b8..086a0d18717 100644 --- a/langtools/test/tools/javac/T6241723.out +++ b/langtools/test/tools/javac/T6241723.out @@ -1,6 +1,6 @@ -T6241723.java:21:5: compiler.warn.has.been.deprecated: A1, unnamed package +T6241723.java:21:5: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package T6241723.java:23:7: compiler.warn.has.been.deprecated: A2.A21, A2 -T6241723.java:26:5: compiler.warn.has.been.deprecated: Z1, unnamed package +T6241723.java:26:5: compiler.warn.has.been.deprecated: Z1, compiler.misc.unnamed.package T6241723.java:28:7: compiler.warn.has.been.deprecated: Z2.Z21, Z2 - compiler.err.warnings.and.werror 1 error diff --git a/langtools/test/tools/javac/annotations/6365854/test1.out b/langtools/test/tools/javac/annotations/6365854/test1.out index ed81b94111b..00eaf216db2 100644 --- a/langtools/test/tools/javac/annotations/6365854/test1.out +++ b/langtools/test/tools/javac/annotations/6365854/test1.out @@ -1,2 +1,2 @@ -- compiler.warn.annotation.method.not.found.reason: test.annotation.TestAnnotation, test, (- compiler.misc.class.file.not.found: test.annotation.TestAnnotation) +- compiler.warn.annotation.method.not.found.reason: test.annotation.TestAnnotation, test, (compiler.misc.class.file.not.found: test.annotation.TestAnnotation) 1 warning diff --git a/langtools/test/tools/javac/boxing/T6816548.java b/langtools/test/tools/javac/boxing/T6816548.java new file mode 100644 index 00000000000..2629fa7fe41 --- /dev/null +++ b/langtools/test/tools/javac/boxing/T6816548.java @@ -0,0 +1,66 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6816548 + * @summary Uninitialized register when performing casting + auto(un)boxing + * @author mcimadamore + */ +public class T6816548 { + + public static void main(String[] args) { + testInt(); + testShort(); + testByte(); + testChar(); + } + + public static void testInt() { + final int fi = 0; + Byte b = fi; + Short s = fi; + Character c = fi; + } + + public static void testShort() { + final short fs = 0; + Byte b = fs; + Short s = fs; + Character c = fs; + } + + public static void testByte() { + final byte fb = 0; + Byte b = fb; + Short s = fb; + Character c = fb; + } + + public static void testChar() { + final char fc = '0'; + Byte b = fc; + Short s = fc; + Character c = fc; + } +} diff --git a/langtools/test/tools/javac/cast/6467183/T6467183a.java b/langtools/test/tools/javac/cast/6467183/T6467183a.java new file mode 100644 index 00000000000..04bc4634ce5 --- /dev/null +++ b/langtools/test/tools/javac/cast/6467183/T6467183a.java @@ -0,0 +1,53 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @author mcimadamore + * @bug 6467183 + * @summary + * @compile/fail/ref=T6467183a.out -Xlint:unchecked -Werror -XDrawDiagnostics T6467183a.java + */ + +class T6467183a<T> { + + class A<S> {} + class B extends A<Integer> {} + class C<X> extends A<X> {} + + void cast1(B b) { + Object o = (A<T>)b; + } + + void cast2(B b) { + Object o = (A<? extends Number>)b; + } + + void cast3(A<Integer> a) { + Object o = (C<? extends Number>)a; + } + + void cast4(A<Integer> a) { + Object o = (C<? extends Integer>)a; + } +} diff --git a/langtools/test/tools/javac/cast/6467183/T6467183a.out b/langtools/test/tools/javac/cast/6467183/T6467183a.out new file mode 100644 index 00000000000..5df842cc72a --- /dev/null +++ b/langtools/test/tools/javac/cast/6467183/T6467183a.out @@ -0,0 +1,6 @@ +T6467183a.java:39:26: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), T6467183a<T>.B, T6467183a<T>.A<T> +T6467183a.java:47:41: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), T6467183a<T>.A<java.lang.Integer>, T6467183a<T>.C<? extends java.lang.Number> +T6467183a.java:51:42: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), T6467183a<T>.A<java.lang.Integer>, T6467183a<T>.C<? extends java.lang.Integer> +- compiler.err.warnings.and.werror +1 error +3 warnings diff --git a/langtools/test/tools/javac/cast/6467183/T6467183b.java b/langtools/test/tools/javac/cast/6467183/T6467183b.java new file mode 100644 index 00000000000..4a90fb2643e --- /dev/null +++ b/langtools/test/tools/javac/cast/6467183/T6467183b.java @@ -0,0 +1,40 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @author mcimadamore + * @bug 6467183 + * @summary + * @compile/fail -Xlint:unchecked -Werror -XDrawDiagnostics T6467183b.java + */ + +class T6665356b<T> { + + class A<S> {} + class B<X> extends A<X> {} + + void cast(A<? extends Number> a) { + Object o = (B<? extends Integer>)a; + } +} diff --git a/langtools/test/tools/javac/cast/6557182/T6557182.out b/langtools/test/tools/javac/cast/6557182/T6557182.out index 9ebe10e9c9f..5f25497ace2 100644 --- a/langtools/test/tools/javac/cast/6557182/T6557182.out +++ b/langtools/test/tools/javac/cast/6557182/T6557182.out @@ -1,4 +1,4 @@ -T6557182.java:35:56: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T, java.lang.Comparable<java.lang.Integer> -T6557182.java:39:56: compiler.warn.prob.found.req: (- compiler.misc.unchecked.cast.to.type), T, java.lang.Comparable<java.lang.Integer> +T6557182.java:35:56: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T, java.lang.Comparable<java.lang.Integer> +T6557182.java:39:56: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), T, java.lang.Comparable<java.lang.Integer> 1 error 1 warning diff --git a/langtools/test/tools/javac/cast/6558559/T6558559a.java b/langtools/test/tools/javac/cast/6558559/T6558559a.java index c440e422f8e..f02664d4e11 100644 --- a/langtools/test/tools/javac/cast/6558559/T6558559a.java +++ b/langtools/test/tools/javac/cast/6558559/T6558559a.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javac/cast/6558559/T6558559b.java b/langtools/test/tools/javac/cast/6558559/T6558559b.java index 9fe99339228..23cfdae9cc9 100644 --- a/langtools/test/tools/javac/cast/6558559/T6558559b.java +++ b/langtools/test/tools/javac/cast/6558559/T6558559b.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javac/cast/6665356/T6665356.java b/langtools/test/tools/javac/cast/6665356/T6665356.java index f9db58fa760..92b93d2c5bf 100644 --- a/langtools/test/tools/javac/cast/6665356/T6665356.java +++ b/langtools/test/tools/javac/cast/6665356/T6665356.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javac/cast/6665356/T6665356.out b/langtools/test/tools/javac/cast/6665356/T6665356.out index 029c66400a2..1db10c64ca4 100644 --- a/langtools/test/tools/javac/cast/6665356/T6665356.out +++ b/langtools/test/tools/javac/cast/6665356/T6665356.out @@ -1,8 +1,8 @@ -T6665356.java:54:55: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.Number>.Inner<java.lang.Long> -T6665356.java:58:58: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? super java.lang.Number> -T6665356.java:62:65: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.Number>.Inner<? super java.lang.Number> -T6665356.java:66:57: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? extends java.lang.String>.Inner<java.lang.Long> -T6665356.java:70:60: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? extends java.lang.String> -T6665356.java:74:55: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.String>.Inner<java.lang.Long> -T6665356.java:78:58: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? super java.lang.String> +T6665356.java:54:55: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.Number>.Inner<java.lang.Long> +T6665356.java:58:58: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? super java.lang.Number> +T6665356.java:62:65: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.Number>.Inner<? super java.lang.Number> +T6665356.java:66:57: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? extends java.lang.String>.Inner<java.lang.Long> +T6665356.java:70:60: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? extends java.lang.String> +T6665356.java:74:55: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.String>.Inner<java.lang.Long> +T6665356.java:78:58: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? super java.lang.String> 7 errors \ No newline at end of file diff --git a/langtools/test/tools/javac/cast/6795580/T6795580.out b/langtools/test/tools/javac/cast/6795580/T6795580.out index f754e1dc2c5..a5d70401650 100644 --- a/langtools/test/tools/javac/cast/6795580/T6795580.out +++ b/langtools/test/tools/javac/cast/6795580/T6795580.out @@ -1,8 +1,8 @@ -T6795580.java:54:57: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.Number>.Inner<java.lang.Long>[] -T6795580.java:58:60: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? super java.lang.Number>[] -T6795580.java:62:67: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.Number>.Inner<? super java.lang.Number>[] -T6795580.java:66:59: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? extends java.lang.String>.Inner<java.lang.Long>[] -T6795580.java:70:62: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? extends java.lang.String>[] -T6795580.java:74:57: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.String>.Inner<java.lang.Long>[] -T6795580.java:78:60: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? super java.lang.String>[] +T6795580.java:54:57: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.Number>.Inner<java.lang.Long>[] +T6795580.java:58:60: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? super java.lang.Number>[] +T6795580.java:62:67: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.Number>.Inner<? super java.lang.Number>[] +T6795580.java:66:59: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? extends java.lang.String>.Inner<java.lang.Long>[] +T6795580.java:70:62: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? extends java.lang.String>[] +T6795580.java:74:57: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.String>.Inner<java.lang.Long>[] +T6795580.java:78:60: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? super java.lang.String>[] 7 errors diff --git a/langtools/test/tools/javac/depDocComment/SuppressDeprecation.out b/langtools/test/tools/javac/depDocComment/SuppressDeprecation.out index af1f47062ca..eb0c0ff686b 100644 --- a/langtools/test/tools/javac/depDocComment/SuppressDeprecation.out +++ b/langtools/test/tools/javac/depDocComment/SuppressDeprecation.out @@ -1,4 +1,4 @@ -SuppressDeprecation.java:130:17: compiler.warn.has.been.deprecated: X, unnamed package +SuppressDeprecation.java:130:17: compiler.warn.has.been.deprecated: X, compiler.misc.unnamed.package SuppressDeprecation.java:82:10: compiler.warn.has.been.deprecated: g(), T SuppressDeprecation.java:83:14: compiler.warn.has.been.deprecated: g(), T SuppressDeprecation.java:84:9: compiler.warn.has.been.deprecated: var, T diff --git a/langtools/test/tools/javac/generics/6182950/T6182950a.java b/langtools/test/tools/javac/generics/6182950/T6182950a.java new file mode 100644 index 00000000000..82fb49ec734 --- /dev/null +++ b/langtools/test/tools/javac/generics/6182950/T6182950a.java @@ -0,0 +1,36 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6182950 + * @summary methods clash algorithm should not depend on return type + * @author mcimadamore + * @compile/fail/ref=T6182950a.out -XDrawDiagnostics T6182950a.java + */ +import java.util.List; + +class T6182950a { + int m(List<String> l) {return 0;} + double m(List<Integer> l) {return 0;} +} diff --git a/langtools/test/tools/javac/generics/6182950/T6182950a.out b/langtools/test/tools/javac/generics/6182950/T6182950a.out new file mode 100644 index 00000000000..6c0f5cb2916 --- /dev/null +++ b/langtools/test/tools/javac/generics/6182950/T6182950a.out @@ -0,0 +1,2 @@ +T6182950a.java:35:12: compiler.err.name.clash.same.erasure: m(java.util.List<java.lang.Integer>), m(java.util.List<java.lang.String>) +1 error diff --git a/langtools/test/tools/javac/generics/6182950/T6182950b.java b/langtools/test/tools/javac/generics/6182950/T6182950b.java new file mode 100644 index 00000000000..b3120dcc03f --- /dev/null +++ b/langtools/test/tools/javac/generics/6182950/T6182950b.java @@ -0,0 +1,40 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6182950 + * @summary methods clash algorithm should not depend on return type + * @author mcimadamore + * @compile/fail/ref=T6182950b.out -XDrawDiagnostics T6182950b.java + */ +import java.util.List; + +class T6182950b { + static class A { + int m(List<String> l) {return 0;} + } + static class B extends A { + double m(List<Integer> l) {return 0;} + } +} diff --git a/langtools/test/tools/javac/generics/6182950/T6182950b.out b/langtools/test/tools/javac/generics/6182950/T6182950b.out new file mode 100644 index 00000000000..d9dcb48f1fa --- /dev/null +++ b/langtools/test/tools/javac/generics/6182950/T6182950b.out @@ -0,0 +1,2 @@ +T6182950b.java:38:16: compiler.err.name.clash.same.erasure.no.override: m(java.util.List<java.lang.Integer>), T6182950b.B, m(java.util.List<java.lang.String>), T6182950b.A +1 error diff --git a/langtools/test/tools/javac/generics/6182950/T6182950c.java b/langtools/test/tools/javac/generics/6182950/T6182950c.java new file mode 100644 index 00000000000..db8da8f6ff5 --- /dev/null +++ b/langtools/test/tools/javac/generics/6182950/T6182950c.java @@ -0,0 +1,44 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6182950 + * @summary methods clash algorithm should not depend on return type + * @author mcimadamore + * @compile T6182950c.java + */ + +class T6182950c { + static abstract class A<X> { + abstract Object m(X x); + } + + static abstract class B<X> extends A<X> { + Number m(X x) {return 0;} + } + + final static class C<X> extends B<X> { + Integer m(X x) {return 0;} + } +} diff --git a/langtools/test/tools/javac/generics/6207386/T6207386.out b/langtools/test/tools/javac/generics/6207386/T6207386.out index bd98d3123c8..768c5c2d341 100644 --- a/langtools/test/tools/javac/generics/6207386/T6207386.out +++ b/langtools/test/tools/javac/generics/6207386/T6207386.out @@ -1,2 +1,2 @@ -T6207386.java:13:30: compiler.err.prob.found.req: (- compiler.misc.incompatible.types), X, T6207386.F<? super X> +T6207386.java:13:30: compiler.err.prob.found.req: (compiler.misc.incompatible.types), X, T6207386.F<? super X> 1 error diff --git a/langtools/test/tools/javac/generics/6723444/T6723444.java b/langtools/test/tools/javac/generics/6723444/T6723444.java index 4d32ba89c4e..1edc6e593a4 100644 --- a/langtools/test/tools/javac/generics/6723444/T6723444.java +++ b/langtools/test/tools/javac/generics/6723444/T6723444.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javac/generics/6729401/T6729401.java b/langtools/test/tools/javac/generics/6729401/T6729401.java index dc7be410bfc..8597e93b57f 100644 --- a/langtools/test/tools/javac/generics/6729401/T6729401.java +++ b/langtools/test/tools/javac/generics/6729401/T6729401.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javac/generics/inference/6315770/T6315770.out b/langtools/test/tools/javac/generics/inference/6315770/T6315770.out index 8dc60f97d6d..dd1fdb9e3d3 100644 --- a/langtools/test/tools/javac/generics/inference/6315770/T6315770.out +++ b/langtools/test/tools/javac/generics/inference/6315770/T6315770.out @@ -1,3 +1,3 @@ -T6315770.java:39:42: compiler.err.undetermined.type.1: <T>T6315770<T>, (- compiler.misc.no.unique.maximal.instance.exists: T, java.lang.String,java.lang.Integer,java.lang.Runnable) -T6315770.java:40:40: compiler.err.prob.found.req: (- compiler.misc.incompatible.types.1: (- compiler.misc.no.conforming.instance.exists: T, T6315770<T>, T6315770<? super java.lang.String>)), <T>T6315770<T>, T6315770<? super java.lang.String> +T6315770.java:39:42: compiler.err.undetermined.type.1: <T>T6315770<T>, (compiler.misc.no.unique.maximal.instance.exists: T, java.lang.String,java.lang.Integer,java.lang.Runnable) +T6315770.java:40:40: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.no.conforming.instance.exists: T, T6315770<T>, T6315770<? super java.lang.String>)), <T>T6315770<T>, T6315770<? super java.lang.String> 2 errors diff --git a/langtools/test/tools/javac/generics/inference/6718364/T6718364.out b/langtools/test/tools/javac/generics/inference/6718364/T6718364.out index e049269d284..1b5ed9ad241 100644 --- a/langtools/test/tools/javac/generics/inference/6718364/T6718364.out +++ b/langtools/test/tools/javac/generics/inference/6718364/T6718364.out @@ -1,3 +1,3 @@ -T6718364.java:36:32: compiler.warn.prob.found.req: (- compiler.misc.unchecked.assign), T6718364.X, T6718364.X<java.lang.Integer> +T6718364.java:36:32: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6718364.X, T6718364.X<java.lang.Integer> T6718364.java:36:10: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, T6718364.X<T>,T, T6718364.X<T6718364.X<java.lang.Integer>>,T6718364.X, kindname.class, T6718364 2 warnings \ No newline at end of file diff --git a/langtools/test/tools/javac/generics/rare/6665356/T6665356.java b/langtools/test/tools/javac/generics/rare/6665356/T6665356.java index 8f0949fcba9..cf757c362df 100644 --- a/langtools/test/tools/javac/generics/rare/6665356/T6665356.java +++ b/langtools/test/tools/javac/generics/rare/6665356/T6665356.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javac/generics/typevars/6680106/T6680106.out b/langtools/test/tools/javac/generics/typevars/6680106/T6680106.out index 06f1eaf100f..f26d2a47c23 100644 --- a/langtools/test/tools/javac/generics/typevars/6680106/T6680106.out +++ b/langtools/test/tools/javac/generics/typevars/6680106/T6680106.out @@ -1,13 +1,13 @@ -T6680106.java:34:25: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:35:25: compiler.err.type.found.req: S[], (- compiler.misc.type.req.class) -T6680106.java:35:40: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:36:25: compiler.err.type.found.req: S[], (- compiler.misc.type.req.class) -T6680106.java:36:40: compiler.err.type.found.req: U[], (- compiler.misc.type.req.class) -T6680106.java:36:55: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:37:30: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:38:30: compiler.err.type.found.req: S[], (- compiler.misc.type.req.class) -T6680106.java:38:50: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:39:30: compiler.err.type.found.req: S[], (- compiler.misc.type.req.class) -T6680106.java:39:50: compiler.err.type.found.req: U[], (- compiler.misc.type.req.class) -T6680106.java:39:70: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) +T6680106.java:34:25: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:35:25: compiler.err.type.found.req: S[], (compiler.misc.type.req.class) +T6680106.java:35:40: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:36:25: compiler.err.type.found.req: S[], (compiler.misc.type.req.class) +T6680106.java:36:40: compiler.err.type.found.req: U[], (compiler.misc.type.req.class) +T6680106.java:36:55: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:37:30: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:38:30: compiler.err.type.found.req: S[], (compiler.misc.type.req.class) +T6680106.java:38:50: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:39:30: compiler.err.type.found.req: S[], (compiler.misc.type.req.class) +T6680106.java:39:50: compiler.err.type.found.req: U[], (compiler.misc.type.req.class) +T6680106.java:39:70: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) 12 errors \ No newline at end of file diff --git a/langtools/test/tools/javac/generics/typevars/6804733/T6804733.java b/langtools/test/tools/javac/generics/typevars/6804733/T6804733.java new file mode 100644 index 00000000000..1e78e5ee2d0 --- /dev/null +++ b/langtools/test/tools/javac/generics/typevars/6804733/T6804733.java @@ -0,0 +1,35 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6804733 + * @summary javac generates spourious diagnostics for ill-formed type-variable bounds + * @author mcimadamore + * @compile/fail/ref=T6804733.out -XDrawDiagnostics T6804733.java + */ + +import java.util.ArrayList; +class T6804733<S> extends ArrayList<S> { + <T extends S & S> void m() {} +} diff --git a/langtools/test/tools/javac/generics/typevars/6804733/T6804733.out b/langtools/test/tools/javac/generics/typevars/6804733/T6804733.out new file mode 100644 index 00000000000..c40724a71ea --- /dev/null +++ b/langtools/test/tools/javac/generics/typevars/6804733/T6804733.out @@ -0,0 +1,2 @@ +T6804733.java:34:20: compiler.err.type.var.may.not.be.followed.by.other.bounds +1 error diff --git a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test3.out b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test3.out index e850113bd97..070f1fabd02 100644 --- a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test3.out +++ b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test3.out @@ -1,3 +1,3 @@ -A.java:10:9: compiler.warn.has.been.deprecated: A1, unnamed package -A.java:10:21: compiler.warn.has.been.deprecated: A1, unnamed package +A.java:10:9: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package +A.java:10:21: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package 2 warnings diff --git a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test3b.out b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test3b.out index a3f8ec73164..4098fdaa654 100644 --- a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test3b.out +++ b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test3b.out @@ -1,3 +1,3 @@ -A.java:10:9: compiler.warn.has.been.deprecated: A1, unnamed package +A.java:10:9: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package - compiler.note.deprecated.filename.additional: A.java 1 warning diff --git a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4.out b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4.out index cbfe3808a6d..bdb88774241 100644 --- a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4.out +++ b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4.out @@ -1,7 +1,7 @@ -A.java:10:9: compiler.warn.has.been.deprecated: A1, unnamed package -A.java:10:21: compiler.warn.has.been.deprecated: A1, unnamed package -B.java:11:9: compiler.warn.has.been.deprecated: B1, unnamed package -B.java:11:21: compiler.warn.has.been.deprecated: B1, unnamed package -B.java:12:9: compiler.warn.has.been.deprecated: B1, unnamed package -B.java:12:22: compiler.warn.has.been.deprecated: B1, unnamed package +A.java:10:9: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package +A.java:10:21: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package +B.java:11:9: compiler.warn.has.been.deprecated: B1, compiler.misc.unnamed.package +B.java:11:21: compiler.warn.has.been.deprecated: B1, compiler.misc.unnamed.package +B.java:12:9: compiler.warn.has.been.deprecated: B1, compiler.misc.unnamed.package +B.java:12:22: compiler.warn.has.been.deprecated: B1, compiler.misc.unnamed.package 6 warnings diff --git a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4b.out b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4b.out index 4a382e0a30d..146a84bfb1a 100644 --- a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4b.out +++ b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4b.out @@ -1,3 +1,3 @@ -A.java:10:9: compiler.warn.has.been.deprecated: A1, unnamed package +A.java:10:9: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package - compiler.note.deprecated.plural.additional 1 warning diff --git a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4c.out b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4c.out index dcf68d576b9..fdb55573a13 100644 --- a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4c.out +++ b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4c.out @@ -1,4 +1,4 @@ -A.java:10:9: compiler.warn.has.been.deprecated: A1, unnamed package -A.java:10:21: compiler.warn.has.been.deprecated: A1, unnamed package +A.java:10:9: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package +A.java:10:21: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package - compiler.note.deprecated.filename: B.java 2 warnings diff --git a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4d.out b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4d.out index bd34b7fc7b6..41a71090a1a 100644 --- a/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4d.out +++ b/langtools/test/tools/javac/mandatoryWarnings/deprecated/Test4d.out @@ -1,5 +1,5 @@ -A.java:10:9: compiler.warn.has.been.deprecated: A1, unnamed package -A.java:10:21: compiler.warn.has.been.deprecated: A1, unnamed package -B.java:11:9: compiler.warn.has.been.deprecated: B1, unnamed package +A.java:10:9: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package +A.java:10:21: compiler.warn.has.been.deprecated: A1, compiler.misc.unnamed.package +B.java:11:9: compiler.warn.has.been.deprecated: B1, compiler.misc.unnamed.package - compiler.note.deprecated.filename.additional: B.java 3 warnings diff --git a/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.out b/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.out index 94a21c0ae5f..b049ccd5aab 100644 --- a/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.out +++ b/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.out @@ -1,5 +1,5 @@ MissingSuperRecovery.java:15: cannot access base -class file for base not found public class MissingSuperRecovery extends impl { ^ + class file for base not found 1 error diff --git a/langtools/test/tools/javac/policy/test3/A.java b/langtools/test/tools/javac/policy/test3/A.java new file mode 100644 index 00000000000..b21c7713860 --- /dev/null +++ b/langtools/test/tools/javac/policy/test3/A.java @@ -0,0 +1,10 @@ +class A { + void m1() { + System.err.println("hello"); + 0 // syntax error + System.err.println("world"); + } + + void m2() { + } +} diff --git a/langtools/test/tools/javac/policy/test3/Test.java b/langtools/test/tools/javac/policy/test3/Test.java new file mode 100644 index 00000000000..09e64449bf7 --- /dev/null +++ b/langtools/test/tools/javac/policy/test3/Test.java @@ -0,0 +1,169 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* @test + * @bug 6813059 + * @summary + */ + +import java.io.*; +import java.util.*; + +// Simple test of -XDshouldStopPolicy. +// For each of the permissable values, we compile a file with an error in it, +// then using -XDverboseCompilePolicy we check that the compilation gets as +// far as expected, but no further. + +public class Test { + enum ShouldStopPolicy { + BLANK(false, null, "attr"), + PROCESS(true, null, "attr"), + ATTR(true, "attr", "flow"), + FLOW(true, "flow", "desugar"), + TRANSTYPES(true, "desugar", "generate"), + LOWER(true, "desugar", "generate"), + GENERATE(true, "generate", null); + ShouldStopPolicy(boolean needOption, String expect, String dontExpect) { + this.needOption = needOption; + this.expect = expect; + this.dontExpect = dontExpect; + } + boolean needOption; + String expect; + String dontExpect; + } + + enum CompilePolicy { + BYFILE, + BYTODO + } + + public static void main(String... args) throws Exception { + new Test().run(); + } + + public void run() throws Exception { + for (CompilePolicy cp: CompilePolicy.values()) { + for (ShouldStopPolicy ssp: ShouldStopPolicy.values()) { + test(cp, ssp); + } + } + + if (errors > 0) + throw new Exception(errors + " errors occurred"); + } + + public void test(CompilePolicy cp, ShouldStopPolicy ssp) { + System.err.println(); + System.err.println("test " + cp + " " + ssp); + List<String> args = new ArrayList<String>(); + args.add("-XDverboseCompilePolicy"); + args.add("-XDcompilePolicy=" + cp.toString().toLowerCase()); + args.add("-d"); + args.add("."); + if (ssp.needOption) + args.add("-XDshouldStopPolicy=" + ssp); + args.add(new File(System.getProperty("test.src", "."), "A.java").getPath()); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + System.err.println("compile " + args); + int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw); + if (rc == 0) + throw new Error("compilation succeeded unexpectedly"); + //System.err.println(sw); + + // The following is a workaround for the current javac implementation, + // that in bytodo mode, it will still attribute files after syntax errors. + // Changing that behavior may surprise existing users, so for now, we + // work around it. + if (cp == CompilePolicy.BYTODO && ssp == ShouldStopPolicy.PROCESS) + ssp = ShouldStopPolicy.ATTR; + + boolean foundExpected = (ssp.expect == null); + String[] lines = sw.toString().split("\n"); + for (String line: lines) { + if (ssp.expect != null && line.startsWith("[" + ssp.expect)) + foundExpected = true; + if (ssp.dontExpect != null && line.startsWith("[" + ssp.dontExpect)) { + error("Unexpected output: " + ssp.dontExpect + "\n" + sw); + return; + } + } + + if (!foundExpected) + error("Expected output not found: " + ssp.expect + "\n" + sw); + } + + void error(String message) { + System.err.println(message); + errors++; + } + + int errors; +} + + + + + + + + + + + + +// These tests test the ability of the compiler to continue in the face of +// errors, accordining to the shouldStopPolicy + +/* @ test /nodynamiccopyright/ + * @bug 6813059 + * @summary + * @compile/fail/ref=flow.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=FLOW Test.java + + * @compile/fail/ref=default.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy Test.java + * @compile/fail/ref=enter.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=ENTER Test.java + * @compile/fail/ref=attr.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=ATTR Test.java + * @compile/fail/ref=transtypes.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=TRANSTYPES Test.java + * @compile/fail/ref=lower.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=LOWER Test.java + * @compile/fail/ref=generate.out -XDrawDiagnostics -XDcompilePolicy=byfile -XDverboseCompilePolicy -XDshouldStopPolicy=GENERATE Test.java + */ + +/* +class Test { + void m1() { + System.err.println("hello"); + 0 // syntax error + System.err.println("world"); + } + + void m2() { + } +} + +class Test2 { +} +*/ + diff --git a/langtools/test/tools/javac/positions/T6253161.out b/langtools/test/tools/javac/positions/T6253161.out index 0bf08100aa4..d5d2e5162e8 100644 --- a/langtools/test/tools/javac/positions/T6253161.out +++ b/langtools/test/tools/javac/positions/T6253161.out @@ -1,2 +1,2 @@ -T6253161.java:19:62: compiler.warn.missing.SVUID: <anonymous T6253161$1$1> +T6253161.java:19:62: compiler.warn.missing.SVUID: compiler.misc.anonymous.class: T6253161$1$1 1 warning diff --git a/langtools/test/tools/javac/positions/T6253161a.out b/langtools/test/tools/javac/positions/T6253161a.out index ac281acdab3..e5ba714cb51 100644 --- a/langtools/test/tools/javac/positions/T6253161a.out +++ b/langtools/test/tools/javac/positions/T6253161a.out @@ -1,2 +1,2 @@ -T6253161a.java:19:62: compiler.warn.missing.SVUID: <anonymous T6253161a$1$1> +T6253161a.java:19:62: compiler.warn.missing.SVUID: compiler.misc.anonymous.class: T6253161a$1$1 1 warning diff --git a/langtools/test/tools/javac/processing/environment/round/Foo.java b/langtools/test/tools/javac/processing/environment/round/Foo.java new file mode 100644 index 00000000000..58ada1d4f95 --- /dev/null +++ b/langtools/test/tools/javac/processing/environment/round/Foo.java @@ -0,0 +1,27 @@ +/* + * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +@AnnotatedElementInfo(annotationName="AnnotatedElementInfo", + expectedSize=1, + names="Foo") +public class Foo {} diff --git a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java index 2a948350bab..867c3c40b97 100644 --- a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java +++ b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6397298 6400986 6425592 6449798 6453386 6508401 + * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 * @summary Tests that getElementsAnnotatedWith works properly. * @author Joseph D. Darcy * @compile TestElementsAnnotatedWith.java @@ -31,16 +31,22 @@ * @compile -processor TestElementsAnnotatedWith -proc:only SurfaceAnnotations.java * @compile -processor TestElementsAnnotatedWith -proc:only BuriedAnnotations.java * @compile -processor TestElementsAnnotatedWith -proc:only Part1.java Part2.java - * @compile -processor TestElementsAnnotatedWith -proc:only TestElementsAnnotatedWith.java * @compile -processor TestElementsAnnotatedWith -proc:only C2.java + * @compile -processor TestElementsAnnotatedWith -proc:only Foo.java + * @compile -XD-d=. Foo.java + * @compile -processor TestElementsAnnotatedWith -proc:only TestElementsAnnotatedWith.java */ import java.lang.annotation.Annotation; +import java.io.*; import java.util.Collections; import java.util.Set; import java.util.HashSet; +import java.util.List; +import java.util.ArrayList; import java.util.Arrays; import javax.annotation.processing.*; +import javax.tools.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.*; import javax.lang.model.util.*; @@ -120,6 +126,9 @@ public class TestElementsAnnotatedWith extends AbstractProcessor { System.err.println("AnnotatedElementInfo: " + annotatedElementInfo); throw new RuntimeException(); } + + if("TestElementsAnnotatedWith".equals(firstType.getSimpleName().toString())) + writeClassFile(); // Start another round to test class file input } else { // If processing is over without an error, the specified // elements should be empty so an empty set should be returned. @@ -161,6 +170,37 @@ public class TestElementsAnnotatedWith extends AbstractProcessor { } catch(IllegalArgumentException iae) {} } + /* + * Hack alert! The class file read below is generated by the + * "@compile -XD-d=. Foo.java" directive above. This sneakily + * overrides the output location to the current directory where a + * subsequent @compile can read the file. This could be improved + * if either a new directive like @process accepted class file + * arguments (the javac command accepts such arguments but + * @compile does not) or the test.src and test.classes properties + * were set to be read with @compile jobs. + */ + private void writeClassFile() { + try { + Filer filer = processingEnv.getFiler(); + JavaFileObject jfo = filer.createClassFile("Foo"); + OutputStream os = jfo.openOutputStream(); + // Copy the bytes over + System.out.println((new File(".")).getAbsolutePath()); + InputStream io = new BufferedInputStream(new FileInputStream(new File(".", "Foo.class"))); + int datum = io.read(); + while(datum != -1) { + os.write(datum); + datum = io.read(); + } + os.close(); + } catch (IOException io) { + throw new RuntimeException(io); + } + + + } + @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latest(); diff --git a/langtools/test/tools/javac/processing/model/testgetallmembers/Main.java b/langtools/test/tools/javac/processing/model/testgetallmembers/Main.java index e783d29264f..6cb584a084b 100644 --- a/langtools/test/tools/javac/processing/model/testgetallmembers/Main.java +++ b/langtools/test/tools/javac/processing/model/testgetallmembers/Main.java @@ -1,5 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javac/unicode/UnicodeNewline.out b/langtools/test/tools/javac/unicode/UnicodeNewline.out index 366d8c6eb0a..5b71702fb4d 100644 --- a/langtools/test/tools/javac/unicode/UnicodeNewline.out +++ b/langtools/test/tools/javac/unicode/UnicodeNewline.out @@ -1,6 +1,6 @@ UnicodeNewline.java:11: cannot find symbol -symbol : class xyzzy -location: class UnicodeNewline xyzzy plugh; // error should be HERE ^ + symbol: class xyzzy + location: class UnicodeNewline 1 error diff --git a/langtools/test/tools/javac/warnings/Deprecation.lintAll.out b/langtools/test/tools/javac/warnings/Deprecation.lintAll.out index ea7148d1268..e778c0cba23 100644 --- a/langtools/test/tools/javac/warnings/Deprecation.lintAll.out +++ b/langtools/test/tools/javac/warnings/Deprecation.lintAll.out @@ -1,3 +1,3 @@ -Deprecation.java:18:24: compiler.warn.has.been.deprecated: Deprecation, unnamed package -Deprecation.java:55:24: compiler.warn.has.been.deprecated: Deprecation, unnamed package +Deprecation.java:18:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package +Deprecation.java:55:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package 2 warnings diff --git a/langtools/test/tools/javac/warnings/Deprecation.lintDeprecation.out b/langtools/test/tools/javac/warnings/Deprecation.lintDeprecation.out index ea7148d1268..e778c0cba23 100644 --- a/langtools/test/tools/javac/warnings/Deprecation.lintDeprecation.out +++ b/langtools/test/tools/javac/warnings/Deprecation.lintDeprecation.out @@ -1,3 +1,3 @@ -Deprecation.java:18:24: compiler.warn.has.been.deprecated: Deprecation, unnamed package -Deprecation.java:55:24: compiler.warn.has.been.deprecated: Deprecation, unnamed package +Deprecation.java:18:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package +Deprecation.java:55:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package 2 warnings diff --git a/langtools/test/tools/javadoc/6176978/T6176978.java b/langtools/test/tools/javadoc/6176978/T6176978.java index 892271a8e3c..9ab98981c82 100644 --- a/langtools/test/tools/javadoc/6176978/T6176978.java +++ b/langtools/test/tools/javadoc/6176978/T6176978.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javadoc/6176978/X.java b/langtools/test/tools/javadoc/6176978/X.java index 2eb5bf4335b..6f5cf090cc3 100644 --- a/langtools/test/tools/javadoc/6176978/X.java +++ b/langtools/test/tools/javadoc/6176978/X.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javap/T4884240.java b/langtools/test/tools/javap/T4884240.java index 93d4cc9361c..f2f36167760 100644 --- a/langtools/test/tools/javap/T4884240.java +++ b/langtools/test/tools/javap/T4884240.java @@ -16,7 +16,7 @@ * * 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-15301 USA. + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or diff --git a/make/Defs-internal.gmk b/make/Defs-internal.gmk index 05d8149c5d2..89be05b1efe 100644 --- a/make/Defs-internal.gmk +++ b/make/Defs-internal.gmk @@ -1,5 +1,5 @@ # -# Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/make/jdk-rules.gmk b/make/jdk-rules.gmk index 821f5d739c6..a84c776a823 100644 --- a/make/jdk-rules.gmk +++ b/make/jdk-rules.gmk @@ -1,5 +1,5 @@ # -# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -106,7 +106,7 @@ jdk-clobber:: $(MAKE) $(JDK_CLOBBER_TARGETS) $(JDK_BUILD_ARGUMENTS) ; ) jdk-sanity:: - @( $(CD) $(JDK_TOPDIR)/make && \ + ( $(CD) $(JDK_TOPDIR)/make && \ $(MAKE) sanity HOTSPOT_IMPORT_CHECK=false $(JDK_BUILD_ARGUMENTS) ; ) compare-images: compare-image diff --git a/make/jprt.config b/make/jprt.config index f3ff50615ef..aa165472358 100644 --- a/make/jprt.config +++ b/make/jprt.config @@ -1,7 +1,7 @@ #!echo "This is not a shell script" ############################################################################# # -# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -358,6 +358,13 @@ else ALT_SPONSOR2DIR=C:/sponsor_binaries export ALT_SPONSOR2DIR + # JPRT systems can never run msival2.exe, set this to avoid them + SKIP_MSIVAL2=true + export SKIP_MSIVAL2 + # Not easy to do + SKIP_COMPARE_IMAGES=true + export SKIP_COMPARE_IMAGES + fi # Export PATH setting diff --git a/make/jprt.gmk b/make/jprt.gmk index fcf67f80b36..078e188af73 100644 --- a/make/jprt.gmk +++ b/make/jprt.gmk @@ -1,5 +1,5 @@ # -# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ DEFAULT_BUILD_FLAVOR=product JPRT_ARCHIVE_BUNDLE=$(ABS_OUTPUTDIR)/$(DEFAULT_BUILD_FLAVOR)-bundle.zip JPRT_ARCHIVE_INSTALL_BUNDLE=$(ABS_OUTPUTDIR)/$(DEFAULT_BUILD_FLAVOR)-install-bundle.zip -jprt_build_product: all_product_build +jprt_build_product: sanity all_product_build ( $(CD) $(OUTPUTDIR)/j2sdk-image && \ $(ZIPEXE) -q -r $(JPRT_ARCHIVE_BUNDLE) . ) ifdef HAVE_JPRT_SAVE_BUNDLES